refclock_parse.c revision 280849
154359Sroberto/*
2280849Scy * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
354359Sroberto *
4280849Scy * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
554359Sroberto *
6182007Sroberto * generic reference clock driver for several DCF/GPS/MSF/... receivers
754359Sroberto *
8182007Sroberto * PPS notes:
9182007Sroberto *   On systems that support PPSAPI (RFC2783) PPSAPI is the
10182007Sroberto *   preferred interface.
1154359Sroberto *
12182007Sroberto *   Optionally make use of a STREAMS module for input processing where
13182007Sroberto *   available and configured. This STREAMS module reduces the time
14182007Sroberto *   stamp latency for serial and PPS events.
15182007Sroberto *   Currently the STREAMS module is only available for Suns running
16182007Sroberto *   SunOS 4.x and SunOS5.x.
1754359Sroberto *
18280849Scy * Copyright (c) 1995-2009 by Frank Kardel <kardel <AT> ntp.org>
19280849Scy * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
2054359Sroberto *
21182007Sroberto * Redistribution and use in source and binary forms, with or without
22182007Sroberto * modification, are permitted provided that the following conditions
23182007Sroberto * are met:
24182007Sroberto * 1. Redistributions of source code must retain the above copyright
25182007Sroberto *    notice, this list of conditions and the following disclaimer.
26182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright
27182007Sroberto *    notice, this list of conditions and the following disclaimer in the
28182007Sroberto *    documentation and/or other materials provided with the distribution.
29182007Sroberto * 3. Neither the name of the author nor the names of its contributors
30182007Sroberto *    may be used to endorse or promote products derived from this software
31182007Sroberto *    without specific prior written permission.
3254359Sroberto *
33182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34182007Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35182007Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36182007Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
37182007Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38182007Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39182007Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40182007Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41182007Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42182007Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43182007Sroberto * SUCH DAMAGE.
4454359Sroberto *
4554359Sroberto */
4654359Sroberto
4754359Sroberto#ifdef HAVE_CONFIG_H
48182007Sroberto# include "config.h"
4954359Sroberto#endif
5054359Sroberto
51280849Scy#include "ntp_types.h"
52280849Scy
5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE)
5454359Sroberto
5554359Sroberto/*
5654359Sroberto * This driver currently provides the support for
5754359Sroberto *   - Meinberg receiver DCF77 PZF 535 (TCXO version)       (DCF)
5854359Sroberto *   - Meinberg receiver DCF77 PZF 535 (OCXO version)       (DCF)
5954359Sroberto *   - Meinberg receiver DCF77 PZF 509                      (DCF)
6054359Sroberto *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
6154359Sroberto *   - IGEL CLOCK                                           (DCF)
6254359Sroberto *   - ELV DCF7000                                          (DCF)
6354359Sroberto *   - Schmid clock                                         (DCF)
6454359Sroberto *   - Conrad DCF77 receiver module                         (DCF)
6554359Sroberto *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
66182007Sroberto *   - WHARTON 400A Series clock			    (DCF)
6754359Sroberto *
6854359Sroberto *   - Meinberg GPS166/GPS167                               (GPS)
6954359Sroberto *   - Trimble (TSIP and TAIP protocol)                     (GPS)
7054359Sroberto *
7154359Sroberto *   - RCC8000 MSF Receiver                                 (MSF)
7254359Sroberto *   - VARITEXT clock					    (MSF)
7354359Sroberto */
7454359Sroberto
7554359Sroberto/*
7654359Sroberto * Meinberg receivers are usually connected via a
7754359Sroberto * 9600 baud serial line
7854359Sroberto *
7954359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp
8054359Sroberto * format. The firmware release is Uni-Erlangen.
8154359Sroberto *
8254359Sroberto * Meinberg generic receiver setup:
8354359Sroberto *	output time code every second
8454359Sroberto *	Baud rate 9600 7E2S
8554359Sroberto *
8654359Sroberto * Meinberg GPS16x setup:
8754359Sroberto *      output time code every second
8854359Sroberto *      Baudrate 19200 8N1
8954359Sroberto *
9054359Sroberto * This software supports the standard data formats used
9154359Sroberto * in Meinberg receivers.
9254359Sroberto *
9354359Sroberto * Special software versions are only sensible for the
9454359Sroberto * GPS 16x family of receivers.
9554359Sroberto *
9654359Sroberto * Meinberg can be reached via: http://www.meinberg.de/
9754359Sroberto */
9854359Sroberto
9954359Sroberto#include "ntpd.h"
10054359Sroberto#include "ntp_refclock.h"
101280849Scy#include "timevalops.h"		/* includes <sys/time.h> */
10254359Sroberto#include "ntp_control.h"
103182007Sroberto#include "ntp_string.h"
10454359Sroberto
10554359Sroberto#include <stdio.h>
10654359Sroberto#include <ctype.h>
10754359Sroberto#ifndef TM_IN_SYS_TIME
10854359Sroberto# include <time.h>
10954359Sroberto#endif
11054359Sroberto
111182007Sroberto#ifdef HAVE_UNISTD_H
112182007Sroberto# include <unistd.h>
113182007Sroberto#endif
114182007Sroberto
11554359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
11654359Sroberto# include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
11754359Sroberto#endif
11854359Sroberto
11954359Sroberto#ifdef STREAM
12054359Sroberto# include <sys/stream.h>
12154359Sroberto# include <sys/stropts.h>
12254359Sroberto#endif
12354359Sroberto
12454359Sroberto#ifdef HAVE_TERMIOS
125280849Scy# include <termios.h>
12654359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
12754359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
12854359Sroberto# undef HAVE_SYSV_TTYS
12954359Sroberto#endif
13054359Sroberto
13154359Sroberto#ifdef HAVE_SYSV_TTYS
13254359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
13354359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
13454359Sroberto#endif
13554359Sroberto
13654359Sroberto#ifdef HAVE_BSD_TTYS
13754359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */
13854359Sroberto# include "Bletch: BSD TTY not currently supported"
13954359Sroberto#endif
14054359Sroberto
14154359Sroberto#ifdef HAVE_SYS_IOCTL_H
14254359Sroberto# include <sys/ioctl.h>
14354359Sroberto#endif
14454359Sroberto
145182007Sroberto#ifdef HAVE_PPSAPI
146182007Sroberto# include "ppsapi_timepps.h"
147280849Scy# include "refclock_atom.h"
148182007Sroberto#endif
149182007Sroberto
15054359Sroberto#ifdef PPS
151182007Sroberto# ifdef HAVE_SYS_PPSCLOCK_H
152182007Sroberto#  include <sys/ppsclock.h>
153182007Sroberto# endif
154182007Sroberto# ifdef HAVE_TIO_SERIAL_STUFF
155182007Sroberto#  include <linux/serial.h>
156182007Sroberto# endif
15754359Sroberto#endif
158182007Sroberto
159182007Sroberto#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
160182007Sroberto#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
161182007Sroberto
162182007Sroberto/*
163182007Sroberto * document type of PPS interfacing - copy of ifdef mechanism in local_input()
164182007Sroberto */
165182007Sroberto#undef PPS_METHOD
166182007Sroberto
167182007Sroberto#ifdef HAVE_PPSAPI
168182007Sroberto#define PPS_METHOD "PPS API"
169182007Sroberto#else
170182007Sroberto#ifdef TIOCDCDTIMESTAMP
171182007Sroberto#define PPS_METHOD "TIOCDCDTIMESTAMP"
172182007Sroberto#else /* TIOCDCDTIMESTAMP */
173182007Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
174182007Sroberto#ifdef HAVE_CIOGETEV
175182007Sroberto#define PPS_METHOD "CIOGETEV"
17654359Sroberto#endif
177182007Sroberto#ifdef HAVE_TIOCGPPSEV
178182007Sroberto#define PPS_METHOD "TIOCGPPSEV"
17954359Sroberto#endif
180182007Sroberto#endif
181182007Sroberto#endif /* TIOCDCDTIMESTAMP */
182182007Sroberto#endif /* HAVE_PPSAPI */
18354359Sroberto
18454359Sroberto#include "ntp_io.h"
18554359Sroberto#include "ntp_stdlib.h"
18654359Sroberto
18754359Sroberto#include "parse.h"
18854359Sroberto#include "mbg_gps166.h"
18954359Sroberto#include "trimble.h"
19054359Sroberto#include "binio.h"
19154359Sroberto#include "ascii.h"
19254359Sroberto#include "ieee754io.h"
193182007Sroberto#include "recvbuff.h"
19454359Sroberto
195280849Scystatic char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST";
19654359Sroberto
19754359Sroberto/**===========================================================================
19854359Sroberto ** external interface to ntp mechanism
19954359Sroberto **/
20054359Sroberto
201280849Scystatic	int	parse_start	(int, struct peer *);
202280849Scystatic	void	parse_shutdown	(int, struct peer *);
203280849Scystatic	void	parse_poll	(int, struct peer *);
204280849Scystatic	void	parse_control	(int, const struct refclockstat *, struct refclockstat *, struct peer *);
20554359Sroberto
20654359Srobertostruct	refclock refclock_parse = {
20754359Sroberto	parse_start,
20854359Sroberto	parse_shutdown,
20954359Sroberto	parse_poll,
21054359Sroberto	parse_control,
211182007Sroberto	noentry,
212182007Sroberto	noentry,
21354359Sroberto	NOFLAGS
21454359Sroberto};
21554359Sroberto
21654359Sroberto/*
21754359Sroberto * Definitions
21854359Sroberto */
21954359Sroberto#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
22054359Sroberto#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
221182007Sroberto#define PARSEPPSDEVICE	"/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
22254359Sroberto
22354359Sroberto#undef ABS
22454359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
22554359Sroberto
226182007Sroberto#define PARSE_HARDPPS_DISABLE 0
227182007Sroberto#define PARSE_HARDPPS_ENABLE  1
228182007Sroberto
22954359Sroberto/**===========================================================================
23054359Sroberto ** function vector for dynamically binding io handling mechanism
23154359Sroberto **/
23254359Sroberto
23354359Srobertostruct parseunit;		/* to keep inquiring minds happy */
23454359Sroberto
23554359Srobertotypedef struct bind
23654359Sroberto{
23754359Sroberto  const char *bd_description;	                                /* name of type of binding */
238280849Scy  int	(*bd_init)     (struct parseunit *);			/* initialize */
239280849Scy  void	(*bd_end)      (struct parseunit *);			/* end */
240280849Scy  int   (*bd_setcs)    (struct parseunit *, parsectl_t *);	/* set character size */
241280849Scy  int	(*bd_disable)  (struct parseunit *);			/* disable */
242280849Scy  int	(*bd_enable)   (struct parseunit *);			/* enable */
243280849Scy  int	(*bd_getfmt)   (struct parseunit *, parsectl_t *);	/* get format */
244280849Scy  int	(*bd_setfmt)   (struct parseunit *, parsectl_t *);	/* setfmt */
245280849Scy  int	(*bd_timecode) (struct parseunit *, parsectl_t *);	/* get time code */
246280849Scy  void	(*bd_receive)  (struct recvbuf *);			/* receive operation */
247280849Scy  int	(*bd_io_input) (struct recvbuf *);			/* input operation */
24854359Sroberto} bind_t;
24954359Sroberto
25054359Sroberto#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
25154359Sroberto#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
25254359Sroberto#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
25354359Sroberto#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
25454359Sroberto#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
25554359Sroberto#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
25654359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
25754359Sroberto
25854359Sroberto/*
259280849Scy * special handling flags
26054359Sroberto */
261280849Scy#define PARSE_F_PPSONSECOND	0x00000001 /* PPS pulses are on second */
262280849Scy#define PARSE_F_POWERUPTRUST	0x00000100 /* POWERUP state ist trusted for */
263280849Scy                                           /* trusttime after SYNC was seen */
26454359Sroberto/**===========================================================================
26554359Sroberto ** error message regression handling
26654359Sroberto **
26754359Sroberto ** there are quite a few errors that can occur in rapid succession such as
26854359Sroberto ** noisy input data or no data at all. in order to reduce the amount of
26954359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit
27054359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a
27154359Sroberto ** configurable number of messages is displayed that way, we move on to the
27254359Sroberto ** next time unit / count for that class. a count of messages that have been
27354359Sroberto ** suppressed is held and displayed whenever a corresponding message is
27454359Sroberto ** displayed. the time units for a message class will also be displayed.
27554359Sroberto ** whenever an error condition clears we reset the error message state,
27654359Sroberto ** thus we would still generate much output on pathological conditions
27754359Sroberto ** where the system oscillates between OK and NOT OK states. coping
27854359Sroberto ** with that condition is currently considered too complicated.
27954359Sroberto **/
28054359Sroberto
28154359Sroberto#define ERR_ALL	        (unsigned)~0	/* "all" errors */
28254359Sroberto#define ERR_BADDATA	(unsigned)0	/* unusable input data/conversion errors */
28354359Sroberto#define ERR_NODATA	(unsigned)1	/* no input data */
28454359Sroberto#define ERR_BADIO	(unsigned)2	/* read/write/select errors */
28554359Sroberto#define ERR_BADSTATUS	(unsigned)3	/* unsync states */
28654359Sroberto#define ERR_BADEVENT	(unsigned)4	/* non nominal events */
28754359Sroberto#define ERR_INTERNAL	(unsigned)5	/* internal error */
28854359Sroberto#define ERR_CNT		(unsigned)(ERR_INTERNAL+1)
28954359Sroberto
29054359Sroberto#define ERR(_X_)	if (list_err(parse, (_X_)))
29154359Sroberto
29254359Srobertostruct errorregression
29354359Sroberto{
29454359Sroberto	u_long err_count;	/* number of repititions per class */
29554359Sroberto	u_long err_delay;	/* minimum delay between messages */
29654359Sroberto};
29754359Sroberto
29854359Srobertostatic struct errorregression
29954359Srobertoerr_baddata[] =			/* error messages for bad input data */
30054359Sroberto{
30154359Sroberto	{ 1,       0 },		/* output first message immediately */
30254359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
30354359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
30454359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
30554359Sroberto};
30654359Sroberto
30754359Srobertostatic struct errorregression
30854359Srobertoerr_nodata[] =			/* error messages for missing input data */
30954359Sroberto{
31054359Sroberto	{ 1,       0 },		/* output first message immediately */
31154359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
31254359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
31354359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
31454359Sroberto};
31554359Sroberto
31654359Srobertostatic struct errorregression
31754359Srobertoerr_badstatus[] =		/* unsynchronized state messages */
31854359Sroberto{
31954359Sroberto	{ 1,       0 },		/* output first message immediately */
32054359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
32154359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
32254359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
32354359Sroberto};
32454359Sroberto
32554359Srobertostatic struct errorregression
32654359Srobertoerr_badio[] =			/* io failures (bad reads, selects, ...) */
32754359Sroberto{
32854359Sroberto	{ 1,       0 },		/* output first message immediately */
32954359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
33054359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
33154359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
33254359Sroberto};
33354359Sroberto
33454359Srobertostatic struct errorregression
33554359Srobertoerr_badevent[] =		/* non nominal events */
33654359Sroberto{
33754359Sroberto	{ 20,      0 },		/* output first message immediately */
33854359Sroberto	{ 6,      60 },		/* output next five messages in 60 second intervals */
33954359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
34054359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
34154359Sroberto};
34254359Sroberto
34354359Srobertostatic struct errorregression
34454359Srobertoerr_internal[] =		/* really bad things - basically coding/OS errors */
34554359Sroberto{
34654359Sroberto	{ 0,       0 },		/* output all messages immediately */
34754359Sroberto};
34854359Sroberto
34954359Srobertostatic struct errorregression *
35054359Srobertoerr_tbl[] =
35154359Sroberto{
35254359Sroberto	err_baddata,
35354359Sroberto	err_nodata,
35454359Sroberto	err_badio,
35554359Sroberto	err_badstatus,
35654359Sroberto	err_badevent,
35754359Sroberto	err_internal
35854359Sroberto};
35954359Sroberto
36054359Srobertostruct errorinfo
36154359Sroberto{
36254359Sroberto	u_long err_started;	/* begin time (ntp) of error condition */
36354359Sroberto	u_long err_last;	/* last time (ntp) error occurred */
36454359Sroberto	u_long err_cnt;	/* number of error repititions */
36554359Sroberto	u_long err_suppressed;	/* number of suppressed messages */
36654359Sroberto	struct errorregression *err_stage; /* current error stage */
36754359Sroberto};
36854359Sroberto
36954359Sroberto/**===========================================================================
37054359Sroberto ** refclock instance data
37154359Sroberto **/
37254359Sroberto
37354359Srobertostruct parseunit
37454359Sroberto{
37554359Sroberto	/*
37654359Sroberto	 * NTP management
37754359Sroberto	 */
37854359Sroberto	struct peer         *peer;		/* backlink to peer structure - refclock inactive if 0  */
37954359Sroberto	struct refclockproc *generic;		/* backlink to refclockproc structure */
38054359Sroberto
38154359Sroberto	/*
38254359Sroberto	 * PARSE io
38354359Sroberto	 */
38454359Sroberto	bind_t	     *binding;	        /* io handling binding */
38554359Sroberto
38654359Sroberto	/*
38754359Sroberto	 * parse state
38854359Sroberto	 */
38954359Sroberto	parse_t	      parseio;	        /* io handling structure (user level parsing) */
39054359Sroberto
39154359Sroberto	/*
39254359Sroberto	 * type specific parameters
39354359Sroberto	 */
39454359Sroberto	struct parse_clockinfo   *parse_type;	        /* link to clock description */
39554359Sroberto
39654359Sroberto	/*
39754359Sroberto	 * clock state handling/reporting
39854359Sroberto	 */
39954359Sroberto	u_char	      flags;	        /* flags (leap_control) */
40054359Sroberto	u_long	      lastchange;       /* time (ntp) when last state change accured */
40154359Sroberto	u_long	      statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
40256746Sroberto	u_long        pollneeddata; 	/* current_time(!=0) for receive sample expected in PPS mode */
40354359Sroberto	u_short	      lastformat;       /* last format used */
40454359Sroberto	u_long        lastsync;		/* time (ntp) when clock was last seen fully synchronized */
405182007Sroberto        u_long        maxunsync;        /* max time in seconds a receiver is trusted after loosing synchronisation */
406182007Sroberto        double        ppsphaseadjust;   /* phase adjustment of PPS time stamp */
407182007Sroberto        u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
40854359Sroberto	u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
409182007Sroberto	int	      ppsfd;	        /* fd to ise for PPS io */
410182007Sroberto#ifdef HAVE_PPSAPI
411182007Sroberto        int           hardppsstate;     /* current hard pps state */
412280849Scy	struct refclock_atom atom;      /* PPSAPI structure */
413182007Sroberto#endif
414182007Sroberto	parsetime_t   timedata;		/* last (parse module) data */
41554359Sroberto	void         *localdata;        /* optional local, receiver-specific data */
41654359Sroberto        unsigned long localstate;       /* private local state */
41754359Sroberto	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
41854359Sroberto	struct ctl_var *kv;	        /* additional pseudo variables */
41954359Sroberto	u_long        laststatistic;    /* time when staticstics where output */
42054359Sroberto};
42154359Sroberto
42254359Sroberto
42354359Sroberto/**===========================================================================
42454359Sroberto ** Clockinfo section all parameter for specific clock types
42554359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters
42654359Sroberto **/
42754359Sroberto
428280849Scystatic	void	poll_dpoll	(struct parseunit *);
429280849Scystatic	void	poll_poll	(struct peer *);
430280849Scystatic	int	poll_init	(struct parseunit *);
43154359Sroberto
43254359Srobertotypedef struct poll_info
43354359Sroberto{
43454359Sroberto	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
43554359Sroberto	const char *string;		/* string to send for polling */
43654359Sroberto	u_long      count;		/* number of characters in string */
43754359Sroberto} poll_info_t;
43854359Sroberto
43954359Sroberto#define NO_CL_FLAGS	0
44054359Sroberto#define NO_POLL		0
44154359Sroberto#define NO_INIT		0
44254359Sroberto#define NO_END		0
44354359Sroberto#define NO_EVENT	0
444182007Sroberto#define NO_LCLDATA	0
44554359Sroberto#define NO_MESSAGE	0
44654359Sroberto#define NO_PPSDELAY     0
44754359Sroberto
44854359Sroberto#define DCF_ID		"DCF"	/* generic DCF */
44954359Sroberto#define DCF_A_ID	"DCFa"	/* AM demodulation */
45054359Sroberto#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
45154359Sroberto#define GPS_ID		"GPS"	/* GPS receiver */
45254359Sroberto
45354359Sroberto#define	NOCLOCK_ROOTDELAY	0.0
45454359Sroberto#define	NOCLOCK_BASEDELAY	0.0
45554359Sroberto#define	NOCLOCK_DESCRIPTION	0
45654359Sroberto#define NOCLOCK_MAXUNSYNC       0
45754359Sroberto#define NOCLOCK_CFLAG           0
45854359Sroberto#define NOCLOCK_IFLAG           0
45954359Sroberto#define NOCLOCK_OFLAG           0
46054359Sroberto#define NOCLOCK_LFLAG           0
46154359Sroberto#define NOCLOCK_ID		"TILT"
46254359Sroberto#define NOCLOCK_POLL		NO_POLL
46354359Sroberto#define NOCLOCK_INIT		NO_INIT
46454359Sroberto#define NOCLOCK_END		NO_END
465182007Sroberto#define NOCLOCK_DATA		NO_LCLDATA
46654359Sroberto#define NOCLOCK_FORMAT		""
46754359Sroberto#define NOCLOCK_TYPE		CTL_SST_TS_UNSPEC
46854359Sroberto#define NOCLOCK_SAMPLES		0
46954359Sroberto#define NOCLOCK_KEEP		0
47054359Sroberto
47154359Sroberto#define DCF_TYPE		CTL_SST_TS_LF
47254359Sroberto#define GPS_TYPE		CTL_SST_TS_UHF
47354359Sroberto
47454359Sroberto/*
47554359Sroberto * receiver specific constants
47654359Sroberto */
47754359Sroberto#define MBG_SPEED		(B9600)
478182007Sroberto#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
47954359Sroberto#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
48054359Sroberto#define MBG_OFLAG		0
48154359Sroberto#define MBG_LFLAG		0
48254359Sroberto#define MBG_FLAGS               PARSE_F_PPSONSECOND
48354359Sroberto
48454359Sroberto/*
48554359Sroberto * Meinberg DCF77 receivers
48654359Sroberto */
48754359Sroberto#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
48854359Sroberto#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
48954359Sroberto#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
49054359Sroberto#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
49154359Sroberto#define DCFUA31_SPEED		MBG_SPEED
49254359Sroberto#define DCFUA31_CFLAG           MBG_CFLAG
49354359Sroberto#define DCFUA31_IFLAG           MBG_IFLAG
49454359Sroberto#define DCFUA31_OFLAG           MBG_OFLAG
49554359Sroberto#define DCFUA31_LFLAG           MBG_LFLAG
49654359Sroberto#define DCFUA31_SAMPLES		5
49754359Sroberto#define DCFUA31_KEEP		3
49854359Sroberto#define DCFUA31_FORMAT		"Meinberg Standard"
49954359Sroberto
50054359Sroberto/*
50154359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
50254359Sroberto */
50354359Sroberto#define	DCFPZF535_ROOTDELAY	0.0
50454359Sroberto#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
50554359Sroberto#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
50654359Sroberto#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
50754359Sroberto						    * @ 5e-8df/f we have accumulated
50854359Sroberto						    * at most 2.16 ms (thus we move to
50954359Sroberto						    * NTP synchronisation */
51054359Sroberto#define DCFPZF535_SPEED		MBG_SPEED
51154359Sroberto#define DCFPZF535_CFLAG         MBG_CFLAG
51254359Sroberto#define DCFPZF535_IFLAG         MBG_IFLAG
51354359Sroberto#define DCFPZF535_OFLAG         MBG_OFLAG
51454359Sroberto#define DCFPZF535_LFLAG         MBG_LFLAG
51554359Sroberto#define DCFPZF535_SAMPLES	       5
51654359Sroberto#define DCFPZF535_KEEP		       3
51754359Sroberto#define DCFPZF535_FORMAT	"Meinberg Standard"
51854359Sroberto
51954359Sroberto/*
52054359Sroberto * Meinberg DCF PZF535/OCXO receiver
52154359Sroberto */
52254359Sroberto#define	DCFPZF535OCXO_ROOTDELAY	0.0
52354359Sroberto#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
52454359Sroberto#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
52554359Sroberto#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
52654359Sroberto						    * @ 5e-9df/f we have accumulated
52754359Sroberto						    * at most an error of 1.73 ms
52854359Sroberto						    * (thus we move to NTP synchronisation) */
52954359Sroberto#define DCFPZF535OCXO_SPEED	    MBG_SPEED
53054359Sroberto#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
53154359Sroberto#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
53254359Sroberto#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
53354359Sroberto#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
53454359Sroberto#define DCFPZF535OCXO_SAMPLES		   5
53554359Sroberto#define DCFPZF535OCXO_KEEP	           3
53654359Sroberto#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
53754359Sroberto
53854359Sroberto/*
53954359Sroberto * Meinberg GPS16X receiver
54054359Sroberto */
541280849Scystatic	void	gps16x_message	 (struct parseunit *, parsetime_t *);
542280849Scystatic  int     gps16x_poll_init (struct parseunit *);
54354359Sroberto
54454359Sroberto#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
54554359Sroberto#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
54654359Sroberto#define	GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
54754359Sroberto#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
54854359Sroberto						* @ 5e-9df/f we have accumulated
54954359Sroberto						* at most an error of 1.73 ms
55054359Sroberto						* (thus we move to NTP synchronisation) */
55154359Sroberto#define GPS16X_SPEED		B19200
55254359Sroberto#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
55354359Sroberto#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
55454359Sroberto#define GPS16X_OFLAG            MBG_OFLAG
55554359Sroberto#define GPS16X_LFLAG            MBG_LFLAG
55654359Sroberto#define GPS16X_POLLRATE	6
55754359Sroberto#define GPS16X_POLLCMD	""
55854359Sroberto#define GPS16X_CMDSIZE	0
55954359Sroberto
56054359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
56154359Sroberto
56254359Sroberto#define GPS16X_INIT		gps16x_poll_init
56354359Sroberto#define GPS16X_POLL	        0
56454359Sroberto#define GPS16X_END		0
56554359Sroberto#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
56654359Sroberto#define GPS16X_MESSAGE		gps16x_message
56754359Sroberto#define GPS16X_ID		GPS_ID
56854359Sroberto#define GPS16X_FORMAT		"Meinberg GPS Extended"
56954359Sroberto#define GPS16X_SAMPLES		5
57054359Sroberto#define GPS16X_KEEP		3
57154359Sroberto
57254359Sroberto/*
57354359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
57454359Sroberto *
57554359Sroberto * This is really not the hottest clock - but before you have nothing ...
57654359Sroberto */
57754359Sroberto#define DCF7000_ROOTDELAY	0.0 /* 0 */
57854359Sroberto#define DCF7000_BASEDELAY	0.405 /* slow blow */
57954359Sroberto#define DCF7000_DESCRIPTION	"ELV DCF7000"
58054359Sroberto#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
58154359Sroberto#define DCF7000_SPEED		(B9600)
58254359Sroberto#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
58354359Sroberto#define DCF7000_IFLAG		(IGNBRK)
58454359Sroberto#define DCF7000_OFLAG		0
58554359Sroberto#define DCF7000_LFLAG		0
58654359Sroberto#define DCF7000_SAMPLES		5
58754359Sroberto#define DCF7000_KEEP		3
58854359Sroberto#define DCF7000_FORMAT		"ELV DCF7000"
58954359Sroberto
59054359Sroberto/*
59154359Sroberto * Schmid DCF Receiver Kit
59254359Sroberto *
59354359Sroberto * When the WSDCF clock is operating optimally we want the primary clock
59454359Sroberto * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
59554359Sroberto * structure is set to 290 ms and we compute delays which are at least
59654359Sroberto * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
59754359Sroberto */
59854359Sroberto#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
59954359Sroberto#define WS_POLLCMD	"\163"
60054359Sroberto#define WS_CMDSIZE	1
60154359Sroberto
60254359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
60354359Sroberto
60454359Sroberto#define WSDCF_INIT		poll_init
60554359Sroberto#define WSDCF_POLL		poll_dpoll
60654359Sroberto#define WSDCF_END		0
60754359Sroberto#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
60854359Sroberto#define	WSDCF_ROOTDELAY		0.0	/* 0 */
60954359Sroberto#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
61054359Sroberto#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
61154359Sroberto#define WSDCF_FORMAT		"Schmid"
61254359Sroberto#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
61354359Sroberto#define WSDCF_SPEED		(B1200)
61454359Sroberto#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
61554359Sroberto#define WSDCF_IFLAG		0
61654359Sroberto#define WSDCF_OFLAG		0
61754359Sroberto#define WSDCF_LFLAG		0
61854359Sroberto#define WSDCF_SAMPLES		5
61954359Sroberto#define WSDCF_KEEP		3
62054359Sroberto
62154359Sroberto/*
62254359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants
62354359Sroberto */
62454359Sroberto#define RAWDCF_FLAGS		0
62554359Sroberto#define RAWDCF_ROOTDELAY	0.0 /* 0 */
62654359Sroberto#define RAWDCF_BASEDELAY	0.258
62754359Sroberto#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
62854359Sroberto#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
62954359Sroberto#define RAWDCF_SPEED		(B50)
63054359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
63154359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */
63254359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
63354359Sroberto#else
63454359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
63554359Sroberto#endif
63654359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
63754359Sroberto# define RAWDCF_IFLAG		0
63854359Sroberto#else
63954359Sroberto# define RAWDCF_IFLAG		(IGNPAR)
64054359Sroberto#endif
64154359Sroberto#define RAWDCF_OFLAG		0
64254359Sroberto#define RAWDCF_LFLAG		0
64354359Sroberto#define RAWDCF_SAMPLES		20
64454359Sroberto#define RAWDCF_KEEP		12
64554359Sroberto#define RAWDCF_INIT		0
64654359Sroberto
64754359Sroberto/*
64854359Sroberto * RAW DCF variants
64954359Sroberto */
65054359Sroberto/*
65154359Sroberto * Conrad receiver
65254359Sroberto *
65354359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
65454359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232
65554359Sroberto */
65654359Sroberto#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
65754359Sroberto#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
65854359Sroberto
659182007Sroberto/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
660182007Sroberto#define GUDE_EMC_USB_V20_SPEED            (B4800)
661182007Sroberto#define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
662182007Sroberto#define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
663182007Sroberto
66454359Sroberto/*
66554359Sroberto * TimeBrick receiver
66654359Sroberto */
66754359Sroberto#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
66854359Sroberto#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
66954359Sroberto
67054359Sroberto/*
67154359Sroberto * IGEL:clock receiver
67254359Sroberto */
67354359Sroberto#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
67454359Sroberto#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
67554359Sroberto#define IGELCLOCK_SPEED		(B1200)
67654359Sroberto#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
67754359Sroberto
67854359Sroberto/*
67954359Sroberto * RAWDCF receivers that need to be powered from DTR
68054359Sroberto * (like Expert mouse clock)
68154359Sroberto */
682280849Scystatic	int	rawdcf_init_1	(struct parseunit *);
68356746Sroberto#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
684280849Scy#define RAWDCFDTRSET75_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)"
68556746Sroberto#define RAWDCFDTRSET_INIT 		rawdcf_init_1
68654359Sroberto
68754359Sroberto/*
68856746Sroberto * RAWDCF receivers that need to be powered from
68956746Sroberto * DTR CLR and RTS SET
69054359Sroberto */
691280849Scystatic	int	rawdcf_init_2	(struct parseunit *);
69256746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
693280849Scy#define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)"
69456746Sroberto#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
69554359Sroberto
69654359Sroberto/*
69754359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols)
69854359Sroberto */
69954359Sroberto#ifndef TRIM_POLLRATE
70054359Sroberto#define TRIM_POLLRATE	0	/* only true direct polling */
70154359Sroberto#endif
70254359Sroberto
70354359Sroberto#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
70454359Sroberto#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
70554359Sroberto
70654359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
707280849Scystatic	int	trimbletaip_init	(struct parseunit *);
708280849Scystatic	void	trimbletaip_event	(struct parseunit *, int);
70954359Sroberto
71054359Sroberto/* query time & UTC correction data */
71154359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
71254359Sroberto
71354359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
714280849Scystatic	int	trimbletsip_init	(struct parseunit *);
715280849Scystatic	void	trimbletsip_end   	(struct parseunit *);
716280849Scystatic	void	trimbletsip_message	(struct parseunit *, parsetime_t *);
717280849Scystatic	void	trimbletsip_event	(struct parseunit *, int);
71854359Sroberto
71954359Sroberto#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
720182007Sroberto#define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
72154359Sroberto
72254359Sroberto#define TRIMBLETAIP_SPEED	    (B4800)
72354359Sroberto#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
72454359Sroberto#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
72554359Sroberto#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
72654359Sroberto#define TRIMBLETAIP_LFLAG           (0)
72754359Sroberto
72854359Sroberto#define TRIMBLETSIP_SPEED	    (B9600)
72954359Sroberto#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
73054359Sroberto#define TRIMBLETSIP_IFLAG           (IGNBRK)
73154359Sroberto#define TRIMBLETSIP_OFLAG           (0)
73254359Sroberto#define TRIMBLETSIP_LFLAG           (ICANON)
73354359Sroberto
73454359Sroberto#define TRIMBLETSIP_SAMPLES	    5
73554359Sroberto#define TRIMBLETSIP_KEEP	    3
73654359Sroberto#define TRIMBLETAIP_SAMPLES	    5
73754359Sroberto#define TRIMBLETAIP_KEEP	    3
73854359Sroberto
73954359Sroberto#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
74054359Sroberto#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
74154359Sroberto
74254359Sroberto#define TRIMBLETAIP_POLL	    poll_dpoll
74354359Sroberto#define TRIMBLETSIP_POLL	    poll_dpoll
74454359Sroberto
74554359Sroberto#define TRIMBLETAIP_INIT	    trimbletaip_init
74654359Sroberto#define TRIMBLETSIP_INIT	    trimbletsip_init
74754359Sroberto
74854359Sroberto#define TRIMBLETAIP_EVENT	    trimbletaip_event
74954359Sroberto
75054359Sroberto#define TRIMBLETSIP_EVENT	    trimbletsip_event
75154359Sroberto#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
75254359Sroberto
75354359Sroberto#define TRIMBLETAIP_END		    0
75454359Sroberto#define TRIMBLETSIP_END		    trimbletsip_end
75554359Sroberto
75654359Sroberto#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
75754359Sroberto#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
75854359Sroberto
75954359Sroberto#define TRIMBLETAIP_ID		    GPS_ID
76054359Sroberto#define TRIMBLETSIP_ID		    GPS_ID
76154359Sroberto
76254359Sroberto#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
76354359Sroberto#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
76454359Sroberto
76554359Sroberto#define TRIMBLETAIP_ROOTDELAY        0x0
76654359Sroberto#define TRIMBLETSIP_ROOTDELAY        0x0
76754359Sroberto
76854359Sroberto#define TRIMBLETAIP_BASEDELAY        0.0
76954359Sroberto#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
77054359Sroberto
77154359Sroberto#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
77254359Sroberto#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
77354359Sroberto
77454359Sroberto#define TRIMBLETAIP_MAXUNSYNC        0
77554359Sroberto#define TRIMBLETSIP_MAXUNSYNC        0
77654359Sroberto
77754359Sroberto#define TRIMBLETAIP_EOL		    '<'
77854359Sroberto
77954359Sroberto/*
78054359Sroberto * RadioCode Clocks RCC 800 receiver
78154359Sroberto */
78254359Sroberto#define RCC_POLLRATE   0       /* only true direct polling */
78354359Sroberto#define RCC_POLLCMD    "\r"
78454359Sroberto#define RCC_CMDSIZE    1
78554359Sroberto
78654359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
78754359Sroberto#define RCC8000_FLAGS		0
78854359Sroberto#define RCC8000_POLL            poll_dpoll
78954359Sroberto#define RCC8000_INIT            poll_init
79054359Sroberto#define RCC8000_END             0
79154359Sroberto#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
79254359Sroberto#define RCC8000_ROOTDELAY       0.0
79354359Sroberto#define RCC8000_BASEDELAY       0.0
79454359Sroberto#define RCC8000_ID              "MSF"
79554359Sroberto#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
79654359Sroberto#define RCC8000_FORMAT          "Radiocode RCC8000"
79754359Sroberto#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
79854359Sroberto#define RCC8000_SPEED		(B2400)
79954359Sroberto#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
80054359Sroberto#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
80154359Sroberto#define RCC8000_OFLAG           0
80254359Sroberto#define RCC8000_LFLAG           0
80354359Sroberto#define RCC8000_SAMPLES         5
80454359Sroberto#define RCC8000_KEEP	        3
80554359Sroberto
80654359Sroberto/*
80754359Sroberto * Hopf Radio clock 6021 Format
80854359Sroberto *
80954359Sroberto */
81054359Sroberto#define HOPF6021_ROOTDELAY	0.0
81154359Sroberto#define HOPF6021_BASEDELAY	0.0
81254359Sroberto#define HOPF6021_DESCRIPTION	"HOPF 6021"
81354359Sroberto#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
81454359Sroberto#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
81554359Sroberto#define HOPF6021_SPEED         (B9600)
81654359Sroberto#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
81754359Sroberto#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
81854359Sroberto#define HOPF6021_OFLAG		0
81954359Sroberto#define HOPF6021_LFLAG		0
82054359Sroberto#define HOPF6021_FLAGS          0
82154359Sroberto#define HOPF6021_SAMPLES        5
82254359Sroberto#define HOPF6021_KEEP	        3
82354359Sroberto
82454359Sroberto/*
82554359Sroberto * Diem's Computime Radio Clock Receiver
82654359Sroberto */
82754359Sroberto#define COMPUTIME_FLAGS       0
82854359Sroberto#define COMPUTIME_ROOTDELAY   0.0
82954359Sroberto#define COMPUTIME_BASEDELAY   0.0
83054359Sroberto#define COMPUTIME_ID          DCF_ID
83154359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
83254359Sroberto#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
83354359Sroberto#define COMPUTIME_TYPE        DCF_TYPE
83454359Sroberto#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
83554359Sroberto#define COMPUTIME_SPEED       (B9600)
83654359Sroberto#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
83754359Sroberto#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
83854359Sroberto#define COMPUTIME_OFLAG       0
83954359Sroberto#define COMPUTIME_LFLAG       0
84054359Sroberto#define COMPUTIME_SAMPLES     5
84154359Sroberto#define COMPUTIME_KEEP        3
84254359Sroberto
84354359Sroberto/*
84454359Sroberto * Varitext Radio Clock Receiver
84554359Sroberto */
84654359Sroberto#define VARITEXT_FLAGS       0
84754359Sroberto#define VARITEXT_ROOTDELAY   0.0
84854359Sroberto#define VARITEXT_BASEDELAY   0.0
84954359Sroberto#define VARITEXT_ID          "MSF"
85054359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver"
85154359Sroberto#define VARITEXT_FORMAT      "Varitext Radio Clock"
85254359Sroberto#define VARITEXT_TYPE        DCF_TYPE
85354359Sroberto#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
85454359Sroberto#define VARITEXT_SPEED       (B9600)
85554359Sroberto#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
85654359Sroberto#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
85754359Sroberto#define VARITEXT_OFLAG       0
85854359Sroberto#define VARITEXT_LFLAG       0
85954359Sroberto#define VARITEXT_SAMPLES     32
86054359Sroberto#define VARITEXT_KEEP        20
86154359Sroberto
862280849Scy/*
863280849Scy * SEL240x Satellite Sychronized Clock
864280849Scy */
865280849Scy#define SEL240X_POLLRATE	0 /* only true direct polling */
866280849Scy#define SEL240X_POLLCMD		"BUB8"
867280849Scy#define SEL240X_CMDSIZE		4
868280849Scy
869280849Scystatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE,
870280849Scy	                                SEL240X_POLLCMD,
871280849Scy					SEL240X_CMDSIZE };
872280849Scy#define SEL240X_FLAGS		(PARSE_F_PPSONSECOND)
873280849Scy#define SEL240X_POLL		poll_dpoll
874280849Scy#define SEL240X_INIT		poll_init
875280849Scy#define SEL240X_END		0
876280849Scy#define SEL240X_DATA            ((void *)(&sel240x_pollinfo))
877280849Scy#define SEL240X_ROOTDELAY	0.0
878280849Scy#define SEL240X_BASEDELAY	0.0
879280849Scy#define SEL240X_ID		GPS_ID
880280849Scy#define SEL240X_DESCRIPTION	"SEL240x Satellite Synchronized Clock"
881280849Scy#define SEL240X_FORMAT		"SEL B8"
882280849Scy#define SEL240X_MAXUNSYNC	60*60*12 /* only trust clock for 12 hours */
883280849Scy#define SEL240X_SPEED		(B9600)
884280849Scy#define SEL240X_CFLAG		(CS8|CREAD|CLOCAL)
885280849Scy#define SEL240X_IFLAG		(IGNBRK|IGNPAR)
886280849Scy#define SEL240X_OFLAG		(0)
887280849Scy#define SEL240X_LFLAG		(0)
888280849Scy#define SEL240X_SAMPLES		5
889280849Scy#define SEL240X_KEEP		3
890280849Scy
89154359Srobertostatic struct parse_clockinfo
89254359Sroberto{
893280849Scy	u_long  cl_flags;		/* operation flags (PPS interpretation, trust handling) */
894280849Scy  void  (*cl_poll)    (struct parseunit *);			/* active poll routine */
895280849Scy  int   (*cl_init)    (struct parseunit *);			/* active poll init routine */
896280849Scy  void  (*cl_event)   (struct parseunit *, int);		/* special event handling (e.g. reset clock) */
897280849Scy  void  (*cl_end)     (struct parseunit *);			/* active poll end routine */
898280849Scy  void  (*cl_message) (struct parseunit *, parsetime_t *);	/* process a lower layer message */
89954359Sroberto	void   *cl_data;		/* local data area for "poll" mechanism */
90054359Sroberto	double    cl_rootdelay;		/* rootdelay */
90154359Sroberto	double    cl_basedelay;		/* current offset by which the RS232
90254359Sroberto				time code is delayed from the actual time */
90354359Sroberto	const char *cl_id;		/* ID code */
90454359Sroberto	const char *cl_description;		/* device name */
90554359Sroberto	const char *cl_format;		/* fixed format */
90654359Sroberto	u_char  cl_type;		/* clock type (ntp control) */
907132451Sroberto	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
90854359Sroberto	u_long  cl_speed;		/* terminal input & output baudrate */
90954359Sroberto	u_long  cl_cflag;             /* terminal control flags */
91054359Sroberto	u_long  cl_iflag;             /* terminal input flags */
91154359Sroberto	u_long  cl_oflag;             /* terminal output flags */
91254359Sroberto	u_long  cl_lflag;             /* terminal local flags */
91354359Sroberto	u_long  cl_samples;	      /* samples for median filter */
91454359Sroberto	u_long  cl_keep;              /* samples for median filter to keep */
91554359Sroberto} parse_clockinfo[] =
91654359Sroberto{
91754359Sroberto	{				/* mode 0 */
91854359Sroberto		MBG_FLAGS,
91954359Sroberto		NO_POLL,
92054359Sroberto		NO_INIT,
92154359Sroberto		NO_EVENT,
92254359Sroberto		NO_END,
92354359Sroberto		NO_MESSAGE,
924182007Sroberto		NO_LCLDATA,
92554359Sroberto		DCFPZF535_ROOTDELAY,
92654359Sroberto		DCFPZF535_BASEDELAY,
92754359Sroberto		DCF_P_ID,
92854359Sroberto		DCFPZF535_DESCRIPTION,
92954359Sroberto		DCFPZF535_FORMAT,
93054359Sroberto		DCF_TYPE,
93154359Sroberto		DCFPZF535_MAXUNSYNC,
93254359Sroberto		DCFPZF535_SPEED,
93354359Sroberto		DCFPZF535_CFLAG,
93454359Sroberto		DCFPZF535_IFLAG,
93554359Sroberto		DCFPZF535_OFLAG,
93654359Sroberto		DCFPZF535_LFLAG,
93754359Sroberto		DCFPZF535_SAMPLES,
93854359Sroberto		DCFPZF535_KEEP
93954359Sroberto	},
94054359Sroberto	{				/* mode 1 */
94154359Sroberto		MBG_FLAGS,
94254359Sroberto		NO_POLL,
94354359Sroberto		NO_INIT,
94454359Sroberto		NO_EVENT,
94554359Sroberto		NO_END,
94654359Sroberto		NO_MESSAGE,
947182007Sroberto		NO_LCLDATA,
94854359Sroberto		DCFPZF535OCXO_ROOTDELAY,
94954359Sroberto		DCFPZF535OCXO_BASEDELAY,
95054359Sroberto		DCF_P_ID,
95154359Sroberto		DCFPZF535OCXO_DESCRIPTION,
95254359Sroberto		DCFPZF535OCXO_FORMAT,
95354359Sroberto		DCF_TYPE,
95454359Sroberto		DCFPZF535OCXO_MAXUNSYNC,
95554359Sroberto		DCFPZF535OCXO_SPEED,
95654359Sroberto		DCFPZF535OCXO_CFLAG,
95754359Sroberto		DCFPZF535OCXO_IFLAG,
95854359Sroberto		DCFPZF535OCXO_OFLAG,
95954359Sroberto		DCFPZF535OCXO_LFLAG,
96054359Sroberto		DCFPZF535OCXO_SAMPLES,
96154359Sroberto		DCFPZF535OCXO_KEEP
96254359Sroberto	},
96354359Sroberto	{				/* mode 2 */
96454359Sroberto		MBG_FLAGS,
96554359Sroberto		NO_POLL,
96654359Sroberto		NO_INIT,
96754359Sroberto		NO_EVENT,
96854359Sroberto		NO_END,
96954359Sroberto		NO_MESSAGE,
970182007Sroberto		NO_LCLDATA,
97154359Sroberto		DCFUA31_ROOTDELAY,
97254359Sroberto		DCFUA31_BASEDELAY,
97354359Sroberto		DCF_A_ID,
97454359Sroberto		DCFUA31_DESCRIPTION,
97554359Sroberto		DCFUA31_FORMAT,
97654359Sroberto		DCF_TYPE,
97754359Sroberto		DCFUA31_MAXUNSYNC,
97854359Sroberto		DCFUA31_SPEED,
97954359Sroberto		DCFUA31_CFLAG,
98054359Sroberto		DCFUA31_IFLAG,
98154359Sroberto		DCFUA31_OFLAG,
98254359Sroberto		DCFUA31_LFLAG,
98354359Sroberto		DCFUA31_SAMPLES,
98454359Sroberto		DCFUA31_KEEP
98554359Sroberto	},
98654359Sroberto	{				/* mode 3 */
98754359Sroberto		MBG_FLAGS,
98854359Sroberto		NO_POLL,
98954359Sroberto		NO_INIT,
99054359Sroberto		NO_EVENT,
99154359Sroberto		NO_END,
99254359Sroberto		NO_MESSAGE,
993182007Sroberto		NO_LCLDATA,
99454359Sroberto		DCF7000_ROOTDELAY,
99554359Sroberto		DCF7000_BASEDELAY,
99654359Sroberto		DCF_A_ID,
99754359Sroberto		DCF7000_DESCRIPTION,
99854359Sroberto		DCF7000_FORMAT,
99954359Sroberto		DCF_TYPE,
100054359Sroberto		DCF7000_MAXUNSYNC,
100154359Sroberto		DCF7000_SPEED,
100254359Sroberto		DCF7000_CFLAG,
100354359Sroberto		DCF7000_IFLAG,
100454359Sroberto		DCF7000_OFLAG,
100554359Sroberto		DCF7000_LFLAG,
100654359Sroberto		DCF7000_SAMPLES,
100754359Sroberto		DCF7000_KEEP
100854359Sroberto	},
100954359Sroberto	{				/* mode 4 */
101054359Sroberto		NO_CL_FLAGS,
101154359Sroberto		WSDCF_POLL,
101254359Sroberto		WSDCF_INIT,
101354359Sroberto		NO_EVENT,
101454359Sroberto		WSDCF_END,
101554359Sroberto		NO_MESSAGE,
101654359Sroberto		WSDCF_DATA,
101754359Sroberto		WSDCF_ROOTDELAY,
101854359Sroberto		WSDCF_BASEDELAY,
101954359Sroberto		DCF_A_ID,
102054359Sroberto		WSDCF_DESCRIPTION,
102154359Sroberto		WSDCF_FORMAT,
102254359Sroberto		DCF_TYPE,
102354359Sroberto		WSDCF_MAXUNSYNC,
102454359Sroberto		WSDCF_SPEED,
102554359Sroberto		WSDCF_CFLAG,
102654359Sroberto		WSDCF_IFLAG,
102754359Sroberto		WSDCF_OFLAG,
102854359Sroberto		WSDCF_LFLAG,
102954359Sroberto		WSDCF_SAMPLES,
103054359Sroberto		WSDCF_KEEP
103154359Sroberto	},
103254359Sroberto	{				/* mode 5 */
103354359Sroberto		RAWDCF_FLAGS,
103454359Sroberto		NO_POLL,
103554359Sroberto		RAWDCF_INIT,
103654359Sroberto		NO_EVENT,
103754359Sroberto		NO_END,
103854359Sroberto		NO_MESSAGE,
1039182007Sroberto		NO_LCLDATA,
104054359Sroberto		RAWDCF_ROOTDELAY,
104154359Sroberto		CONRAD_BASEDELAY,
104254359Sroberto		DCF_A_ID,
104354359Sroberto		CONRAD_DESCRIPTION,
104454359Sroberto		RAWDCF_FORMAT,
104554359Sroberto		DCF_TYPE,
104654359Sroberto		RAWDCF_MAXUNSYNC,
104754359Sroberto		RAWDCF_SPEED,
104854359Sroberto		RAWDCF_CFLAG,
104954359Sroberto		RAWDCF_IFLAG,
105054359Sroberto		RAWDCF_OFLAG,
105154359Sroberto		RAWDCF_LFLAG,
105254359Sroberto		RAWDCF_SAMPLES,
105354359Sroberto		RAWDCF_KEEP
105454359Sroberto	},
105554359Sroberto	{				/* mode 6 */
105654359Sroberto		RAWDCF_FLAGS,
105754359Sroberto		NO_POLL,
105854359Sroberto		RAWDCF_INIT,
105954359Sroberto		NO_EVENT,
106054359Sroberto		NO_END,
106154359Sroberto		NO_MESSAGE,
1062182007Sroberto		NO_LCLDATA,
106354359Sroberto		RAWDCF_ROOTDELAY,
106454359Sroberto		TIMEBRICK_BASEDELAY,
106554359Sroberto		DCF_A_ID,
106654359Sroberto		TIMEBRICK_DESCRIPTION,
106754359Sroberto		RAWDCF_FORMAT,
106854359Sroberto		DCF_TYPE,
106954359Sroberto		RAWDCF_MAXUNSYNC,
107054359Sroberto		RAWDCF_SPEED,
107154359Sroberto		RAWDCF_CFLAG,
107254359Sroberto		RAWDCF_IFLAG,
107354359Sroberto		RAWDCF_OFLAG,
107454359Sroberto		RAWDCF_LFLAG,
107554359Sroberto		RAWDCF_SAMPLES,
107654359Sroberto		RAWDCF_KEEP
107754359Sroberto	},
107854359Sroberto	{				/* mode 7 */
107954359Sroberto		MBG_FLAGS,
108054359Sroberto		GPS16X_POLL,
108154359Sroberto		GPS16X_INIT,
108254359Sroberto		NO_EVENT,
108354359Sroberto		GPS16X_END,
108454359Sroberto		GPS16X_MESSAGE,
108554359Sroberto		GPS16X_DATA,
108654359Sroberto		GPS16X_ROOTDELAY,
108754359Sroberto		GPS16X_BASEDELAY,
108854359Sroberto		GPS16X_ID,
108954359Sroberto		GPS16X_DESCRIPTION,
109054359Sroberto		GPS16X_FORMAT,
109154359Sroberto		GPS_TYPE,
109254359Sroberto		GPS16X_MAXUNSYNC,
109354359Sroberto		GPS16X_SPEED,
109454359Sroberto		GPS16X_CFLAG,
109554359Sroberto		GPS16X_IFLAG,
109654359Sroberto		GPS16X_OFLAG,
109754359Sroberto		GPS16X_LFLAG,
109854359Sroberto		GPS16X_SAMPLES,
109954359Sroberto		GPS16X_KEEP
110054359Sroberto	},
110154359Sroberto	{				/* mode 8 */
110254359Sroberto		RAWDCF_FLAGS,
110354359Sroberto		NO_POLL,
110454359Sroberto		NO_INIT,
110554359Sroberto		NO_EVENT,
110654359Sroberto		NO_END,
110754359Sroberto		NO_MESSAGE,
1108182007Sroberto		NO_LCLDATA,
110954359Sroberto		RAWDCF_ROOTDELAY,
111054359Sroberto		IGELCLOCK_BASEDELAY,
111154359Sroberto		DCF_A_ID,
111254359Sroberto		IGELCLOCK_DESCRIPTION,
111354359Sroberto		RAWDCF_FORMAT,
111454359Sroberto		DCF_TYPE,
111554359Sroberto		RAWDCF_MAXUNSYNC,
111654359Sroberto		IGELCLOCK_SPEED,
111754359Sroberto		IGELCLOCK_CFLAG,
111854359Sroberto		RAWDCF_IFLAG,
111954359Sroberto		RAWDCF_OFLAG,
112054359Sroberto		RAWDCF_LFLAG,
112154359Sroberto		RAWDCF_SAMPLES,
112254359Sroberto		RAWDCF_KEEP
112354359Sroberto	},
112454359Sroberto	{				/* mode 9 */
112554359Sroberto		TRIMBLETAIP_FLAGS,
112654359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
112754359Sroberto		NO_POLL,
112854359Sroberto#else
112954359Sroberto		TRIMBLETAIP_POLL,
113054359Sroberto#endif
113154359Sroberto		TRIMBLETAIP_INIT,
113254359Sroberto		TRIMBLETAIP_EVENT,
113354359Sroberto		TRIMBLETAIP_END,
113454359Sroberto		NO_MESSAGE,
113554359Sroberto		TRIMBLETAIP_DATA,
113654359Sroberto		TRIMBLETAIP_ROOTDELAY,
113754359Sroberto		TRIMBLETAIP_BASEDELAY,
113854359Sroberto		TRIMBLETAIP_ID,
113954359Sroberto		TRIMBLETAIP_DESCRIPTION,
114054359Sroberto		TRIMBLETAIP_FORMAT,
114154359Sroberto		GPS_TYPE,
114254359Sroberto		TRIMBLETAIP_MAXUNSYNC,
114354359Sroberto		TRIMBLETAIP_SPEED,
114454359Sroberto		TRIMBLETAIP_CFLAG,
114554359Sroberto		TRIMBLETAIP_IFLAG,
114654359Sroberto		TRIMBLETAIP_OFLAG,
114754359Sroberto		TRIMBLETAIP_LFLAG,
114854359Sroberto		TRIMBLETAIP_SAMPLES,
114954359Sroberto		TRIMBLETAIP_KEEP
115054359Sroberto	},
115154359Sroberto	{				/* mode 10 */
115254359Sroberto		TRIMBLETSIP_FLAGS,
115354359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
115454359Sroberto		NO_POLL,
115554359Sroberto#else
115654359Sroberto		TRIMBLETSIP_POLL,
115754359Sroberto#endif
115854359Sroberto		TRIMBLETSIP_INIT,
115954359Sroberto		TRIMBLETSIP_EVENT,
116054359Sroberto		TRIMBLETSIP_END,
116154359Sroberto		TRIMBLETSIP_MESSAGE,
116254359Sroberto		TRIMBLETSIP_DATA,
116354359Sroberto		TRIMBLETSIP_ROOTDELAY,
116454359Sroberto		TRIMBLETSIP_BASEDELAY,
116554359Sroberto		TRIMBLETSIP_ID,
116654359Sroberto		TRIMBLETSIP_DESCRIPTION,
116754359Sroberto		TRIMBLETSIP_FORMAT,
116854359Sroberto		GPS_TYPE,
116954359Sroberto		TRIMBLETSIP_MAXUNSYNC,
117054359Sroberto		TRIMBLETSIP_SPEED,
117154359Sroberto		TRIMBLETSIP_CFLAG,
117254359Sroberto		TRIMBLETSIP_IFLAG,
117354359Sroberto		TRIMBLETSIP_OFLAG,
117454359Sroberto		TRIMBLETSIP_LFLAG,
117554359Sroberto		TRIMBLETSIP_SAMPLES,
117654359Sroberto		TRIMBLETSIP_KEEP
117754359Sroberto	},
117854359Sroberto	{                             /* mode 11 */
117954359Sroberto		NO_CL_FLAGS,
118054359Sroberto		RCC8000_POLL,
118154359Sroberto		RCC8000_INIT,
118254359Sroberto		NO_EVENT,
118354359Sroberto		RCC8000_END,
118454359Sroberto		NO_MESSAGE,
118554359Sroberto		RCC8000_DATA,
118654359Sroberto		RCC8000_ROOTDELAY,
118754359Sroberto		RCC8000_BASEDELAY,
118854359Sroberto		RCC8000_ID,
118954359Sroberto		RCC8000_DESCRIPTION,
119054359Sroberto		RCC8000_FORMAT,
119154359Sroberto		DCF_TYPE,
119254359Sroberto		RCC8000_MAXUNSYNC,
119354359Sroberto		RCC8000_SPEED,
119454359Sroberto		RCC8000_CFLAG,
119554359Sroberto		RCC8000_IFLAG,
119654359Sroberto		RCC8000_OFLAG,
119754359Sroberto		RCC8000_LFLAG,
119854359Sroberto		RCC8000_SAMPLES,
119954359Sroberto		RCC8000_KEEP
120054359Sroberto	},
120154359Sroberto	{                             /* mode 12 */
120254359Sroberto		HOPF6021_FLAGS,
120354359Sroberto		NO_POLL,
120454359Sroberto		NO_INIT,
120554359Sroberto		NO_EVENT,
120654359Sroberto		NO_END,
120754359Sroberto		NO_MESSAGE,
1208182007Sroberto		NO_LCLDATA,
120954359Sroberto		HOPF6021_ROOTDELAY,
121054359Sroberto		HOPF6021_BASEDELAY,
121154359Sroberto		DCF_ID,
121254359Sroberto		HOPF6021_DESCRIPTION,
121354359Sroberto		HOPF6021_FORMAT,
121454359Sroberto		DCF_TYPE,
121554359Sroberto		HOPF6021_MAXUNSYNC,
121654359Sroberto		HOPF6021_SPEED,
121754359Sroberto		HOPF6021_CFLAG,
121854359Sroberto		HOPF6021_IFLAG,
121954359Sroberto		HOPF6021_OFLAG,
122054359Sroberto		HOPF6021_LFLAG,
122154359Sroberto		HOPF6021_SAMPLES,
122254359Sroberto		HOPF6021_KEEP
122354359Sroberto	},
122454359Sroberto	{                            /* mode 13 */
122554359Sroberto		COMPUTIME_FLAGS,
122654359Sroberto		NO_POLL,
122754359Sroberto		NO_INIT,
122854359Sroberto		NO_EVENT,
122954359Sroberto		NO_END,
123054359Sroberto		NO_MESSAGE,
1231182007Sroberto		NO_LCLDATA,
123254359Sroberto		COMPUTIME_ROOTDELAY,
123354359Sroberto		COMPUTIME_BASEDELAY,
123454359Sroberto		COMPUTIME_ID,
123554359Sroberto		COMPUTIME_DESCRIPTION,
123654359Sroberto		COMPUTIME_FORMAT,
123754359Sroberto		COMPUTIME_TYPE,
123854359Sroberto		COMPUTIME_MAXUNSYNC,
123954359Sroberto		COMPUTIME_SPEED,
124054359Sroberto		COMPUTIME_CFLAG,
124154359Sroberto		COMPUTIME_IFLAG,
124254359Sroberto		COMPUTIME_OFLAG,
124354359Sroberto		COMPUTIME_LFLAG,
124454359Sroberto		COMPUTIME_SAMPLES,
124554359Sroberto		COMPUTIME_KEEP
124654359Sroberto	},
124754359Sroberto	{				/* mode 14 */
124854359Sroberto		RAWDCF_FLAGS,
124954359Sroberto		NO_POLL,
125056746Sroberto		RAWDCFDTRSET_INIT,
125154359Sroberto		NO_EVENT,
125254359Sroberto		NO_END,
125354359Sroberto		NO_MESSAGE,
1254182007Sroberto		NO_LCLDATA,
125554359Sroberto		RAWDCF_ROOTDELAY,
125654359Sroberto		RAWDCF_BASEDELAY,
125754359Sroberto		DCF_A_ID,
125856746Sroberto		RAWDCFDTRSET_DESCRIPTION,
125954359Sroberto		RAWDCF_FORMAT,
126054359Sroberto		DCF_TYPE,
126154359Sroberto		RAWDCF_MAXUNSYNC,
126254359Sroberto		RAWDCF_SPEED,
126354359Sroberto		RAWDCF_CFLAG,
126454359Sroberto		RAWDCF_IFLAG,
126554359Sroberto		RAWDCF_OFLAG,
126654359Sroberto		RAWDCF_LFLAG,
126754359Sroberto		RAWDCF_SAMPLES,
126854359Sroberto		RAWDCF_KEEP
126954359Sroberto	},
127054359Sroberto	{				/* mode 15 */
127156746Sroberto		0,				/* operation flags (io modes) */
127282498Sroberto  		NO_POLL,			/* active poll routine */
127382498Sroberto		NO_INIT,			/* active poll init routine */
127456746Sroberto  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
127556746Sroberto  		NO_END,				/* active poll end routine */
127656746Sroberto  		NO_MESSAGE,			/* process a lower layer message */
1277182007Sroberto		NO_LCLDATA,			/* local data area for "poll" mechanism */
127856746Sroberto		0,				/* rootdelay */
127982498Sroberto		11.0 /* bits */ / 9600,		/* current offset by which the RS232
128056746Sroberto				           	time code is delayed from the actual time */
128156746Sroberto		DCF_ID,				/* ID code */
128256746Sroberto		"WHARTON 400A Series clock",	/* device name */
128382498Sroberto		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
128456746Sroberto			/* Must match a format-name in a libparse/clk_xxx.c file */
128556746Sroberto		DCF_TYPE,			/* clock type (ntp control) */
1286132451Sroberto		(1*60*60),		        /* time to trust oscillator after losing synch */
128756746Sroberto		B9600,				/* terminal input & output baudrate */
128856746Sroberto		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
128956746Sroberto		0,				/* terminal input flags */
129056746Sroberto		0,				/* terminal output flags */
129156746Sroberto		0,				/* terminal local flags */
129256746Sroberto		5,				/* samples for median filter */
129356746Sroberto		3,				/* samples for median filter to keep */
129454359Sroberto	},
129556746Sroberto	{				/* mode 16 - RAWDCF RTS set, DTR clr */
129656746Sroberto		RAWDCF_FLAGS,
129756746Sroberto		NO_POLL,
129856746Sroberto		RAWDCFDTRCLRRTSSET_INIT,
129956746Sroberto		NO_EVENT,
130056746Sroberto		NO_END,
130156746Sroberto		NO_MESSAGE,
1302182007Sroberto		NO_LCLDATA,
130356746Sroberto		RAWDCF_ROOTDELAY,
130456746Sroberto		RAWDCF_BASEDELAY,
130556746Sroberto		DCF_A_ID,
130656746Sroberto		RAWDCFDTRCLRRTSSET_DESCRIPTION,
130756746Sroberto		RAWDCF_FORMAT,
130856746Sroberto		DCF_TYPE,
130956746Sroberto		RAWDCF_MAXUNSYNC,
131056746Sroberto		RAWDCF_SPEED,
131156746Sroberto		RAWDCF_CFLAG,
131256746Sroberto		RAWDCF_IFLAG,
131356746Sroberto		RAWDCF_OFLAG,
131456746Sroberto		RAWDCF_LFLAG,
131556746Sroberto		RAWDCF_SAMPLES,
131656746Sroberto		RAWDCF_KEEP
131756746Sroberto	},
131856746Sroberto        {                            /* mode 17 */
131954359Sroberto                VARITEXT_FLAGS,
132054359Sroberto                NO_POLL,
132154359Sroberto                NO_INIT,
132254359Sroberto                NO_EVENT,
132354359Sroberto                NO_END,
132454359Sroberto                NO_MESSAGE,
1325182007Sroberto                NO_LCLDATA,
132654359Sroberto                VARITEXT_ROOTDELAY,
132754359Sroberto                VARITEXT_BASEDELAY,
132854359Sroberto                VARITEXT_ID,
132954359Sroberto                VARITEXT_DESCRIPTION,
133054359Sroberto                VARITEXT_FORMAT,
133154359Sroberto                VARITEXT_TYPE,
133254359Sroberto                VARITEXT_MAXUNSYNC,
133354359Sroberto                VARITEXT_SPEED,
133454359Sroberto                VARITEXT_CFLAG,
133554359Sroberto                VARITEXT_IFLAG,
133654359Sroberto                VARITEXT_OFLAG,
133754359Sroberto                VARITEXT_LFLAG,
133854359Sroberto                VARITEXT_SAMPLES,
133954359Sroberto                VARITEXT_KEEP
1340182007Sroberto        },
1341182007Sroberto	{				/* mode 18 */
1342182007Sroberto		MBG_FLAGS,
1343182007Sroberto		NO_POLL,
1344182007Sroberto		NO_INIT,
1345182007Sroberto		NO_EVENT,
1346182007Sroberto		GPS16X_END,
1347182007Sroberto		GPS16X_MESSAGE,
1348182007Sroberto		GPS16X_DATA,
1349182007Sroberto		GPS16X_ROOTDELAY,
1350182007Sroberto		GPS16X_BASEDELAY,
1351182007Sroberto		GPS16X_ID,
1352182007Sroberto		GPS16X_DESCRIPTION,
1353182007Sroberto		GPS16X_FORMAT,
1354182007Sroberto		GPS_TYPE,
1355182007Sroberto		GPS16X_MAXUNSYNC,
1356182007Sroberto		GPS16X_SPEED,
1357182007Sroberto		GPS16X_CFLAG,
1358182007Sroberto		GPS16X_IFLAG,
1359182007Sroberto		GPS16X_OFLAG,
1360182007Sroberto		GPS16X_LFLAG,
1361182007Sroberto		GPS16X_SAMPLES,
1362182007Sroberto		GPS16X_KEEP
1363182007Sroberto	},
1364182007Sroberto	{				/* mode 19 */
1365182007Sroberto		RAWDCF_FLAGS,
1366182007Sroberto		NO_POLL,
1367182007Sroberto		RAWDCF_INIT,
1368182007Sroberto		NO_EVENT,
1369182007Sroberto		NO_END,
1370182007Sroberto		NO_MESSAGE,
1371182007Sroberto		NO_LCLDATA,
1372182007Sroberto		RAWDCF_ROOTDELAY,
1373182007Sroberto		GUDE_EMC_USB_V20_BASEDELAY,
1374182007Sroberto		DCF_A_ID,
1375182007Sroberto		GUDE_EMC_USB_V20_DESCRIPTION,
1376182007Sroberto		RAWDCF_FORMAT,
1377182007Sroberto		DCF_TYPE,
1378182007Sroberto		RAWDCF_MAXUNSYNC,
1379182007Sroberto		GUDE_EMC_USB_V20_SPEED,
1380182007Sroberto		RAWDCF_CFLAG,
1381182007Sroberto		RAWDCF_IFLAG,
1382182007Sroberto		RAWDCF_OFLAG,
1383182007Sroberto		RAWDCF_LFLAG,
1384182007Sroberto		RAWDCF_SAMPLES,
1385182007Sroberto		RAWDCF_KEEP
1386182007Sroberto	},
1387280849Scy	{				/* mode 20, like mode 14 but driven by 75 baud */
1388280849Scy		RAWDCF_FLAGS,
1389280849Scy		NO_POLL,
1390280849Scy		RAWDCFDTRSET_INIT,
1391280849Scy		NO_EVENT,
1392280849Scy		NO_END,
1393280849Scy		NO_MESSAGE,
1394280849Scy		NO_LCLDATA,
1395280849Scy		RAWDCF_ROOTDELAY,
1396280849Scy		RAWDCF_BASEDELAY,
1397280849Scy		DCF_A_ID,
1398280849Scy		RAWDCFDTRSET75_DESCRIPTION,
1399280849Scy		RAWDCF_FORMAT,
1400280849Scy		DCF_TYPE,
1401280849Scy		RAWDCF_MAXUNSYNC,
1402280849Scy		B75,
1403280849Scy		RAWDCF_CFLAG,
1404280849Scy		RAWDCF_IFLAG,
1405280849Scy		RAWDCF_OFLAG,
1406280849Scy		RAWDCF_LFLAG,
1407280849Scy		RAWDCF_SAMPLES,
1408280849Scy		RAWDCF_KEEP
1409280849Scy	},
1410280849Scy	{				/* mode 21, like mode 16 but driven by 75 baud
1411280849Scy					 - RAWDCF RTS set, DTR clr */
1412280849Scy		RAWDCF_FLAGS,
1413280849Scy		NO_POLL,
1414280849Scy		RAWDCFDTRCLRRTSSET_INIT,
1415280849Scy		NO_EVENT,
1416280849Scy		NO_END,
1417280849Scy		NO_MESSAGE,
1418280849Scy		NO_LCLDATA,
1419280849Scy		RAWDCF_ROOTDELAY,
1420280849Scy		RAWDCF_BASEDELAY,
1421280849Scy		DCF_A_ID,
1422280849Scy		RAWDCFDTRCLRRTSSET75_DESCRIPTION,
1423280849Scy		RAWDCF_FORMAT,
1424280849Scy		DCF_TYPE,
1425280849Scy		RAWDCF_MAXUNSYNC,
1426280849Scy		B75,
1427280849Scy		RAWDCF_CFLAG,
1428280849Scy		RAWDCF_IFLAG,
1429280849Scy		RAWDCF_OFLAG,
1430280849Scy		RAWDCF_LFLAG,
1431280849Scy		RAWDCF_SAMPLES,
1432280849Scy		RAWDCF_KEEP
1433280849Scy	},
1434280849Scy	{				/* mode 22 - like 2 with POWERUP trust */
1435280849Scy		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1436280849Scy		NO_POLL,
1437280849Scy		NO_INIT,
1438280849Scy		NO_EVENT,
1439280849Scy		NO_END,
1440280849Scy		NO_MESSAGE,
1441280849Scy		NO_LCLDATA,
1442280849Scy		DCFUA31_ROOTDELAY,
1443280849Scy		DCFUA31_BASEDELAY,
1444280849Scy		DCF_A_ID,
1445280849Scy		DCFUA31_DESCRIPTION,
1446280849Scy		DCFUA31_FORMAT,
1447280849Scy		DCF_TYPE,
1448280849Scy		DCFUA31_MAXUNSYNC,
1449280849Scy		DCFUA31_SPEED,
1450280849Scy		DCFUA31_CFLAG,
1451280849Scy		DCFUA31_IFLAG,
1452280849Scy		DCFUA31_OFLAG,
1453280849Scy		DCFUA31_LFLAG,
1454280849Scy		DCFUA31_SAMPLES,
1455280849Scy		DCFUA31_KEEP
1456280849Scy	},
1457280849Scy	{				/* mode 23 - like 7 with POWERUP trust */
1458280849Scy		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1459280849Scy		GPS16X_POLL,
1460280849Scy		GPS16X_INIT,
1461280849Scy		NO_EVENT,
1462280849Scy		GPS16X_END,
1463280849Scy		GPS16X_MESSAGE,
1464280849Scy		GPS16X_DATA,
1465280849Scy		GPS16X_ROOTDELAY,
1466280849Scy		GPS16X_BASEDELAY,
1467280849Scy		GPS16X_ID,
1468280849Scy		GPS16X_DESCRIPTION,
1469280849Scy		GPS16X_FORMAT,
1470280849Scy		GPS_TYPE,
1471280849Scy		GPS16X_MAXUNSYNC,
1472280849Scy		GPS16X_SPEED,
1473280849Scy		GPS16X_CFLAG,
1474280849Scy		GPS16X_IFLAG,
1475280849Scy		GPS16X_OFLAG,
1476280849Scy		GPS16X_LFLAG,
1477280849Scy		GPS16X_SAMPLES,
1478280849Scy		GPS16X_KEEP
1479280849Scy	},
1480280849Scy	{				/* mode 24 */
1481280849Scy		SEL240X_FLAGS,
1482280849Scy		SEL240X_POLL,
1483280849Scy		SEL240X_INIT,
1484280849Scy		NO_EVENT,
1485280849Scy		SEL240X_END,
1486280849Scy		NO_MESSAGE,
1487280849Scy		SEL240X_DATA,
1488280849Scy		SEL240X_ROOTDELAY,
1489280849Scy		SEL240X_BASEDELAY,
1490280849Scy		SEL240X_ID,
1491280849Scy		SEL240X_DESCRIPTION,
1492280849Scy		SEL240X_FORMAT,
1493280849Scy		GPS_TYPE,
1494280849Scy		SEL240X_MAXUNSYNC,
1495280849Scy		SEL240X_SPEED,
1496280849Scy		SEL240X_CFLAG,
1497280849Scy		SEL240X_IFLAG,
1498280849Scy		SEL240X_OFLAG,
1499280849Scy		SEL240X_LFLAG,
1500280849Scy		SEL240X_SAMPLES,
1501280849Scy		SEL240X_KEEP
1502280849Scy	},
150354359Sroberto};
150454359Sroberto
150554359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
150654359Sroberto
1507132451Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
150854359Sroberto#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
150954359Sroberto#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1510132451Sroberto#define CLK_PPS(x)	(((x)->ttl) & 0x80)
151154359Sroberto
151254359Sroberto/*
151354359Sroberto * Other constant stuff
151454359Sroberto */
151554359Sroberto#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
151654359Sroberto
151754359Sroberto#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
151854359Sroberto
151954359Srobertostatic int notice = 0;
152054359Sroberto
152154359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
152254359Sroberto
1523280849Scystatic void parse_event   (struct parseunit *, int);
1524280849Scystatic void parse_process (struct parseunit *, parsetime_t *);
1525280849Scystatic void clear_err     (struct parseunit *, u_long);
1526280849Scystatic int  list_err      (struct parseunit *, u_long);
1527280849Scystatic char * l_mktime    (u_long);
152854359Sroberto
152954359Sroberto/**===========================================================================
153054359Sroberto ** implementation error message regression module
153154359Sroberto **/
153254359Srobertostatic void
153354359Srobertoclear_err(
153454359Sroberto	struct parseunit *parse,
153554359Sroberto	u_long            lstate
153654359Sroberto	)
153754359Sroberto{
153854359Sroberto	if (lstate == ERR_ALL)
153954359Sroberto	{
1540280849Scy		size_t i;
154154359Sroberto
154254359Sroberto		for (i = 0; i < ERR_CNT; i++)
154354359Sroberto		{
154454359Sroberto			parse->errors[i].err_stage   = err_tbl[i];
154554359Sroberto			parse->errors[i].err_cnt     = 0;
154654359Sroberto			parse->errors[i].err_last    = 0;
154754359Sroberto			parse->errors[i].err_started = 0;
154854359Sroberto			parse->errors[i].err_suppressed = 0;
154954359Sroberto		}
155054359Sroberto	}
155154359Sroberto	else
155254359Sroberto	{
155354359Sroberto		parse->errors[lstate].err_stage   = err_tbl[lstate];
155454359Sroberto		parse->errors[lstate].err_cnt     = 0;
155554359Sroberto		parse->errors[lstate].err_last    = 0;
155654359Sroberto		parse->errors[lstate].err_started = 0;
155754359Sroberto		parse->errors[lstate].err_suppressed = 0;
155854359Sroberto	}
155954359Sroberto}
156054359Sroberto
156154359Srobertostatic int
156254359Srobertolist_err(
156354359Sroberto	struct parseunit *parse,
156454359Sroberto	u_long            lstate
156554359Sroberto	)
156654359Sroberto{
156754359Sroberto	int do_it;
156854359Sroberto	struct errorinfo *err = &parse->errors[lstate];
156954359Sroberto
157054359Sroberto	if (err->err_started == 0)
157154359Sroberto	{
157254359Sroberto		err->err_started = current_time;
157354359Sroberto	}
157454359Sroberto
157554359Sroberto	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
157654359Sroberto
157754359Sroberto	if (do_it)
157854359Sroberto	    err->err_cnt++;
157954359Sroberto
158054359Sroberto	if (err->err_stage->err_count &&
158154359Sroberto	    (err->err_cnt >= err->err_stage->err_count))
158254359Sroberto	{
158354359Sroberto		err->err_stage++;
158454359Sroberto		err->err_cnt = 0;
158554359Sroberto	}
158654359Sroberto
158754359Sroberto	if (!err->err_cnt && do_it)
158854359Sroberto	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
158954359Sroberto		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
159054359Sroberto
159154359Sroberto	if (!do_it)
159254359Sroberto	    err->err_suppressed++;
159354359Sroberto	else
159454359Sroberto	    err->err_last = current_time;
159554359Sroberto
159654359Sroberto	if (do_it && err->err_suppressed)
159754359Sroberto	{
159854359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
159954359Sroberto			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
160054359Sroberto			l_mktime(current_time - err->err_started));
160154359Sroberto		err->err_suppressed = 0;
160254359Sroberto	}
160354359Sroberto
160454359Sroberto	return do_it;
160554359Sroberto}
160654359Sroberto
160754359Sroberto/*--------------------------------------------------
160854359Sroberto * mkreadable - make a printable ascii string (without
160954359Sroberto * embedded quotes so that the ntpq protocol isn't
161054359Sroberto * fooled
161154359Sroberto */
161254359Sroberto#ifndef isprint
161354359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
161454359Sroberto#endif
161554359Sroberto
161654359Srobertostatic char *
161754359Srobertomkreadable(
161854359Sroberto	char  *buffer,
161954359Sroberto	long  blen,
162054359Sroberto	const char  *src,
162154359Sroberto	u_long  srclen,
162254359Sroberto	int hex
162354359Sroberto	)
162454359Sroberto{
1625280849Scy	static const char ellipsis[] = "...";
162654359Sroberto	char *b    = buffer;
1627280849Scy	char *endb = NULL;
162854359Sroberto
162954359Sroberto	if (blen < 4)
1630280849Scy		return NULL;		/* don't bother with mini buffers */
163154359Sroberto
1632280849Scy	endb = buffer + blen - sizeof(ellipsis);
163354359Sroberto
163454359Sroberto	blen--;			/* account for '\0' */
163554359Sroberto
163654359Sroberto	while (blen && srclen--)
163754359Sroberto	{
163854359Sroberto		if (!hex &&             /* no binary only */
163954359Sroberto		    (*src != '\\') &&   /* no plain \ */
164054359Sroberto		    (*src != '"') &&    /* no " */
1641280849Scy		    isprint((unsigned char)*src))	/* only printables */
164254359Sroberto		{			/* they are easy... */
164354359Sroberto			*buffer++ = *src++;
164454359Sroberto			blen--;
164554359Sroberto		}
164654359Sroberto		else
164754359Sroberto		{
164854359Sroberto			if (blen < 4)
164954359Sroberto			{
165054359Sroberto				while (blen--)
165154359Sroberto				{
165254359Sroberto					*buffer++ = '.';
165354359Sroberto				}
165454359Sroberto				*buffer = '\0';
165554359Sroberto				return b;
165654359Sroberto			}
165754359Sroberto			else
165854359Sroberto			{
165954359Sroberto				if (*src == '\\')
166054359Sroberto				{
1661280849Scy					memcpy(buffer, "\\\\", 2);
166254359Sroberto					buffer += 2;
166354359Sroberto					blen   -= 2;
166454359Sroberto					src++;
166554359Sroberto				}
166654359Sroberto				else
166754359Sroberto				{
1668280849Scy					snprintf(buffer, blen, "\\x%02x", *src++);
166954359Sroberto					blen   -= 4;
167054359Sroberto					buffer += 4;
167154359Sroberto				}
167254359Sroberto			}
167354359Sroberto		}
167454359Sroberto		if (srclen && !blen && endb) /* overflow - set last chars to ... */
1675280849Scy			memcpy(endb, ellipsis, sizeof(ellipsis));
167654359Sroberto	}
167754359Sroberto
167854359Sroberto	*buffer = '\0';
167954359Sroberto	return b;
168054359Sroberto}
168154359Sroberto
168254359Sroberto
168354359Sroberto/*--------------------------------------------------
168454359Sroberto * mkascii - make a printable ascii string
168554359Sroberto * assumes (unless defined better) 7-bit ASCII
168654359Sroberto */
168754359Srobertostatic char *
168854359Srobertomkascii(
168954359Sroberto	char  *buffer,
169054359Sroberto	long  blen,
169154359Sroberto	const char  *src,
169254359Sroberto	u_long  srclen
169354359Sroberto	)
169454359Sroberto{
169554359Sroberto	return mkreadable(buffer, blen, src, srclen, 0);
169654359Sroberto}
169754359Sroberto
169854359Sroberto/**===========================================================================
169954359Sroberto ** implementation of i/o handling methods
170054359Sroberto ** (all STREAM, partial STREAM, user level)
170154359Sroberto **/
170254359Sroberto
170354359Sroberto/*
170454359Sroberto * define possible io handling methods
170554359Sroberto */
170654359Sroberto#ifdef STREAM
1707280849Scystatic int  ppsclock_init   (struct parseunit *);
1708280849Scystatic int  stream_init     (struct parseunit *);
1709280849Scystatic void stream_end      (struct parseunit *);
1710280849Scystatic int  stream_enable   (struct parseunit *);
1711280849Scystatic int  stream_disable  (struct parseunit *);
1712280849Scystatic int  stream_setcs    (struct parseunit *, parsectl_t *);
1713280849Scystatic int  stream_getfmt   (struct parseunit *, parsectl_t *);
1714280849Scystatic int  stream_setfmt   (struct parseunit *, parsectl_t *);
1715280849Scystatic int  stream_timecode (struct parseunit *, parsectl_t *);
1716280849Scystatic void stream_receive  (struct recvbuf *);
171754359Sroberto#endif
171854359Sroberto
1719280849Scystatic int  local_init     (struct parseunit *);
1720280849Scystatic void local_end      (struct parseunit *);
1721280849Scystatic int  local_nop      (struct parseunit *);
1722280849Scystatic int  local_setcs    (struct parseunit *, parsectl_t *);
1723280849Scystatic int  local_getfmt   (struct parseunit *, parsectl_t *);
1724280849Scystatic int  local_setfmt   (struct parseunit *, parsectl_t *);
1725280849Scystatic int  local_timecode (struct parseunit *, parsectl_t *);
1726280849Scystatic void local_receive  (struct recvbuf *);
1727280849Scystatic int  local_input    (struct recvbuf *);
172854359Sroberto
172954359Srobertostatic bind_t io_bindings[] =
173054359Sroberto{
173154359Sroberto#ifdef STREAM
173254359Sroberto	{
173354359Sroberto		"parse STREAM",
173454359Sroberto		stream_init,
173554359Sroberto		stream_end,
173654359Sroberto		stream_setcs,
173754359Sroberto		stream_disable,
173854359Sroberto		stream_enable,
173954359Sroberto		stream_getfmt,
174054359Sroberto		stream_setfmt,
174154359Sroberto		stream_timecode,
174254359Sroberto		stream_receive,
174354359Sroberto		0,
174454359Sroberto	},
174554359Sroberto	{
174654359Sroberto		"ppsclock STREAM",
174754359Sroberto		ppsclock_init,
174854359Sroberto		local_end,
174954359Sroberto		local_setcs,
175054359Sroberto		local_nop,
175154359Sroberto		local_nop,
175254359Sroberto		local_getfmt,
175354359Sroberto		local_setfmt,
175454359Sroberto		local_timecode,
175554359Sroberto		local_receive,
175654359Sroberto		local_input,
175754359Sroberto	},
175854359Sroberto#endif
175954359Sroberto	{
176054359Sroberto		"normal",
176154359Sroberto		local_init,
176254359Sroberto		local_end,
176354359Sroberto		local_setcs,
176454359Sroberto		local_nop,
176554359Sroberto		local_nop,
176654359Sroberto		local_getfmt,
176754359Sroberto		local_setfmt,
176854359Sroberto		local_timecode,
176954359Sroberto		local_receive,
177054359Sroberto		local_input,
177154359Sroberto	},
177254359Sroberto	{
177354359Sroberto		(char *)0,
1774280849Scy		NULL,
1775280849Scy		NULL,
1776280849Scy		NULL,
1777280849Scy		NULL,
1778280849Scy		NULL,
1779280849Scy		NULL,
1780280849Scy		NULL,
1781280849Scy		NULL,
1782280849Scy		NULL,
1783280849Scy		NULL,
178454359Sroberto	}
178554359Sroberto};
178654359Sroberto
178754359Sroberto#ifdef STREAM
178854359Sroberto
178954359Sroberto/*--------------------------------------------------
179054359Sroberto * ppsclock STREAM init
179154359Sroberto */
179254359Srobertostatic int
179354359Srobertoppsclock_init(
179454359Sroberto	struct parseunit *parse
179554359Sroberto	)
179654359Sroberto{
179754359Sroberto        static char m1[] = "ppsclocd";
179854359Sroberto	static char m2[] = "ppsclock";
179954359Sroberto
180054359Sroberto	/*
180154359Sroberto	 * now push the parse streams module
180254359Sroberto	 * it will ensure exclusive access to the device
180354359Sroberto	 */
1804182007Sroberto	if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1805182007Sroberto	    ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
180654359Sroberto	{
180754359Sroberto		if (errno != EINVAL)
180856746Sroberto		{
180956746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
181056746Sroberto				CLK_UNIT(parse->peer));
181154359Sroberto		}
181254359Sroberto		return 0;
181354359Sroberto	}
181454359Sroberto	if (!local_init(parse))
181554359Sroberto	{
1816182007Sroberto		(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
181754359Sroberto		return 0;
181854359Sroberto	}
181954359Sroberto
182054359Sroberto	parse->flags |= PARSE_PPSCLOCK;
182154359Sroberto	return 1;
182254359Sroberto}
182354359Sroberto
182454359Sroberto/*--------------------------------------------------
182554359Sroberto * parse STREAM init
182654359Sroberto */
182754359Srobertostatic int
182854359Srobertostream_init(
182954359Sroberto	struct parseunit *parse
183054359Sroberto	)
183154359Sroberto{
183254359Sroberto	static char m1[] = "parse";
183354359Sroberto	/*
183454359Sroberto	 * now push the parse streams module
183554359Sroberto	 * to test whether it is there (neat interface 8-( )
183654359Sroberto	 */
183754359Sroberto	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
183854359Sroberto	{
183954359Sroberto		if (errno != EINVAL) /* accept non-existence */
184056746Sroberto		{
184156746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
184254359Sroberto		}
184354359Sroberto		return 0;
184454359Sroberto	}
184554359Sroberto	else
184654359Sroberto	{
184754359Sroberto		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
184854359Sroberto		    /* empty loop */;
184954359Sroberto
185054359Sroberto		/*
185154359Sroberto		 * now push it a second time after we have removed all
185254359Sroberto		 * module garbage
185354359Sroberto		 */
185454359Sroberto		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
185554359Sroberto		{
185654359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
185754359Sroberto			return 0;
185854359Sroberto		}
185954359Sroberto		else
186054359Sroberto		{
186154359Sroberto			return 1;
186254359Sroberto		}
186354359Sroberto	}
186454359Sroberto}
186554359Sroberto
186654359Sroberto/*--------------------------------------------------
186754359Sroberto * parse STREAM end
186854359Sroberto */
186954359Srobertostatic void
187054359Srobertostream_end(
187154359Sroberto	struct parseunit *parse
187254359Sroberto	)
187354359Sroberto{
187454359Sroberto	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
187554359Sroberto	    /* empty loop */;
187654359Sroberto}
187754359Sroberto
187854359Sroberto/*--------------------------------------------------
187954359Sroberto * STREAM setcs
188054359Sroberto */
188154359Srobertostatic int
188254359Srobertostream_setcs(
188354359Sroberto	struct parseunit *parse,
188454359Sroberto	parsectl_t  *tcl
188554359Sroberto	)
188654359Sroberto{
188754359Sroberto	struct strioctl strioc;
188854359Sroberto
188954359Sroberto	strioc.ic_cmd     = PARSEIOC_SETCS;
189054359Sroberto	strioc.ic_timout  = 0;
189154359Sroberto	strioc.ic_dp      = (char *)tcl;
189254359Sroberto	strioc.ic_len     = sizeof (*tcl);
189354359Sroberto
189454359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
189554359Sroberto	{
189654359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
189754359Sroberto		return 0;
189854359Sroberto	}
189954359Sroberto	return 1;
190054359Sroberto}
190154359Sroberto
190254359Sroberto/*--------------------------------------------------
190354359Sroberto * STREAM enable
190454359Sroberto */
190554359Srobertostatic int
190654359Srobertostream_enable(
190754359Sroberto	struct parseunit *parse
190854359Sroberto	)
190954359Sroberto{
191054359Sroberto	struct strioctl strioc;
191154359Sroberto
191254359Sroberto	strioc.ic_cmd     = PARSEIOC_ENABLE;
191354359Sroberto	strioc.ic_timout  = 0;
191454359Sroberto	strioc.ic_dp      = (char *)0;
191554359Sroberto	strioc.ic_len     = 0;
191654359Sroberto
191754359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
191854359Sroberto	{
191954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
192054359Sroberto		return 0;
192154359Sroberto	}
192254359Sroberto	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
192354359Sroberto	return 1;
192454359Sroberto}
192554359Sroberto
192654359Sroberto/*--------------------------------------------------
192754359Sroberto * STREAM disable
192854359Sroberto */
192954359Srobertostatic int
193054359Srobertostream_disable(
193154359Sroberto	struct parseunit *parse
193254359Sroberto	)
193354359Sroberto{
193454359Sroberto	struct strioctl strioc;
193554359Sroberto
193654359Sroberto	strioc.ic_cmd     = PARSEIOC_DISABLE;
193754359Sroberto	strioc.ic_timout  = 0;
193854359Sroberto	strioc.ic_dp      = (char *)0;
193954359Sroberto	strioc.ic_len     = 0;
194054359Sroberto
194154359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
194254359Sroberto	{
194354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
194454359Sroberto		return 0;
194554359Sroberto	}
194654359Sroberto	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
194754359Sroberto	return 1;
194854359Sroberto}
194954359Sroberto
195054359Sroberto/*--------------------------------------------------
195154359Sroberto * STREAM getfmt
195254359Sroberto */
195354359Srobertostatic int
195454359Srobertostream_getfmt(
195554359Sroberto	struct parseunit *parse,
195654359Sroberto	parsectl_t  *tcl
195754359Sroberto	)
195854359Sroberto{
195954359Sroberto	struct strioctl strioc;
196054359Sroberto
196154359Sroberto	strioc.ic_cmd     = PARSEIOC_GETFMT;
196254359Sroberto	strioc.ic_timout  = 0;
196354359Sroberto	strioc.ic_dp      = (char *)tcl;
196454359Sroberto	strioc.ic_len     = sizeof (*tcl);
196554359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
196654359Sroberto	{
196754359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
196854359Sroberto		return 0;
196954359Sroberto	}
197054359Sroberto	return 1;
197154359Sroberto}
197254359Sroberto
197354359Sroberto/*--------------------------------------------------
197454359Sroberto * STREAM setfmt
197554359Sroberto */
197654359Srobertostatic int
197754359Srobertostream_setfmt(
197854359Sroberto	struct parseunit *parse,
197954359Sroberto	parsectl_t  *tcl
198054359Sroberto	)
198154359Sroberto{
198254359Sroberto	struct strioctl strioc;
198354359Sroberto
198454359Sroberto	strioc.ic_cmd     = PARSEIOC_SETFMT;
198554359Sroberto	strioc.ic_timout  = 0;
198654359Sroberto	strioc.ic_dp      = (char *)tcl;
198754359Sroberto	strioc.ic_len     = sizeof (*tcl);
198854359Sroberto
198954359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
199054359Sroberto	{
199154359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
199254359Sroberto		return 0;
199354359Sroberto	}
199454359Sroberto	return 1;
199554359Sroberto}
199654359Sroberto
199754359Sroberto
199854359Sroberto/*--------------------------------------------------
199954359Sroberto * STREAM timecode
200054359Sroberto */
200154359Srobertostatic int
200254359Srobertostream_timecode(
200354359Sroberto	struct parseunit *parse,
200454359Sroberto	parsectl_t  *tcl
200554359Sroberto	)
200654359Sroberto{
200754359Sroberto	struct strioctl strioc;
200854359Sroberto
200954359Sroberto	strioc.ic_cmd     = PARSEIOC_TIMECODE;
201054359Sroberto	strioc.ic_timout  = 0;
201154359Sroberto	strioc.ic_dp      = (char *)tcl;
201254359Sroberto	strioc.ic_len     = sizeof (*tcl);
201354359Sroberto
201454359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
201554359Sroberto	{
201654359Sroberto		ERR(ERR_INTERNAL)
201754359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
201854359Sroberto		return 0;
201954359Sroberto	}
202054359Sroberto	clear_err(parse, ERR_INTERNAL);
202154359Sroberto	return 1;
202254359Sroberto}
202354359Sroberto
202454359Sroberto/*--------------------------------------------------
202554359Sroberto * STREAM receive
202654359Sroberto */
202754359Srobertostatic void
202854359Srobertostream_receive(
202954359Sroberto	struct recvbuf *rbufp
203054359Sroberto	)
203154359Sroberto{
2032280849Scy	struct parseunit * parse;
203354359Sroberto	parsetime_t parsetime;
203454359Sroberto
2035280849Scy	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
203654359Sroberto	if (!parse->peer)
203754359Sroberto	    return;
203854359Sroberto
203954359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
204054359Sroberto	{
204154359Sroberto		ERR(ERR_BADIO)
204254359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
204354359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
204454359Sroberto		parse_event(parse, CEVNT_BADREPLY);
204554359Sroberto		return;
204654359Sroberto	}
204754359Sroberto	clear_err(parse, ERR_BADIO);
204854359Sroberto
204954359Sroberto	memmove((caddr_t)&parsetime,
205054359Sroberto		(caddr_t)rbufp->recv_buffer,
205154359Sroberto		sizeof(parsetime_t));
205254359Sroberto
205354359Sroberto#ifdef DEBUG
205454359Sroberto	if (debug > 3)
205554359Sroberto	  {
205654359Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
205754359Sroberto		   CLK_UNIT(parse->peer),
205854359Sroberto		   (unsigned int)parsetime.parse_status,
205954359Sroberto		   (unsigned int)parsetime.parse_state,
2060182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_sec,
2061182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_usec,
2062182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_sec,
2063182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_usec,
2064182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_sec,
2065182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_usec);
206654359Sroberto	  }
206754359Sroberto#endif
206854359Sroberto
206954359Sroberto	/*
207054359Sroberto	 * switch time stamp world - be sure to normalize small usec field
207154359Sroberto	 * errors.
207254359Sroberto	 */
207354359Sroberto
2074280849Scy	parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv);
207554359Sroberto
207654359Sroberto	if (PARSE_TIMECODE(parsetime.parse_state))
207754359Sroberto	{
2078280849Scy		parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv);
207954359Sroberto	}
208054359Sroberto
208154359Sroberto	if (PARSE_PPS(parsetime.parse_state))
2082280849Scy	{
2083280849Scy		parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv);
2084280849Scy	}
208554359Sroberto
208654359Sroberto	parse_process(parse, &parsetime);
208754359Sroberto}
208854359Sroberto#endif
208954359Sroberto
209054359Sroberto/*--------------------------------------------------
209154359Sroberto * local init
209254359Sroberto */
209354359Srobertostatic int
209454359Srobertolocal_init(
209554359Sroberto	struct parseunit *parse
209654359Sroberto	)
209754359Sroberto{
209854359Sroberto	return parse_ioinit(&parse->parseio);
209954359Sroberto}
210054359Sroberto
210154359Sroberto/*--------------------------------------------------
210254359Sroberto * local end
210354359Sroberto */
210454359Srobertostatic void
210554359Srobertolocal_end(
210654359Sroberto	struct parseunit *parse
210754359Sroberto	)
210854359Sroberto{
210954359Sroberto	parse_ioend(&parse->parseio);
211054359Sroberto}
211154359Sroberto
211254359Sroberto
211354359Sroberto/*--------------------------------------------------
211454359Sroberto * local nop
211554359Sroberto */
211654359Srobertostatic int
211754359Srobertolocal_nop(
211854359Sroberto	struct parseunit *parse
211954359Sroberto	)
212054359Sroberto{
212154359Sroberto	return 1;
212254359Sroberto}
212354359Sroberto
212454359Sroberto/*--------------------------------------------------
212554359Sroberto * local setcs
212654359Sroberto */
212754359Srobertostatic int
212854359Srobertolocal_setcs(
212954359Sroberto	struct parseunit *parse,
213054359Sroberto	parsectl_t  *tcl
213154359Sroberto	)
213254359Sroberto{
213354359Sroberto	return parse_setcs(tcl, &parse->parseio);
213454359Sroberto}
213554359Sroberto
213654359Sroberto/*--------------------------------------------------
213754359Sroberto * local getfmt
213854359Sroberto */
213954359Srobertostatic int
214054359Srobertolocal_getfmt(
214154359Sroberto	struct parseunit *parse,
214254359Sroberto	parsectl_t  *tcl
214354359Sroberto	)
214454359Sroberto{
214554359Sroberto	return parse_getfmt(tcl, &parse->parseio);
214654359Sroberto}
214754359Sroberto
214854359Sroberto/*--------------------------------------------------
214954359Sroberto * local setfmt
215054359Sroberto */
215154359Srobertostatic int
215254359Srobertolocal_setfmt(
215354359Sroberto	struct parseunit *parse,
215454359Sroberto	parsectl_t  *tcl
215554359Sroberto	)
215654359Sroberto{
215754359Sroberto	return parse_setfmt(tcl, &parse->parseio);
215854359Sroberto}
215954359Sroberto
216054359Sroberto/*--------------------------------------------------
216154359Sroberto * local timecode
216254359Sroberto */
216354359Srobertostatic int
216454359Srobertolocal_timecode(
216554359Sroberto	struct parseunit *parse,
216654359Sroberto	parsectl_t  *tcl
216754359Sroberto	)
216854359Sroberto{
216954359Sroberto	return parse_timecode(tcl, &parse->parseio);
217054359Sroberto}
217154359Sroberto
217254359Sroberto
217354359Sroberto/*--------------------------------------------------
217454359Sroberto * local input
217554359Sroberto */
217654359Srobertostatic int
217754359Srobertolocal_input(
217854359Sroberto	struct recvbuf *rbufp
217954359Sroberto	)
218054359Sroberto{
2181280849Scy	struct parseunit * parse;
2182280849Scy
218354359Sroberto	int count;
218454359Sroberto	unsigned char *s;
218554359Sroberto	timestamp_t ts;
218654359Sroberto
2187280849Scy	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
218854359Sroberto	if (!parse->peer)
218954359Sroberto		return 0;
219054359Sroberto
219154359Sroberto	/*
219254359Sroberto	 * eat all characters, parsing then and feeding complete samples
219354359Sroberto	 */
219454359Sroberto	count = rbufp->recv_length;
219554359Sroberto	s = (unsigned char *)rbufp->recv_buffer;
219654359Sroberto	ts.fp = rbufp->recv_time;
219754359Sroberto
219854359Sroberto	while (count--)
219954359Sroberto	{
220054359Sroberto		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
220154359Sroberto		{
2202182007Sroberto			struct recvbuf *buf;
220354359Sroberto
220454359Sroberto			/*
220554359Sroberto			 * got something good to eat
220654359Sroberto			 */
220754359Sroberto			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
220854359Sroberto			{
2209182007Sroberto#ifdef HAVE_PPSAPI
2210182007Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2211182007Sroberto				{
2212182007Sroberto					struct timespec pps_timeout;
2213182007Sroberto					pps_info_t      pps_info;
2214182007Sroberto
2215182007Sroberto					pps_timeout.tv_sec  = 0;
2216182007Sroberto					pps_timeout.tv_nsec = 0;
2217182007Sroberto
2218280849Scy					if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
2219182007Sroberto							   &pps_timeout) == 0)
2220182007Sroberto					{
2221182007Sroberto						if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2222182007Sroberto						{
2223182007Sroberto							double dtemp;
2224182007Sroberto
2225182007Sroberto						        struct timespec pts;
2226182007Sroberto							/*
2227182007Sroberto							 * add PPS time stamp if available via ppsclock module
2228182007Sroberto							 * and not supplied already.
2229182007Sroberto							 */
2230182007Sroberto							if (parse->flags & PARSE_CLEAR)
2231182007Sroberto							  pts = pps_info.clear_timestamp;
2232182007Sroberto							else
2233182007Sroberto							  pts = pps_info.assert_timestamp;
2234182007Sroberto
2235182007Sroberto							parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
2236182007Sroberto
2237182007Sroberto							dtemp = pts.tv_nsec / 1e9;
2238182007Sroberto							if (dtemp < 0.) {
2239182007Sroberto								dtemp += 1;
2240182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2241182007Sroberto							}
2242182007Sroberto							if (dtemp > 1.) {
2243182007Sroberto								dtemp -= 1;
2244182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2245182007Sroberto							}
2246182007Sroberto							parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
2247182007Sroberto
2248182007Sroberto						        parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2249182007Sroberto#ifdef DEBUG
2250182007Sroberto							if (debug > 3)
2251182007Sroberto							{
2252182007Sroberto								printf(
2253182007Sroberto								       "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2254182007Sroberto								       rbufp->fd,
2255182007Sroberto								       (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2256182007Sroberto								       lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2257182007Sroberto							}
2258182007Sroberto#endif
2259182007Sroberto						}
2260182007Sroberto#ifdef DEBUG
2261182007Sroberto						else
2262182007Sroberto						{
2263182007Sroberto							if (debug > 3)
2264182007Sroberto							{
2265182007Sroberto								printf(
2266182007Sroberto								       "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2267182007Sroberto								       rbufp->fd,
2268182007Sroberto								       (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2269182007Sroberto							}
2270182007Sroberto						}
2271182007Sroberto#endif
2272182007Sroberto						parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2273182007Sroberto					}
2274182007Sroberto#ifdef DEBUG
2275182007Sroberto					else
2276182007Sroberto					{
2277182007Sroberto						if (debug > 3)
2278182007Sroberto						{
2279182007Sroberto							printf(
2280182007Sroberto							       "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2281182007Sroberto							       rbufp->fd,
2282182007Sroberto							       errno);
2283182007Sroberto						}
2284182007Sroberto					}
2285182007Sroberto#endif
2286182007Sroberto				}
2287182007Sroberto#else
228854359Sroberto#ifdef TIOCDCDTIMESTAMP
228954359Sroberto				struct timeval dcd_time;
229054359Sroberto
2291182007Sroberto				if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
229254359Sroberto				{
229354359Sroberto					l_fp tstmp;
229454359Sroberto
229554359Sroberto					TVTOTS(&dcd_time, &tstmp);
229654359Sroberto					tstmp.l_ui += JAN_1970;
229754359Sroberto					L_SUB(&ts.fp, &tstmp);
229854359Sroberto					if (ts.fp.l_ui == 0)
229954359Sroberto					{
230054359Sroberto#ifdef DEBUG
230154359Sroberto						if (debug)
230254359Sroberto						{
230354359Sroberto							printf(
230454359Sroberto							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2305182007Sroberto							       parse->ppsfd,
230654359Sroberto							       lfptoa(&tstmp, 6));
230754359Sroberto							printf(" sigio %s\n",
230854359Sroberto							       lfptoa(&ts.fp, 6));
230954359Sroberto						}
231054359Sroberto#endif
231154359Sroberto						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
231254359Sroberto						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
231354359Sroberto					}
231454359Sroberto				}
231554359Sroberto#else /* TIOCDCDTIMESTAMP */
231654359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
231754359Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2318182007Sroberto				  {
2319182007Sroberto				    l_fp tts;
2320182007Sroberto				    struct ppsclockev ev;
232154359Sroberto
232254359Sroberto#ifdef HAVE_CIOGETEV
2323182007Sroberto				    if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
232454359Sroberto#endif
232554359Sroberto#ifdef HAVE_TIOCGPPSEV
2326182007Sroberto				    if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
232754359Sroberto#endif
232854359Sroberto					{
2329182007Sroberto					  if (ev.serial != parse->ppsserial)
2330182007Sroberto					    {
2331182007Sroberto					      /*
2332182007Sroberto					       * add PPS time stamp if available via ppsclock module
2333182007Sroberto					       * and not supplied already.
2334182007Sroberto					       */
2335182007Sroberto					      if (!buftvtots((const char *)&ev.tv, &tts))
233654359Sroberto						{
2337182007Sroberto						  ERR(ERR_BADDATA)
2338182007Sroberto						    msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
233954359Sroberto						}
2340182007Sroberto					      else
2341182007Sroberto						{
2342182007Sroberto						  parse->parseio.parse_dtime.parse_ptime.fp = tts;
2343182007Sroberto						  parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2344182007Sroberto						}
2345182007Sroberto					    }
2346182007Sroberto					  parse->ppsserial = ev.serial;
234754359Sroberto					}
2348182007Sroberto				  }
234954359Sroberto#endif
235054359Sroberto#endif /* TIOCDCDTIMESTAMP */
2351182007Sroberto#endif /* !HAVE_PPSAPI */
235254359Sroberto			}
235354359Sroberto			if (count)
235454359Sroberto			{	/* simulate receive */
2355182007Sroberto				buf = get_free_recv_buffer();
2356182007Sroberto				if (buf != NULL) {
2357182007Sroberto					memmove((caddr_t)buf->recv_buffer,
2358182007Sroberto						(caddr_t)&parse->parseio.parse_dtime,
2359182007Sroberto						sizeof(parsetime_t));
2360182007Sroberto					buf->recv_length  = sizeof(parsetime_t);
2361182007Sroberto					buf->recv_time    = rbufp->recv_time;
2362280849Scy#ifndef HAVE_IO_COMPLETION_PORT
2363182007Sroberto					buf->srcadr       = rbufp->srcadr;
2364280849Scy#endif
2365182007Sroberto					buf->dstadr       = rbufp->dstadr;
2366182007Sroberto					buf->receiver     = rbufp->receiver;
2367182007Sroberto					buf->fd           = rbufp->fd;
2368182007Sroberto					buf->X_from_where = rbufp->X_from_where;
2369280849Scy					parse->generic->io.recvcount++;
2370280849Scy					packets_received++;
2371182007Sroberto					add_full_recv_buffer(buf);
2372280849Scy#ifdef HAVE_IO_COMPLETION_PORT
2373280849Scy					SetEvent(WaitableIoEventHandle);
2374280849Scy#endif
2375182007Sroberto				}
237654359Sroberto				parse_iodone(&parse->parseio);
237754359Sroberto			}
237854359Sroberto			else
237954359Sroberto			{
238056746Sroberto				memmove((caddr_t)rbufp->recv_buffer,
238156746Sroberto					(caddr_t)&parse->parseio.parse_dtime,
238256746Sroberto					sizeof(parsetime_t));
238356746Sroberto				parse_iodone(&parse->parseio);
238454359Sroberto				rbufp->recv_length = sizeof(parsetime_t);
238554359Sroberto				return 1; /* got something & in place return */
238654359Sroberto			}
238754359Sroberto		}
238854359Sroberto	}
238954359Sroberto	return 0;		/* nothing to pass up */
239054359Sroberto}
239154359Sroberto
239254359Sroberto/*--------------------------------------------------
239354359Sroberto * local receive
239454359Sroberto */
239554359Srobertostatic void
239654359Srobertolocal_receive(
239754359Sroberto	struct recvbuf *rbufp
239854359Sroberto	)
239954359Sroberto{
2400280849Scy	struct parseunit * parse;
240154359Sroberto	parsetime_t parsetime;
240254359Sroberto
2403280849Scy	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
240454359Sroberto	if (!parse->peer)
240554359Sroberto	    return;
240654359Sroberto
240754359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
240854359Sroberto	{
240954359Sroberto		ERR(ERR_BADIO)
241054359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
241154359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
241254359Sroberto		parse_event(parse, CEVNT_BADREPLY);
241354359Sroberto		return;
241454359Sroberto	}
241554359Sroberto	clear_err(parse, ERR_BADIO);
241654359Sroberto
241754359Sroberto	memmove((caddr_t)&parsetime,
241854359Sroberto		(caddr_t)rbufp->recv_buffer,
241954359Sroberto		sizeof(parsetime_t));
242054359Sroberto
242154359Sroberto#ifdef DEBUG
242254359Sroberto	if (debug > 3)
242354359Sroberto	  {
2424182007Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
242554359Sroberto		   CLK_UNIT(parse->peer),
242654359Sroberto		   (unsigned int)parsetime.parse_status,
242754359Sroberto		   (unsigned int)parsetime.parse_state,
2428182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_ui,
2429182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_uf,
2430182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_ui,
2431182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_uf,
2432182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_ui,
2433182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_uf);
243454359Sroberto	  }
243554359Sroberto#endif
243654359Sroberto
243754359Sroberto	parse_process(parse, &parsetime);
243854359Sroberto}
243954359Sroberto
244054359Sroberto/*--------------------------------------------------
244154359Sroberto * init_iobinding - find and initialize lower layers
244254359Sroberto */
244354359Srobertostatic bind_t *
244454359Srobertoinit_iobinding(
244554359Sroberto	struct parseunit *parse
244654359Sroberto	)
244754359Sroberto{
244854359Sroberto  bind_t *b = io_bindings;
244954359Sroberto
245054359Sroberto	while (b->bd_description != (char *)0)
245154359Sroberto	{
245254359Sroberto		if ((*b->bd_init)(parse))
245354359Sroberto		{
245454359Sroberto			return b;
245554359Sroberto		}
245654359Sroberto		b++;
245754359Sroberto	}
245854359Sroberto	return (bind_t *)0;
245954359Sroberto}
246054359Sroberto
246154359Sroberto/**===========================================================================
246254359Sroberto ** support routines
246354359Sroberto **/
246454359Sroberto
2465280849Scystatic NTP_PRINTF(4, 5) char *
2466280849Scyap(char *buffer, size_t len, char *pos, const char *fmt, ...)
2467280849Scy{
2468280849Scy	va_list va;
2469280849Scy	int l;
2470280849Scy	size_t rem = len - (pos - buffer);
2471280849Scy
2472280849Scy	if (rem == 0)
2473280849Scy		return pos;
2474280849Scy
2475280849Scy	va_start(va, fmt);
2476280849Scy	l = vsnprintf(pos, rem, fmt, va);
2477280849Scy	va_end(va);
2478280849Scy
2479280849Scy	if (l != -1) {
2480280849Scy		rem--;
2481280849Scy		if (rem >= (size_t)l)
2482280849Scy			pos += l;
2483280849Scy		else
2484280849Scy			pos += rem;
2485280849Scy	}
2486280849Scy
2487280849Scy	return pos;
2488280849Scy}
2489280849Scy
249054359Sroberto/*--------------------------------------------------
249154359Sroberto * convert a flag field to a string
249254359Sroberto */
249354359Srobertostatic char *
249454359Srobertoparsestate(
249554359Sroberto	u_long lstate,
2496182007Sroberto	char *buffer,
2497182007Sroberto	int size
249854359Sroberto	)
249954359Sroberto{
250054359Sroberto	static struct bits
250154359Sroberto	{
250254359Sroberto		u_long      bit;
250354359Sroberto		const char *name;
250454359Sroberto	} flagstrings[] =
250554359Sroberto	  {
250656746Sroberto		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
250756746Sroberto		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
250856746Sroberto		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
250956746Sroberto		  { PARSEB_DST,        "DST" },
251056746Sroberto		  { PARSEB_UTC,        "UTC DISPLAY" },
251156746Sroberto		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
251256746Sroberto		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
251354359Sroberto		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
251456746Sroberto		  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
251556746Sroberto		  { PARSEB_TIMECODE,   "TIME CODE" },
251656746Sroberto		  { PARSEB_PPS,        "PPS" },
251756746Sroberto		  { PARSEB_POSITION,   "POSITION" },
2518280849Scy		  { 0,		       NULL }
251954359Sroberto	  };
252054359Sroberto
252154359Sroberto	static struct sbits
252254359Sroberto	{
252354359Sroberto		u_long      bit;
252454359Sroberto		const char *name;
252554359Sroberto	} sflagstrings[] =
252654359Sroberto	  {
252754359Sroberto		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
252854359Sroberto		  { PARSEB_S_PPS,      "PPS SIGNAL" },
252954359Sroberto		  { PARSEB_S_ANTENNA,  "ANTENNA" },
253054359Sroberto		  { PARSEB_S_POSITION, "POSITION" },
2531280849Scy		  { 0,		       NULL }
253254359Sroberto	  };
253354359Sroberto	int i;
2534182007Sroberto	char *s, *t;
253554359Sroberto
253654359Sroberto	*buffer = '\0';
2537182007Sroberto	s = t = buffer;
253854359Sroberto
253954359Sroberto	i = 0;
254054359Sroberto	while (flagstrings[i].bit)
254154359Sroberto	{
254254359Sroberto		if (flagstrings[i].bit & lstate)
254354359Sroberto		{
2544182007Sroberto			if (s != t)
2545280849Scy				t = ap(buffer, size, t, "; ");
2546280849Scy			t = ap(buffer, size, t, "%s", flagstrings[i].name);
254754359Sroberto		}
254854359Sroberto		i++;
254954359Sroberto	}
255054359Sroberto
255154359Sroberto	if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
255254359Sroberto	{
2553182007Sroberto		if (s != t)
2554280849Scy			t = ap(buffer, size, t, "; ");
255554359Sroberto
2556280849Scy		t = ap(buffer, size, t, "(");
255754359Sroberto
2558280849Scy		s = t;
255954359Sroberto
256054359Sroberto		i = 0;
256154359Sroberto		while (sflagstrings[i].bit)
256254359Sroberto		{
256354359Sroberto			if (sflagstrings[i].bit & lstate)
256454359Sroberto			{
256554359Sroberto				if (t != s)
256654359Sroberto				{
2567280849Scy					t = ap(buffer, size, t, "; ");
256854359Sroberto				}
256954359Sroberto
2570280849Scy				t = ap(buffer, size, t, "%s",
2571280849Scy				    sflagstrings[i].name);
257254359Sroberto			}
257354359Sroberto			i++;
257454359Sroberto		}
2575280849Scy		t = ap(buffer, size, t, ")");
257654359Sroberto	}
257754359Sroberto	return buffer;
257854359Sroberto}
257954359Sroberto
258054359Sroberto/*--------------------------------------------------
258154359Sroberto * convert a status flag field to a string
258254359Sroberto */
258354359Srobertostatic char *
258454359Srobertoparsestatus(
258554359Sroberto	u_long lstate,
2586182007Sroberto	char *buffer,
2587182007Sroberto	int size
258854359Sroberto	)
258954359Sroberto{
259054359Sroberto	static struct bits
259154359Sroberto	{
259254359Sroberto		u_long      bit;
259354359Sroberto		const char *name;
259454359Sroberto	} flagstrings[] =
259554359Sroberto	  {
259654359Sroberto		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
259754359Sroberto		  { CVT_NONE,    "NO CONVERSION" },
259854359Sroberto		  { CVT_FAIL,    "CONVERSION FAILED" },
259954359Sroberto		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
260054359Sroberto		  { CVT_BADDATE, "DATE ILLEGAL" },
260154359Sroberto		  { CVT_BADTIME, "TIME ILLEGAL" },
260254359Sroberto		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2603280849Scy		  { 0,		 NULL }
260454359Sroberto	  };
260554359Sroberto	int i;
2606280849Scy	char *t;
260754359Sroberto
2608280849Scy	t = buffer;
260954359Sroberto	*buffer = '\0';
261054359Sroberto
261154359Sroberto	i = 0;
261254359Sroberto	while (flagstrings[i].bit)
261354359Sroberto	{
261454359Sroberto		if (flagstrings[i].bit & lstate)
261554359Sroberto		{
2616280849Scy			if (t != buffer)
2617280849Scy				t = ap(buffer, size, t, "; ");
2618280849Scy			t = ap(buffer, size, t, "%s", flagstrings[i].name);
261954359Sroberto		}
262054359Sroberto		i++;
262154359Sroberto	}
262254359Sroberto
262354359Sroberto	return buffer;
262454359Sroberto}
262554359Sroberto
262654359Sroberto/*--------------------------------------------------
262754359Sroberto * convert a clock status flag field to a string
262854359Sroberto */
262954359Srobertostatic const char *
263054359Srobertoclockstatus(
263154359Sroberto	u_long lstate
263254359Sroberto	)
263354359Sroberto{
263454359Sroberto	static char buffer[20];
263554359Sroberto	static struct status
263654359Sroberto	{
263754359Sroberto		u_long      value;
263854359Sroberto		const char *name;
263954359Sroberto	} flagstrings[] =
264054359Sroberto	  {
264154359Sroberto		  { CEVNT_NOMINAL, "NOMINAL" },
264254359Sroberto		  { CEVNT_TIMEOUT, "NO RESPONSE" },
264354359Sroberto		  { CEVNT_BADREPLY,"BAD FORMAT" },
264454359Sroberto		  { CEVNT_FAULT,   "FAULT" },
264554359Sroberto		  { CEVNT_PROP,    "PROPAGATION DELAY" },
264654359Sroberto		  { CEVNT_BADDATE, "ILLEGAL DATE" },
264754359Sroberto		  { CEVNT_BADTIME, "ILLEGAL TIME" },
2648280849Scy		  { (unsigned)~0L, NULL }
264954359Sroberto	  };
265054359Sroberto	int i;
265154359Sroberto
265254359Sroberto	i = 0;
2653280849Scy	while (flagstrings[i].value != (u_int)~0)
265454359Sroberto	{
265554359Sroberto		if (flagstrings[i].value == lstate)
265654359Sroberto		{
265754359Sroberto			return flagstrings[i].name;
265854359Sroberto		}
265954359Sroberto		i++;
266054359Sroberto	}
266154359Sroberto
2662182007Sroberto	snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
266354359Sroberto
266454359Sroberto	return buffer;
266554359Sroberto}
266654359Sroberto
266754359Sroberto
266854359Sroberto/*--------------------------------------------------
266954359Sroberto * l_mktime - make representation of a relative time
267054359Sroberto */
267154359Srobertostatic char *
267254359Srobertol_mktime(
267354359Sroberto	u_long delta
267454359Sroberto	)
267554359Sroberto{
267654359Sroberto	u_long tmp, m, s;
267754359Sroberto	static char buffer[40];
2678182007Sroberto	char *t;
267954359Sroberto
268054359Sroberto	buffer[0] = '\0';
2681280849Scy	t = buffer;
268254359Sroberto
268354359Sroberto	if ((tmp = delta / (60*60*24)) != 0)
268454359Sroberto	{
2685280849Scy		t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp);
268654359Sroberto		delta -= tmp * 60*60*24;
268754359Sroberto	}
268854359Sroberto
268954359Sroberto	s = delta % 60;
269054359Sroberto	delta /= 60;
269154359Sroberto	m = delta % 60;
269254359Sroberto	delta /= 60;
269354359Sroberto
2694280849Scy	t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
2695280849Scy	     (int)delta, (int)m, (int)s);
269654359Sroberto
269754359Sroberto	return buffer;
269854359Sroberto}
269954359Sroberto
270054359Sroberto
270154359Sroberto/*--------------------------------------------------
270254359Sroberto * parse_statistics - list summary of clock states
270354359Sroberto */
270454359Srobertostatic void
270554359Srobertoparse_statistics(
270654359Sroberto	struct parseunit *parse
270754359Sroberto	)
270854359Sroberto{
270954359Sroberto	int i;
271054359Sroberto
271154359Sroberto	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
271254359Sroberto		{
271354359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
271454359Sroberto				CLK_UNIT(parse->peer),
271554359Sroberto				l_mktime(current_time - parse->generic->timestarted));
271654359Sroberto
271754359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
271854359Sroberto				CLK_UNIT(parse->peer),
271954359Sroberto				clockstatus(parse->generic->currentstatus));
272054359Sroberto
272154359Sroberto			for (i = 0; i <= CEVNT_MAX; i++)
272254359Sroberto			{
272354359Sroberto				u_long s_time;
272454359Sroberto				u_long percent, d = current_time - parse->generic->timestarted;
272554359Sroberto
272654359Sroberto				percent = s_time = PARSE_STATETIME(parse, i);
272754359Sroberto
272854359Sroberto				while (((u_long)(~0) / 10000) < percent)
272954359Sroberto				{
273054359Sroberto					percent /= 10;
273154359Sroberto					d       /= 10;
273254359Sroberto				}
273354359Sroberto
273454359Sroberto				if (d)
273554359Sroberto				    percent = (percent * 10000) / d;
273654359Sroberto				else
273754359Sroberto				    percent = 10000;
273854359Sroberto
273954359Sroberto				if (s_time)
274054359Sroberto				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
274154359Sroberto					    CLK_UNIT(parse->peer),
274254359Sroberto					    clockstatus((unsigned int)i),
274354359Sroberto					    l_mktime(s_time),
274454359Sroberto					    percent / 100, percent % 100);
274554359Sroberto			}
274654359Sroberto		}
274754359Sroberto}
274854359Sroberto
274954359Sroberto/*--------------------------------------------------
275054359Sroberto * cparse_statistics - wrapper for statistics call
275154359Sroberto */
275254359Srobertostatic void
275354359Srobertocparse_statistics(
2754182007Sroberto        struct parseunit *parse
275554359Sroberto	)
275654359Sroberto{
275754359Sroberto	if (parse->laststatistic + PARSESTATISTICS < current_time)
275854359Sroberto		parse_statistics(parse);
275954359Sroberto	parse->laststatistic = current_time;
276054359Sroberto}
276154359Sroberto
276254359Sroberto/**===========================================================================
276354359Sroberto ** ntp interface routines
276454359Sroberto **/
276554359Sroberto
276654359Sroberto/*--------------------------------------------------
276754359Sroberto * parse_shutdown - shut down a PARSE clock
276854359Sroberto */
276954359Srobertostatic void
277054359Srobertoparse_shutdown(
277154359Sroberto	int unit,
277254359Sroberto	struct peer *peer
277354359Sroberto	)
277454359Sroberto{
2775280849Scy	struct parseunit *parse = NULL;
277654359Sroberto
2777182007Sroberto	if (peer && peer->procptr)
2778280849Scy		parse = peer->procptr->unitptr;
2779182007Sroberto
2780182007Sroberto	if (!parse)
278154359Sroberto	{
2782182007Sroberto		/* nothing to clean up */
278354359Sroberto		return;
278454359Sroberto	}
278554359Sroberto
2786280849Scy	if (!parse->peer)
2787182007Sroberto	{
2788182007Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2789182007Sroberto		return;
2790182007Sroberto	}
2791182007Sroberto
2792182007Sroberto#ifdef HAVE_PPSAPI
2793182007Sroberto	if (parse->flags & PARSE_PPSCLOCK)
2794182007Sroberto	{
2795280849Scy		(void)time_pps_destroy(parse->atom.handle);
2796182007Sroberto	}
2797182007Sroberto#endif
2798182007Sroberto	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2799280849Scy		(void)closeserial(parse->ppsfd);  /* close separate PPS source */
2800182007Sroberto
280154359Sroberto	/*
280254359Sroberto	 * print statistics a last time and
280354359Sroberto	 * stop statistics machine
280454359Sroberto	 */
280554359Sroberto	parse_statistics(parse);
280654359Sroberto
280754359Sroberto	if (parse->parse_type->cl_end)
280854359Sroberto	{
280954359Sroberto		parse->parse_type->cl_end(parse);
281054359Sroberto	}
281154359Sroberto
2812182007Sroberto	/*
2813182007Sroberto	 * cleanup before leaving this world
2814182007Sroberto	 */
281554359Sroberto	if (parse->binding)
281654359Sroberto	    PARSE_END(parse);
281754359Sroberto
281854359Sroberto	/*
281954359Sroberto	 * Tell the I/O module to turn us off.  We're history.
282054359Sroberto	 */
282154359Sroberto	io_closeclock(&parse->generic->io);
282254359Sroberto
282354359Sroberto	free_varlist(parse->kv);
282454359Sroberto
282554359Sroberto	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
282654359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
282754359Sroberto			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
282854359Sroberto
282954359Sroberto	parse->peer = (struct peer *)0; /* unused now */
2830182007Sroberto	peer->procptr->unitptr = (caddr_t)0;
283154359Sroberto	free(parse);
283254359Sroberto}
283354359Sroberto
2834182007Sroberto#ifdef HAVE_PPSAPI
2835182007Sroberto/*----------------------------------------
2836182007Sroberto * set up HARDPPS via PPSAPI
2837182007Sroberto */
2838182007Srobertostatic void
2839182007Srobertoparse_hardpps(
2840182007Sroberto	      struct parseunit *parse,
2841182007Sroberto	      int mode
2842182007Sroberto	      )
2843182007Sroberto{
2844182007Sroberto        if (parse->hardppsstate == mode)
2845182007Sroberto	        return;
2846182007Sroberto
2847182007Sroberto	if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2848182007Sroberto		int	i = 0;
2849182007Sroberto
2850182007Sroberto		if (mode == PARSE_HARDPPS_ENABLE)
2851182007Sroberto		        {
2852182007Sroberto			        if (parse->flags & PARSE_CLEAR)
2853182007Sroberto				        i = PPS_CAPTURECLEAR;
2854182007Sroberto				else
2855182007Sroberto				        i = PPS_CAPTUREASSERT;
2856182007Sroberto			}
2857182007Sroberto
2858280849Scy		if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
2859182007Sroberto		    PPS_TSFMT_TSPEC) < 0) {
2860182007Sroberto		        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2861182007Sroberto				CLK_UNIT(parse->peer));
2862182007Sroberto		} else {
2863182007Sroberto		        NLOG(NLOG_CLOCKINFO)
2864182007Sroberto		                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2865182007Sroberto					CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2866182007Sroberto			/*
2867182007Sroberto			 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2868182007Sroberto			 */
2869182007Sroberto			if (mode == PARSE_HARDPPS_ENABLE)
2870280849Scy			        hardpps_enable = 1;
2871182007Sroberto		}
2872182007Sroberto	}
2873182007Sroberto
2874182007Sroberto	parse->hardppsstate = mode;
2875182007Sroberto}
2876182007Sroberto
2877182007Sroberto/*----------------------------------------
2878182007Sroberto * set up PPS via PPSAPI
2879182007Sroberto */
2880182007Srobertostatic int
2881182007Srobertoparse_ppsapi(
2882182007Sroberto	     struct parseunit *parse
2883182007Sroberto	)
2884182007Sroberto{
2885280849Scy	int cap, mode_ppsoffset;
2886280849Scy	const char *cp;
2887182007Sroberto
2888182007Sroberto	parse->flags &= ~PARSE_PPSCLOCK;
2889182007Sroberto
2890280849Scy	/*
2891280849Scy	 * collect PPSAPI offset capability - should move into generic handling
2892280849Scy	 */
2893280849Scy	if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
2894182007Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2895182007Sroberto			CLK_UNIT(parse->peer));
2896182007Sroberto
2897182007Sroberto		return 0;
2898182007Sroberto	}
2899182007Sroberto
2900280849Scy	/*
2901280849Scy	 * initialize generic PPSAPI interface
2902280849Scy	 *
2903280849Scy	 * we leave out CLK_FLAG3 as time_pps_kcbind()
2904280849Scy	 * is handled here for now. Ideally this should also
2905280849Scy	 * be part of the generic PPSAPI interface
2906280849Scy	 */
2907280849Scy	if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
2908182007Sroberto		return 0;
2909182007Sroberto
2910182007Sroberto	/* nb. only turn things on, if someone else has turned something
2911182007Sroberto	 *	on before we get here, leave it alone!
2912182007Sroberto	 */
2913182007Sroberto
2914182007Sroberto	if (parse->flags & PARSE_CLEAR) {
2915182007Sroberto		cp = "CLEAR";
2916280849Scy		mode_ppsoffset = PPS_OFFSETCLEAR;
2917182007Sroberto	} else {
2918182007Sroberto		cp = "ASSERT";
2919280849Scy		mode_ppsoffset = PPS_OFFSETASSERT;
2920182007Sroberto	}
2921182007Sroberto
2922182007Sroberto	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2923182007Sroberto		CLK_UNIT(parse->peer), cp);
2924182007Sroberto
2925280849Scy	if (!(mode_ppsoffset & cap)) {
2926182007Sroberto	  msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2927182007Sroberto		  CLK_UNIT(parse->peer), cp, cap);
2928280849Scy		mode_ppsoffset = 0;
2929182007Sroberto	} else {
2930280849Scy	        if (mode_ppsoffset == PPS_OFFSETCLEAR)
2931182007Sroberto		        {
2932280849Scy			        parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust;
2933280849Scy			        parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2934182007Sroberto			}
2935182007Sroberto
2936280849Scy		if (mode_ppsoffset == PPS_OFFSETASSERT)
2937182007Sroberto	                {
2938280849Scy		                parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust;
2939280849Scy				parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2940182007Sroberto			}
2941182007Sroberto	}
2942182007Sroberto
2943280849Scy	parse->atom.pps_params.mode |= mode_ppsoffset;
2944182007Sroberto
2945280849Scy	if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
2946182007Sroberto	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2947182007Sroberto		  CLK_UNIT(parse->peer));
2948182007Sroberto		return 0;
2949182007Sroberto	}
2950182007Sroberto
2951182007Sroberto	parse->flags |= PARSE_PPSCLOCK;
2952182007Sroberto	return 1;
2953182007Sroberto}
2954182007Sroberto#else
2955182007Sroberto#define parse_hardpps(_PARSE_, _MODE_) /* empty */
2956182007Sroberto#endif
2957182007Sroberto
295854359Sroberto/*--------------------------------------------------
295954359Sroberto * parse_start - open the PARSE devices and initialize data for processing
296054359Sroberto */
296154359Srobertostatic int
296254359Srobertoparse_start(
296354359Sroberto	int sysunit,
296454359Sroberto	struct peer *peer
296554359Sroberto	)
296654359Sroberto{
296754359Sroberto	u_int unit;
296854359Sroberto	int fd232;
296954359Sroberto#ifdef HAVE_TERMIOS
297054359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
297154359Sroberto#endif
297254359Sroberto#ifdef HAVE_SYSV_TTYS
297354359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
297454359Sroberto#endif
297554359Sroberto	struct parseunit * parse;
297654359Sroberto	char parsedev[sizeof(PARSEDEVICE)+20];
2977182007Sroberto	char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
297854359Sroberto	parsectl_t tmp_ctl;
297954359Sroberto	u_int type;
298054359Sroberto
2981182007Sroberto	/*
2982182007Sroberto	 * get out Copyright information once
2983182007Sroberto	 */
2984182007Sroberto	if (!notice)
2985182007Sroberto        {
2986182007Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2987280849Scy			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel");
2988182007Sroberto		notice = 1;
2989182007Sroberto	}
2990182007Sroberto
299154359Sroberto	type = CLK_TYPE(peer);
299254359Sroberto	unit = CLK_UNIT(peer);
299354359Sroberto
2994280849Scy	if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0))
299554359Sroberto	{
299654359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
299754359Sroberto			unit, CLK_REALTYPE(peer), ncltypes-1);
299854359Sroberto		return 0;
299954359Sroberto	}
300054359Sroberto
300154359Sroberto	/*
300254359Sroberto	 * Unit okay, attempt to open the device.
300354359Sroberto	 */
3004182007Sroberto	(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
3005182007Sroberto	(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
300654359Sroberto
300754359Sroberto#ifndef O_NOCTTY
300854359Sroberto#define O_NOCTTY 0
300954359Sroberto#endif
3010280849Scy#ifndef O_NONBLOCK
3011280849Scy#define O_NONBLOCK 0
301254359Sroberto#endif
301354359Sroberto
3014280849Scy	fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3015280849Scy
301654359Sroberto	if (fd232 == -1)
301754359Sroberto	{
301854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
301954359Sroberto		return 0;
302054359Sroberto	}
302154359Sroberto
3022280849Scy	parse = emalloc_zero(sizeof(*parse));
302354359Sroberto
302454359Sroberto	parse->generic = peer->procptr;	 /* link up */
302554359Sroberto	parse->generic->unitptr = (caddr_t)parse; /* link down */
302654359Sroberto
302754359Sroberto	/*
302854359Sroberto	 * Set up the structures
302954359Sroberto	 */
303054359Sroberto	parse->generic->timestarted    = current_time;
303154359Sroberto	parse->lastchange     = current_time;
303254359Sroberto
303354359Sroberto	parse->flags          = 0;
303454359Sroberto	parse->pollneeddata   = 0;
303554359Sroberto	parse->laststatistic  = current_time;
303654359Sroberto	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
3037182007Sroberto	parse->timedata.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
303854359Sroberto	parse->lastmissed     = 0;	/* assume got everything */
303954359Sroberto	parse->ppsserial      = 0;
3040182007Sroberto	parse->ppsfd	      = -1;
304154359Sroberto	parse->localdata      = (void *)0;
304254359Sroberto	parse->localstate     = 0;
304354359Sroberto	parse->kv             = (struct ctl_var *)0;
304454359Sroberto
304554359Sroberto	clear_err(parse, ERR_ALL);
304654359Sroberto
304754359Sroberto	parse->parse_type     = &parse_clockinfo[type];
304854359Sroberto
3049182007Sroberto	parse->maxunsync      = parse->parse_type->cl_maxunsync;
3050182007Sroberto
305154359Sroberto	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
305254359Sroberto
305354359Sroberto	parse->generic->fudgetime2 = 0.0;
3054182007Sroberto	parse->ppsphaseadjust = parse->generic->fudgetime2;
305554359Sroberto
3056182007Sroberto	parse->generic->clockdesc  = parse->parse_type->cl_description;
305754359Sroberto
305854359Sroberto	peer->rootdelay       = parse->parse_type->cl_rootdelay;
305954359Sroberto	peer->sstclktype      = parse->parse_type->cl_type;
306054359Sroberto	peer->precision       = sys_precision;
306154359Sroberto
306254359Sroberto	peer->stratum         = STRATUM_REFCLOCK;
3063182007Sroberto
306454359Sroberto	if (peer->stratum <= 1)
306554359Sroberto	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
306654359Sroberto	else
306754359Sroberto	    parse->generic->refid = htonl(PARSEHSREFID);
306854359Sroberto
306954359Sroberto	parse->generic->io.fd = fd232;
307054359Sroberto
307154359Sroberto	parse->peer = peer;		/* marks it also as busy */
307254359Sroberto
307354359Sroberto	/*
307454359Sroberto	 * configure terminal line
307554359Sroberto	 */
307654359Sroberto	if (TTY_GETATTR(fd232, &tio) == -1)
307754359Sroberto	{
307854359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
307954359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
308054359Sroberto		return 0;
308154359Sroberto	}
308254359Sroberto	else
308354359Sroberto	{
308454359Sroberto#ifndef _PC_VDISABLE
308554359Sroberto		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
308654359Sroberto#else
308754359Sroberto		int disablec;
308854359Sroberto		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
308954359Sroberto
309054359Sroberto		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
309154359Sroberto		if (disablec == -1 && errno)
309254359Sroberto		{
309354359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
309454359Sroberto			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
309554359Sroberto		}
309654359Sroberto		else
309754359Sroberto		    if (disablec != -1)
309854359Sroberto			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
309954359Sroberto#endif
310054359Sroberto
310154359Sroberto#if defined (VMIN) || defined(VTIME)
310254359Sroberto		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
310354359Sroberto		{
310454359Sroberto#ifdef VMIN
310554359Sroberto			tio.c_cc[VMIN]   = 1;
310654359Sroberto#endif
310754359Sroberto#ifdef VTIME
310854359Sroberto			tio.c_cc[VTIME]  = 0;
310954359Sroberto#endif
311054359Sroberto		}
311154359Sroberto#endif
311254359Sroberto
311354359Sroberto		tio.c_cflag = parse_clockinfo[type].cl_cflag;
311454359Sroberto		tio.c_iflag = parse_clockinfo[type].cl_iflag;
311554359Sroberto		tio.c_oflag = parse_clockinfo[type].cl_oflag;
311654359Sroberto		tio.c_lflag = parse_clockinfo[type].cl_lflag;
311754359Sroberto
311854359Sroberto
311954359Sroberto#ifdef HAVE_TERMIOS
312054359Sroberto		if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
312154359Sroberto		    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
312254359Sroberto		{
312354359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
312454359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
312554359Sroberto			return 0;
312654359Sroberto		}
312754359Sroberto#else
312854359Sroberto		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
312954359Sroberto#endif
313054359Sroberto
3131182007Sroberto		/*
3132182007Sroberto		 * set up pps device
3133182007Sroberto		 * if the PARSEPPSDEVICE can be opened that will be used
3134182007Sroberto		 * for PPS else PARSEDEVICE will be used
3135182007Sroberto		 */
3136280849Scy		parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3137182007Sroberto
3138182007Sroberto		if (parse->ppsfd == -1)
3139182007Sroberto		{
3140182007Sroberto			parse->ppsfd = fd232;
3141182007Sroberto		}
3142182007Sroberto
3143182007Sroberto/*
3144182007Sroberto * Linux PPS - the old way
3145182007Sroberto */
314654359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
314754359Sroberto		{
3148182007Sroberto			struct serial_struct	ss;
3149182007Sroberto			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
3150182007Sroberto			    (
315154359Sroberto#ifdef ASYNC_LOW_LATENCY
3152182007Sroberto			     ss.flags |= ASYNC_LOW_LATENCY,
315354359Sroberto#endif
3154182007Sroberto#ifndef HAVE_PPSAPI
315554359Sroberto#ifdef ASYNC_PPS_CD_NEG
3156182007Sroberto			     ss.flags |= ASYNC_PPS_CD_NEG,
315754359Sroberto#endif
3158182007Sroberto#endif
3159182007Sroberto			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3160182007Sroberto				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3161182007Sroberto				msyslog(LOG_NOTICE,
3162182007Sroberto					"refclock_parse: optional PPS processing not available");
3163182007Sroberto			} else {
3164182007Sroberto				parse->flags    |= PARSE_PPSCLOCK;
3165182007Sroberto#ifdef ASYNC_PPS_CD_NEG
3166182007Sroberto				NLOG(NLOG_CLOCKINFO)
3167182007Sroberto				  msyslog(LOG_INFO,
3168182007Sroberto					  "refclock_parse: PPS detection on");
3169182007Sroberto#endif
3170182007Sroberto			}
317154359Sroberto		}
317254359Sroberto#endif
3173182007Sroberto
3174182007Sroberto/*
3175182007Sroberto * SUN the Solaris way
3176182007Sroberto */
317754359Sroberto#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
317854359Sroberto		if (CLK_PPS(parse->peer))
3179182007Sroberto		    {
3180182007Sroberto			int i = 1;
318154359Sroberto
3182182007Sroberto			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3183182007Sroberto			    {
3184182007Sroberto				parse->flags |= PARSE_PPSCLOCK;
3185182007Sroberto			    }
3186182007Sroberto		    }
318754359Sroberto#endif
318854359Sroberto
3189182007Sroberto/*
3190182007Sroberto * PPS via PPSAPI
3191182007Sroberto */
3192182007Sroberto#if defined(HAVE_PPSAPI)
3193182007Sroberto		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3194182007Sroberto		if (CLK_PPS(parse->peer))
3195182007Sroberto		{
3196280849Scy		  if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3197182007Sroberto		    {
3198182007Sroberto		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3199182007Sroberto		    }
3200182007Sroberto		  else
3201182007Sroberto		    {
3202182007Sroberto		      parse_ppsapi(parse);
3203182007Sroberto		    }
3204182007Sroberto		}
3205182007Sroberto#endif
3206182007Sroberto
320754359Sroberto		if (TTY_SETATTR(fd232, &tio) == -1)
320854359Sroberto		{
320954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
321054359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
321154359Sroberto			return 0;
321254359Sroberto		}
321354359Sroberto	}
321454359Sroberto
321554359Sroberto	/*
3216182007Sroberto	 * pick correct input machine
321754359Sroberto	 */
3218280849Scy	parse->generic->io.srcclock = peer;
321954359Sroberto	parse->generic->io.datalen = 0;
322054359Sroberto
322154359Sroberto	parse->binding = init_iobinding(parse);
322254359Sroberto
322354359Sroberto	if (parse->binding == (bind_t *)0)
322454359Sroberto		{
322554359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
322654359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
322754359Sroberto			return 0;			/* well, ok - special initialisation broke */
3228280849Scy		}
322954359Sroberto
3230182007Sroberto	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3231182007Sroberto	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3232182007Sroberto
323354359Sroberto	/*
323454359Sroberto	 * as we always(?) get 8 bit chars we want to be
323554359Sroberto	 * sure, that the upper bits are zero for less
323654359Sroberto	 * than 8 bit I/O - so we pass that information on.
323754359Sroberto	 * note that there can be only one bit count format
323854359Sroberto	 * per file descriptor
323954359Sroberto	 */
324054359Sroberto
324154359Sroberto	switch (tio.c_cflag & CSIZE)
324254359Sroberto	{
324354359Sroberto	    case CS5:
324454359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
324554359Sroberto		break;
324654359Sroberto
324754359Sroberto	    case CS6:
324854359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
324954359Sroberto		break;
325054359Sroberto
325154359Sroberto	    case CS7:
325254359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
325354359Sroberto		break;
325454359Sroberto
325554359Sroberto	    case CS8:
325654359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
325754359Sroberto		break;
325854359Sroberto	}
325954359Sroberto
326054359Sroberto	if (!PARSE_SETCS(parse, &tmp_ctl))
326154359Sroberto	{
326254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
326354359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
326454359Sroberto		return 0;			/* well, ok - special initialisation broke */
326554359Sroberto	}
326654359Sroberto
3267280849Scy	strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
326854359Sroberto	tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
326954359Sroberto
327054359Sroberto	if (!PARSE_SETFMT(parse, &tmp_ctl))
327154359Sroberto	{
327254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
327354359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
327454359Sroberto		return 0;			/* well, ok - special initialisation broke */
327554359Sroberto	}
327654359Sroberto
327754359Sroberto	/*
327854359Sroberto	 * get rid of all IO accumulated so far
327954359Sroberto	 */
328054359Sroberto#ifdef HAVE_TERMIOS
328154359Sroberto	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
328254359Sroberto#else
3283182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH)
328454359Sroberto	{
328554359Sroberto		int flshcmd = TCIOFLUSH;
328654359Sroberto
328754359Sroberto		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
328854359Sroberto	}
328954359Sroberto#endif
329054359Sroberto#endif
329156746Sroberto
329254359Sroberto	/*
329354359Sroberto	 * try to do any special initializations
329454359Sroberto	 */
329554359Sroberto	if (parse->parse_type->cl_init)
329654359Sroberto		{
329754359Sroberto			if (parse->parse_type->cl_init(parse))
329854359Sroberto				{
329954359Sroberto					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
330054359Sroberto					return 0;		/* well, ok - special initialisation broke */
330154359Sroberto				}
330254359Sroberto		}
330354359Sroberto
330454359Sroberto	/*
3305182007Sroberto	 * Insert in async io device list.
330654359Sroberto	 */
3307182007Sroberto	if (!io_addclock(&parse->generic->io))
330854359Sroberto        {
3309182007Sroberto		msyslog(LOG_ERR,
3310182007Sroberto			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3311182007Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3312182007Sroberto		return 0;
331354359Sroberto	}
331454359Sroberto
331554359Sroberto	/*
331654359Sroberto	 * print out configuration
331754359Sroberto	 */
331854359Sroberto	NLOG(NLOG_CLOCKINFO)
331954359Sroberto		{
332054359Sroberto			/* conditional if clause for conditional syslog */
3321182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
332254359Sroberto				CLK_UNIT(parse->peer),
3323182007Sroberto				parse->parse_type->cl_description, parsedev,
3324182007Sroberto				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
332554359Sroberto
3326182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
332754359Sroberto				CLK_UNIT(parse->peer),
3328182007Sroberto				parse->peer->stratum,
3329182007Sroberto				l_mktime(parse->maxunsync), parse->peer->precision);
333054359Sroberto
3331182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
333254359Sroberto				CLK_UNIT(parse->peer),
333354359Sroberto				parse->parse_type->cl_rootdelay,
333454359Sroberto				parse->generic->fudgetime1,
3335182007Sroberto				parse->ppsphaseadjust,
3336182007Sroberto                                parse->binding->bd_description);
333754359Sroberto
3338182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
333954359Sroberto				parse->parse_type->cl_format);
3340182007Sroberto                        msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3341182007Sroberto				CLK_PPS(parse->peer) ? "" : "NO ",
3342182007Sroberto				CLK_PPS(parse->peer) ?
3343182007Sroberto#ifdef PPS_METHOD
3344182007Sroberto				" (implementation " PPS_METHOD ")"
3345182007Sroberto#else
3346182007Sroberto				""
334754359Sroberto#endif
3348182007Sroberto				: ""
3349182007Sroberto				);
335054359Sroberto		}
335154359Sroberto
335254359Sroberto	return 1;
335354359Sroberto}
335454359Sroberto
335554359Sroberto/*--------------------------------------------------
3356182007Sroberto * parse_ctl - process changes on flags/time values
3357182007Sroberto */
3358182007Srobertostatic void
3359182007Srobertoparse_ctl(
3360182007Sroberto	    struct parseunit *parse,
3361280849Scy	    const struct refclockstat *in
3362182007Sroberto	    )
3363182007Sroberto{
3364182007Sroberto        if (in)
3365182007Sroberto	{
3366182007Sroberto		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3367182007Sroberto		{
3368182007Sroberto		  parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3369182007Sroberto		    (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3370182007Sroberto#if defined(HAVE_PPSAPI)
3371182007Sroberto		  if (CLK_PPS(parse->peer))
3372182007Sroberto		    {
3373182007Sroberto		      parse_ppsapi(parse);
3374182007Sroberto		    }
3375182007Sroberto#endif
3376182007Sroberto		}
3377182007Sroberto
3378182007Sroberto		if (in->haveflags & CLK_HAVETIME1)
3379182007Sroberto                {
3380182007Sroberto		  parse->generic->fudgetime1 = in->fudgetime1;
3381182007Sroberto		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3382182007Sroberto			  CLK_UNIT(parse->peer),
3383182007Sroberto			  parse->generic->fudgetime1);
3384182007Sroberto		}
3385182007Sroberto
3386182007Sroberto		if (in->haveflags & CLK_HAVETIME2)
3387182007Sroberto                {
3388182007Sroberto		  parse->generic->fudgetime2 = in->fudgetime2;
3389182007Sroberto		  if (parse->flags & PARSE_TRUSTTIME)
3390182007Sroberto		    {
3391182007Sroberto		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3392182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3393182007Sroberto			      CLK_UNIT(parse->peer),
3394182007Sroberto			      l_mktime(parse->maxunsync));
3395182007Sroberto		    }
3396182007Sroberto		  else
3397182007Sroberto		    {
3398182007Sroberto		      parse->ppsphaseadjust = in->fudgetime2;
3399182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3400182007Sroberto			  CLK_UNIT(parse->peer),
3401182007Sroberto			      parse->ppsphaseadjust);
3402182007Sroberto#if defined(HAVE_PPSAPI)
3403182007Sroberto		      if (CLK_PPS(parse->peer))
3404182007Sroberto		      {
3405182007Sroberto			      parse_ppsapi(parse);
3406182007Sroberto		      }
3407182007Sroberto#endif
3408182007Sroberto		    }
3409182007Sroberto		}
3410182007Sroberto	}
3411182007Sroberto}
3412182007Sroberto
3413182007Sroberto/*--------------------------------------------------
341454359Sroberto * parse_poll - called by the transmit procedure
341554359Sroberto */
341654359Srobertostatic void
341754359Srobertoparse_poll(
341854359Sroberto	int unit,
341954359Sroberto	struct peer *peer
342054359Sroberto	)
342154359Sroberto{
3422280849Scy	struct parseunit *parse = peer->procptr->unitptr;
342354359Sroberto
342454359Sroberto	if (peer != parse->peer)
342554359Sroberto	{
342654359Sroberto		msyslog(LOG_ERR,
342754359Sroberto			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
342854359Sroberto			unit);
342954359Sroberto		return;
343054359Sroberto	}
343154359Sroberto
343254359Sroberto	/*
343354359Sroberto	 * Update clock stat counters
343454359Sroberto	 */
343554359Sroberto	parse->generic->polls++;
343654359Sroberto
343756746Sroberto	if (parse->pollneeddata &&
3438280849Scy	    ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
343954359Sroberto	{
344054359Sroberto		/*
344156746Sroberto		 * start worrying when exceeding a poll inteval
344254359Sroberto		 * bad news - didn't get a response last time
344354359Sroberto		 */
344454359Sroberto		parse->lastmissed = current_time;
344554359Sroberto		parse_event(parse, CEVNT_TIMEOUT);
344654359Sroberto
344754359Sroberto		ERR(ERR_NODATA)
3448182007Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
344954359Sroberto	}
345054359Sroberto
345154359Sroberto	/*
345254359Sroberto	 * we just mark that we want the next sample for the clock filter
345354359Sroberto	 */
345456746Sroberto	parse->pollneeddata = current_time;
345554359Sroberto
345654359Sroberto	if (parse->parse_type->cl_poll)
345754359Sroberto	{
345854359Sroberto		parse->parse_type->cl_poll(parse);
345954359Sroberto	}
346054359Sroberto
346154359Sroberto	cparse_statistics(parse);
346254359Sroberto
346354359Sroberto	return;
346454359Sroberto}
346554359Sroberto
346654359Sroberto#define LEN_STATES 300		/* length of state string */
346754359Sroberto
346854359Sroberto/*--------------------------------------------------
346954359Sroberto * parse_control - set fudge factors, return statistics
347054359Sroberto */
347154359Srobertostatic void
347254359Srobertoparse_control(
347354359Sroberto	int unit,
3474280849Scy	const struct refclockstat *in,
347554359Sroberto	struct refclockstat *out,
347654359Sroberto	struct peer *peer
347754359Sroberto	)
347854359Sroberto{
3479280849Scy	struct parseunit *parse = peer->procptr->unitptr;
348054359Sroberto	parsectl_t tmpctl;
348154359Sroberto
348254359Sroberto	static char outstatus[400];	/* status output buffer */
348354359Sroberto
348454359Sroberto	if (out)
348554359Sroberto	{
348654359Sroberto		out->lencode       = 0;
348754359Sroberto		out->p_lastcode    = 0;
348854359Sroberto		out->kv_list       = (struct ctl_var *)0;
348954359Sroberto	}
349054359Sroberto
349154359Sroberto	if (!parse || !parse->peer)
349254359Sroberto	{
349354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
349454359Sroberto			unit);
349554359Sroberto		return;
349654359Sroberto	}
349754359Sroberto
349854359Sroberto	unit = CLK_UNIT(parse->peer);
349954359Sroberto
3500182007Sroberto	/*
3501182007Sroberto	 * handle changes
3502182007Sroberto	 */
3503182007Sroberto	parse_ctl(parse, in);
3504182007Sroberto
3505182007Sroberto	/*
3506182007Sroberto	 * supply data
3507182007Sroberto	 */
350854359Sroberto	if (out)
350954359Sroberto	{
351054359Sroberto		u_long sum = 0;
3511182007Sroberto		char *tt, *start;
351254359Sroberto		int i;
351354359Sroberto
351454359Sroberto		outstatus[0] = '\0';
351554359Sroberto
351654359Sroberto		out->type       = REFCLK_PARSE;
351754359Sroberto
351854359Sroberto		/*
3519182007Sroberto		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3520182007Sroberto		 */
3521182007Sroberto		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3522182007Sroberto
3523182007Sroberto		/*
352454359Sroberto		 * figure out skew between PPS and RS232 - just for informational
3525182007Sroberto		 * purposes
352654359Sroberto		 */
3527182007Sroberto		if (PARSE_SYNC(parse->timedata.parse_state))
352854359Sroberto		{
3529182007Sroberto			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
353054359Sroberto			{
353154359Sroberto				l_fp off;
353254359Sroberto
353354359Sroberto				/*
353454359Sroberto				 * we have a PPS and RS232 signal - calculate the skew
353554359Sroberto				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
353654359Sroberto				 */
3537182007Sroberto				off = parse->timedata.parse_stime.fp;
3538182007Sroberto				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
353954359Sroberto				tt = add_var(&out->kv_list, 80, RO);
3540182007Sroberto				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
354154359Sroberto			}
354254359Sroberto		}
354354359Sroberto
3544182007Sroberto		if (PARSE_PPS(parse->timedata.parse_state))
354554359Sroberto		{
354654359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
3547182007Sroberto			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
354854359Sroberto		}
354954359Sroberto
3550182007Sroberto		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3551280849Scy		tt = ap(start, 128, tt, "refclock_time=\"");
355254359Sroberto
3553182007Sroberto		if (parse->timedata.parse_time.fp.l_ui == 0)
355454359Sroberto		{
3555280849Scy			tt = ap(start, 128, tt, "<UNDEFINED>\"");
355654359Sroberto		}
355754359Sroberto		else
355854359Sroberto		{
3559280849Scy			tt = ap(start, 128, tt, "%s\"",
3560280849Scy			    gmprettydate(&parse->timedata.parse_time.fp));
356154359Sroberto		}
356254359Sroberto
356354359Sroberto		if (!PARSE_GETTIMECODE(parse, &tmpctl))
356454359Sroberto		{
356554359Sroberto			ERR(ERR_INTERNAL)
356654359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
356754359Sroberto		}
356854359Sroberto		else
356954359Sroberto		{
3570182007Sroberto			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3571280849Scy			tt = ap(start, 512, tt, "refclock_status=\"");
357254359Sroberto
357354359Sroberto			/*
357454359Sroberto			 * copy PPS flags from last read transaction (informational only)
357554359Sroberto			 */
3576182007Sroberto			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
357754359Sroberto				(PARSEB_PPS|PARSEB_S_PPS);
357854359Sroberto
3579280849Scy			(void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
358054359Sroberto
3581280849Scy			tt += strlen(tt);
358254359Sroberto
3583280849Scy			tt = ap(start, 512, tt, "\"");
3584280849Scy
358554359Sroberto			if (tmpctl.parsegettc.parse_count)
358654359Sroberto			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3587182007Sroberto				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
358854359Sroberto
358954359Sroberto		}
359054359Sroberto
359154359Sroberto		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
359254359Sroberto
359354359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
359454359Sroberto		{
359554359Sroberto			ERR(ERR_INTERNAL)
359654359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
359754359Sroberto		}
359854359Sroberto		else
359954359Sroberto		{
3600280849Scy			int count = tmpctl.parseformat.parse_count - 1;
360154359Sroberto
3602280849Scy			start = tt = add_var(&out->kv_list, 80, RO|DEF);
3603280849Scy			tt = ap(start, 80, tt, "refclock_format=\"");
3604280849Scy
3605280849Scy			if (count > 0) {
3606280849Scy				tt = ap(start, 80, tt, "%*.*s",
3607280849Scy			        	count,
3608280849Scy			        	count,
3609280849Scy			        	tmpctl.parseformat.parse_buffer);
3610280849Scy			}
3611280849Scy
3612280849Scy			tt = ap(start, 80, tt, "\"");
361354359Sroberto		}
361454359Sroberto
361554359Sroberto		/*
361654359Sroberto		 * gather state statistics
361754359Sroberto		 */
361854359Sroberto
361954359Sroberto		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3620280849Scy		tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
362154359Sroberto
362254359Sroberto		for (i = 0; i <= CEVNT_MAX; i++)
362354359Sroberto		{
362454359Sroberto			u_long s_time;
362554359Sroberto			u_long d = current_time - parse->generic->timestarted;
362654359Sroberto			u_long percent;
362754359Sroberto
362854359Sroberto			percent = s_time = PARSE_STATETIME(parse, i);
362954359Sroberto
363054359Sroberto			while (((u_long)(~0) / 10000) < percent)
363154359Sroberto			{
363254359Sroberto				percent /= 10;
363354359Sroberto				d       /= 10;
363454359Sroberto			}
363554359Sroberto
363654359Sroberto			if (d)
363754359Sroberto			    percent = (percent * 10000) / d;
363854359Sroberto			else
363954359Sroberto			    percent = 10000;
364054359Sroberto
364154359Sroberto			if (s_time)
364254359Sroberto			{
364354359Sroberto				char item[80];
364454359Sroberto				int count;
364554359Sroberto
3646182007Sroberto				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
364754359Sroberto					sum ? "; " : "",
364854359Sroberto					(parse->generic->currentstatus == i) ? "*" : "",
364954359Sroberto					clockstatus((unsigned int)i),
365054359Sroberto					l_mktime(s_time),
365154359Sroberto					(int)(percent / 100), (int)(percent % 100));
365254359Sroberto				if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
365354359Sroberto					{
3654280849Scy						tt = ap(start, LEN_STATES, tt,
3655280849Scy						    "%s", item);
365654359Sroberto					}
365754359Sroberto				sum += s_time;
365854359Sroberto			}
365954359Sroberto		}
366054359Sroberto
3661280849Scy		tt = ap(start, LEN_STATES, tt,
3662280849Scy		    "; running time: %s\"", l_mktime(sum));
366354359Sroberto
366454359Sroberto		tt = add_var(&out->kv_list, 32, RO);
3665182007Sroberto		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
366654359Sroberto
366754359Sroberto		tt = add_var(&out->kv_list, 80, RO);
3668182007Sroberto		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
366954359Sroberto
367054359Sroberto		tt = add_var(&out->kv_list, 128, RO);
3671182007Sroberto		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
367254359Sroberto
367354359Sroberto		{
367454359Sroberto			struct ctl_var *k;
367554359Sroberto
367654359Sroberto			k = parse->kv;
367754359Sroberto			while (k && !(k->flags & EOV))
367854359Sroberto			{
367954359Sroberto				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
368054359Sroberto				k++;
368154359Sroberto			}
368254359Sroberto		}
368354359Sroberto
368454359Sroberto		out->lencode       = strlen(outstatus);
368554359Sroberto		out->p_lastcode    = outstatus;
368654359Sroberto	}
368754359Sroberto}
368854359Sroberto
368954359Sroberto/**===========================================================================
369054359Sroberto ** processing routines
369154359Sroberto **/
369254359Sroberto
369354359Sroberto/*--------------------------------------------------
369454359Sroberto * event handling - note that nominal events will also be posted
3695182007Sroberto * keep track of state dwelling times
369654359Sroberto */
369754359Srobertostatic void
369854359Srobertoparse_event(
369954359Sroberto	struct parseunit *parse,
370054359Sroberto	int event
370154359Sroberto	)
370254359Sroberto{
370354359Sroberto	if (parse->generic->currentstatus != (u_char) event)
370454359Sroberto	{
370554359Sroberto		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
370654359Sroberto		parse->lastchange              = current_time;
370754359Sroberto
370854359Sroberto		if (parse->parse_type->cl_event)
370954359Sroberto		    parse->parse_type->cl_event(parse, event);
3710280849Scy
3711182007Sroberto		if (event == CEVNT_NOMINAL)
371254359Sroberto		{
371354359Sroberto			NLOG(NLOG_CLOCKSTATUS)
371454359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
371554359Sroberto					CLK_UNIT(parse->peer));
371654359Sroberto		}
371754359Sroberto
3718182007Sroberto		refclock_report(parse->peer, event);
371954359Sroberto	}
372054359Sroberto}
372154359Sroberto
372254359Sroberto/*--------------------------------------------------
372354359Sroberto * process a PARSE time sample
372454359Sroberto */
372554359Srobertostatic void
372654359Srobertoparse_process(
372754359Sroberto	struct parseunit *parse,
372854359Sroberto	parsetime_t      *parsetime
372954359Sroberto	)
373054359Sroberto{
373154359Sroberto	l_fp off, rectime, reftime;
373254359Sroberto	double fudge;
373354359Sroberto
3734280849Scy	/* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */
3735280849Scy	ZERO(off);
3736280849Scy
373754359Sroberto	/*
373854359Sroberto	 * check for changes in conversion status
373954359Sroberto	 * (only one for each new status !)
374054359Sroberto	 */
374154359Sroberto	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
374254359Sroberto	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3743182007Sroberto	    (parse->timedata.parse_status != parsetime->parse_status))
374454359Sroberto	{
374554359Sroberto		char buffer[400];
374654359Sroberto
374754359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
374854359Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3749182007Sroberto				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
375054359Sroberto
375154359Sroberto		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
375254359Sroberto		{
375354359Sroberto			/*
375454359Sroberto			 * tell more about the story - list time code
375554359Sroberto			 * there is a slight change for a race condition and
375654359Sroberto			 * the time code might be overwritten by the next packet
375754359Sroberto			 */
375854359Sroberto			parsectl_t tmpctl;
375954359Sroberto
376054359Sroberto			if (!PARSE_GETTIMECODE(parse, &tmpctl))
376154359Sroberto			{
376254359Sroberto				ERR(ERR_INTERNAL)
376354359Sroberto					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
376454359Sroberto			}
376554359Sroberto			else
376654359Sroberto			{
376754359Sroberto				ERR(ERR_BADDATA)
3768182007Sroberto					msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
376954359Sroberto						CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
377054359Sroberto			}
377154359Sroberto		}
377254359Sroberto	}
377354359Sroberto
377454359Sroberto	/*
377554359Sroberto	 * examine status and post appropriate events
377654359Sroberto	 */
377754359Sroberto	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
377854359Sroberto	{
377954359Sroberto		/*
378054359Sroberto		 * got bad data - tell the rest of the system
378154359Sroberto		 */
378254359Sroberto		switch (parsetime->parse_status & CVT_MASK)
378354359Sroberto		{
378454359Sroberto		case CVT_NONE:
378554359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
378654359Sroberto			    parse->parse_type->cl_message)
378754359Sroberto				parse->parse_type->cl_message(parse, parsetime);
3788182007Sroberto			/*
3789182007Sroberto			 * save PPS information that comes piggyback
3790182007Sroberto			 */
3791182007Sroberto			if (PARSE_PPS(parsetime->parse_state))
3792182007Sroberto			  {
3793182007Sroberto			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3794182007Sroberto			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3795182007Sroberto			  }
379654359Sroberto			break; 		/* well, still waiting - timeout is handled at higher levels */
379754359Sroberto
379854359Sroberto		case CVT_FAIL:
379954359Sroberto			if (parsetime->parse_status & CVT_BADFMT)
380054359Sroberto			{
380154359Sroberto				parse_event(parse, CEVNT_BADREPLY);
380254359Sroberto			}
380354359Sroberto			else
380454359Sroberto				if (parsetime->parse_status & CVT_BADDATE)
380554359Sroberto				{
380654359Sroberto					parse_event(parse, CEVNT_BADDATE);
380754359Sroberto				}
380854359Sroberto				else
380954359Sroberto					if (parsetime->parse_status & CVT_BADTIME)
381054359Sroberto					{
381154359Sroberto						parse_event(parse, CEVNT_BADTIME);
381254359Sroberto					}
381354359Sroberto					else
381454359Sroberto					{
381554359Sroberto						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
381654359Sroberto					}
381754359Sroberto		}
381854359Sroberto		return;			/* skip the rest - useless */
381954359Sroberto	}
382054359Sroberto
382154359Sroberto	/*
382254359Sroberto	 * check for format changes
382354359Sroberto	 * (in case somebody has swapped clocks 8-)
382454359Sroberto	 */
382554359Sroberto	if (parse->lastformat != parsetime->parse_format)
382654359Sroberto	{
382754359Sroberto		parsectl_t tmpctl;
382854359Sroberto
382954359Sroberto		tmpctl.parseformat.parse_format = parsetime->parse_format;
383054359Sroberto
383154359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
383254359Sroberto		{
383354359Sroberto			ERR(ERR_INTERNAL)
383454359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
383554359Sroberto		}
383654359Sroberto		else
383754359Sroberto		{
383854359Sroberto			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
383954359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
384054359Sroberto					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
384154359Sroberto		}
384254359Sroberto		parse->lastformat = parsetime->parse_format;
384354359Sroberto	}
384454359Sroberto
384554359Sroberto	/*
384654359Sroberto	 * now, any changes ?
384754359Sroberto	 */
3848182007Sroberto	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3849182007Sroberto	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
385054359Sroberto	{
385154359Sroberto		char tmp1[200];
385254359Sroberto		char tmp2[200];
385354359Sroberto		/*
3854182007Sroberto		 * something happend - except for PPS events
385554359Sroberto		 */
385654359Sroberto
3857182007Sroberto		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3858182007Sroberto		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
385954359Sroberto
386054359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
386154359Sroberto			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
386254359Sroberto				CLK_UNIT(parse->peer), tmp2, tmp1);
386354359Sroberto	}
386454359Sroberto
386554359Sroberto	/*
3866182007Sroberto	 * carry on PPS information if still usable
3867182007Sroberto	 */
3868182007Sroberto	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3869182007Sroberto        {
3870182007Sroberto	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3871182007Sroberto		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3872182007Sroberto	}
3873182007Sroberto
3874182007Sroberto	/*
387554359Sroberto	 * remember for future
387654359Sroberto	 */
3877182007Sroberto	parse->timedata = *parsetime;
387854359Sroberto
387954359Sroberto	/*
388054359Sroberto	 * check to see, whether the clock did a complete powerup or lost PZF signal
388154359Sroberto	 * and post correct events for current condition
388254359Sroberto	 */
388354359Sroberto	if (PARSE_POWERUP(parsetime->parse_state))
388454359Sroberto	{
388554359Sroberto		/*
388654359Sroberto		 * this is bad, as we have completely lost synchronisation
388754359Sroberto		 * well this is a problem with the receiver here
388854359Sroberto		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
388954359Sroberto		 * is true as it is the powerup state and the time is taken
389054359Sroberto		 * from a crude real time clock chip
3891280849Scy		 * for the PZF/GPS series this is only partly true, as
389254359Sroberto		 * PARSE_POWERUP only means that the pseudo random
389354359Sroberto		 * phase shift sequence cannot be found. this is only
389454359Sroberto		 * bad, if we have never seen the clock in the SYNC
389554359Sroberto		 * state, where the PHASE and EPOCH are correct.
389654359Sroberto		 * for reporting events the above business does not
389754359Sroberto		 * really matter, but we can use the time code
389854359Sroberto		 * even in the POWERUP state after having seen
389954359Sroberto		 * the clock in the synchronized state (PZF class
390054359Sroberto		 * receivers) unless we have had a telegram disruption
390154359Sroberto		 * after having seen the clock in the SYNC state. we
390254359Sroberto		 * thus require having seen the clock in SYNC state
390354359Sroberto		 * *after* having missed telegrams (noresponse) from
390454359Sroberto		 * the clock. one problem remains: we might use erroneously
390554359Sroberto		 * POWERUP data if the disruption is shorter than 1 polling
390654359Sroberto		 * interval. fortunately powerdowns last usually longer than 64
390754359Sroberto		 * seconds and the receiver is at least 2 minutes in the
390854359Sroberto		 * POWERUP or NOSYNC state before switching to SYNC
3909280849Scy		 * for GPS receivers this can mean antenna problems and other causes.
3910280849Scy		 * the additional grace period can be enables by a clock
3911280849Scy		 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
391254359Sroberto		 */
391354359Sroberto		parse_event(parse, CEVNT_FAULT);
391454359Sroberto		NLOG(NLOG_CLOCKSTATUS)
391554359Sroberto			ERR(ERR_BADSTATUS)
3916280849Scy			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
391754359Sroberto				CLK_UNIT(parse->peer));
391854359Sroberto	}
391954359Sroberto	else
392054359Sroberto	{
392154359Sroberto		/*
392254359Sroberto		 * we have two states left
392354359Sroberto		 *
392454359Sroberto		 * SYNC:
392554359Sroberto		 *  this state means that the EPOCH (timecode) and PHASE
392654359Sroberto		 *  information has be read correctly (at least two
392754359Sroberto		 *  successive PARSE timecodes were received correctly)
392854359Sroberto		 *  this is the best possible state - full trust
392954359Sroberto		 *
393054359Sroberto		 * NOSYNC:
393154359Sroberto		 *  The clock should be on phase with respect to the second
393254359Sroberto		 *  signal, but the timecode has not been received correctly within
393354359Sroberto		 *  at least the last two minutes. this is a sort of half baked state
393454359Sroberto		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
393554359Sroberto		 *  without timecode confirmation)
393654359Sroberto		 *  PZF 535 has also no time confirmation, but the phase should be
393754359Sroberto		 *  very precise as the PZF signal can be decoded
393854359Sroberto		 */
393954359Sroberto
394054359Sroberto		if (PARSE_SYNC(parsetime->parse_state))
394154359Sroberto		{
394254359Sroberto			/*
394354359Sroberto			 * currently completely synchronized - best possible state
394454359Sroberto			 */
394554359Sroberto			parse->lastsync = current_time;
394654359Sroberto			clear_err(parse, ERR_BADSTATUS);
394754359Sroberto		}
394854359Sroberto		else
394954359Sroberto		{
395054359Sroberto			/*
395154359Sroberto			 * we have had some problems receiving the time code
395254359Sroberto			 */
395354359Sroberto			parse_event(parse, CEVNT_PROP);
395454359Sroberto			NLOG(NLOG_CLOCKSTATUS)
395554359Sroberto				ERR(ERR_BADSTATUS)
395654359Sroberto				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
395754359Sroberto					CLK_UNIT(parse->peer));
395854359Sroberto		}
395954359Sroberto	}
396054359Sroberto
396154359Sroberto	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
396254359Sroberto
396354359Sroberto	if (PARSE_TIMECODE(parsetime->parse_state))
396454359Sroberto	{
396554359Sroberto		rectime = parsetime->parse_stime.fp;
396654359Sroberto		off = reftime = parsetime->parse_time.fp;
396754359Sroberto
396854359Sroberto		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
396954359Sroberto
397054359Sroberto#ifdef DEBUG
397154359Sroberto		if (debug > 3)
397254359Sroberto			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
397354359Sroberto			       CLK_UNIT(parse->peer),
397454359Sroberto			       prettydate(&reftime),
397554359Sroberto			       prettydate(&rectime),
397654359Sroberto			       lfptoa(&off,6));
397754359Sroberto#endif
397854359Sroberto	}
397954359Sroberto
398054359Sroberto	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
398154359Sroberto	{
398254359Sroberto		l_fp offset;
3983182007Sroberto		double ppsphaseadjust = parse->ppsphaseadjust;
398454359Sroberto
3985182007Sroberto#ifdef HAVE_PPSAPI
398654359Sroberto		/*
3987182007Sroberto		 * set fudge = 0.0 if already included in PPS time stamps
3988182007Sroberto		 */
3989280849Scy		if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3990182007Sroberto		        {
3991182007Sroberto			        ppsphaseadjust = 0.0;
3992182007Sroberto			}
3993182007Sroberto#endif
3994182007Sroberto
3995182007Sroberto		/*
399654359Sroberto		 * we have a PPS signal - much better than the RS232 stuff (we hope)
399754359Sroberto		 */
399854359Sroberto		offset = parsetime->parse_ptime.fp;
399954359Sroberto
400054359Sroberto#ifdef DEBUG
400154359Sroberto		if (debug > 3)
400254359Sroberto			printf("PARSE receiver #%d: PPStime %s\n",
400354359Sroberto				CLK_UNIT(parse->peer),
400454359Sroberto				prettydate(&offset));
400554359Sroberto#endif
400654359Sroberto		if (PARSE_TIMECODE(parsetime->parse_state))
400754359Sroberto		{
4008280849Scy			if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) &&
4009280849Scy			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf))
401054359Sroberto			{
4011182007Sroberto				fudge = ppsphaseadjust; /* pick PPS fudge factor */
401254359Sroberto
401354359Sroberto				/*
401454359Sroberto				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
401554359Sroberto				 */
401654359Sroberto
401754359Sroberto				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
401854359Sroberto				{
401954359Sroberto					reftime = off = offset;
4020280849Scy					if (reftime.l_uf & 0x80000000)
402154359Sroberto						reftime.l_ui++;
402254359Sroberto					reftime.l_uf = 0;
402356746Sroberto
402454359Sroberto
402554359Sroberto					/*
402654359Sroberto					 * implied on second offset
402754359Sroberto					 */
402854359Sroberto					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4029280849Scy					off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
403054359Sroberto				}
403154359Sroberto				else
403254359Sroberto				{
403354359Sroberto					/*
403454359Sroberto					 * time code describes pulse
403554359Sroberto					 */
403654359Sroberto					reftime = off = parsetime->parse_time.fp;
403754359Sroberto
403854359Sroberto					L_SUB(&off, &offset); /* true offset */
403954359Sroberto				}
404054359Sroberto			}
404154359Sroberto			/*
404254359Sroberto			 * take RS232 offset when PPS when out of bounds
404354359Sroberto			 */
404454359Sroberto		}
404554359Sroberto		else
404654359Sroberto		{
4047182007Sroberto			fudge = ppsphaseadjust; /* pick PPS fudge factor */
404854359Sroberto			/*
404954359Sroberto			 * Well, no time code to guide us - assume on second pulse
405054359Sroberto			 * and pray, that we are within [-0.5..0.5[
405154359Sroberto			 */
405254359Sroberto			off = offset;
405354359Sroberto			reftime = offset;
4054280849Scy			if (reftime.l_uf & 0x80000000)
405554359Sroberto				reftime.l_ui++;
405654359Sroberto			reftime.l_uf = 0;
405754359Sroberto			/*
405854359Sroberto			 * implied on second offset
405954359Sroberto			 */
406054359Sroberto			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4061280849Scy			off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
406254359Sroberto		}
406354359Sroberto	}
406454359Sroberto	else
406554359Sroberto	{
406654359Sroberto		if (!PARSE_TIMECODE(parsetime->parse_state))
406754359Sroberto		{
406854359Sroberto			/*
406954359Sroberto			 * Well, no PPS, no TIMECODE, no more work ...
407054359Sroberto			 */
407154359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
407254359Sroberto			    parse->parse_type->cl_message)
407354359Sroberto				parse->parse_type->cl_message(parse, parsetime);
407454359Sroberto			return;
407554359Sroberto		}
407654359Sroberto	}
407754359Sroberto
407854359Sroberto#ifdef DEBUG
407954359Sroberto	if (debug > 3)
408054359Sroberto		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
408154359Sroberto			CLK_UNIT(parse->peer),
408254359Sroberto			prettydate(&reftime),
408354359Sroberto			prettydate(&rectime),
408454359Sroberto			lfptoa(&off,6));
408554359Sroberto#endif
408654359Sroberto
408754359Sroberto
408854359Sroberto	rectime = reftime;
408954359Sroberto	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
409054359Sroberto
409154359Sroberto#ifdef DEBUG
409254359Sroberto	if (debug > 3)
409354359Sroberto		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
409454359Sroberto			CLK_UNIT(parse->peer),
409554359Sroberto			prettydate(&reftime),
409654359Sroberto			prettydate(&rectime));
409754359Sroberto#endif
409854359Sroberto
409954359Sroberto	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
410054359Sroberto	    parse->parse_type->cl_message)
410154359Sroberto		parse->parse_type->cl_message(parse, parsetime);
410254359Sroberto
410354359Sroberto	if (PARSE_SYNC(parsetime->parse_state))
410454359Sroberto	{
410554359Sroberto		/*
410654359Sroberto		 * log OK status
410754359Sroberto		 */
410854359Sroberto		parse_event(parse, CEVNT_NOMINAL);
410954359Sroberto	}
411054359Sroberto
411154359Sroberto	clear_err(parse, ERR_BADIO);
411254359Sroberto	clear_err(parse, ERR_BADDATA);
411354359Sroberto	clear_err(parse, ERR_NODATA);
411454359Sroberto	clear_err(parse, ERR_INTERNAL);
411554359Sroberto
411654359Sroberto	/*
411754359Sroberto	 * and now stick it into the clock machine
411854359Sroberto	 * samples are only valid iff lastsync is not too old and
411954359Sroberto	 * we have seen the clock in sync at least once
412054359Sroberto	 * after the last time we didn't see an expected data telegram
4121182007Sroberto	 * at startup being not in sync is also bad just like
4122280849Scy	 * POWERUP state unless PARSE_F_POWERUPTRUST is set
412354359Sroberto	 * see the clock states section above for more reasoning
412454359Sroberto	 */
4125280849Scy	if (((current_time - parse->lastsync) > parse->maxunsync)           ||
4126280849Scy	    (parse->lastsync < parse->lastmissed)                           ||
4127182007Sroberto	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
4128280849Scy	    (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
4129280849Scy	     PARSE_POWERUP(parsetime->parse_state)))
413054359Sroberto	{
413154359Sroberto		parse->generic->leap = LEAP_NOTINSYNC;
4132182007Sroberto		parse->lastsync = 0;	/* wait for full sync again */
413354359Sroberto	}
413454359Sroberto	else
413554359Sroberto	{
413654359Sroberto		if (PARSE_LEAPADD(parsetime->parse_state))
413754359Sroberto		{
413854359Sroberto			/*
413954359Sroberto			 * we pick this state also for time code that pass leap warnings
414054359Sroberto			 * without direction information (as earth is currently slowing
414154359Sroberto			 * down).
414254359Sroberto			 */
414354359Sroberto			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
414454359Sroberto		}
414554359Sroberto		else
414654359Sroberto		    if (PARSE_LEAPDEL(parsetime->parse_state))
414754359Sroberto		    {
414854359Sroberto			    parse->generic->leap = LEAP_DELSECOND;
414954359Sroberto		    }
415054359Sroberto		    else
415154359Sroberto		    {
415254359Sroberto			    parse->generic->leap = LEAP_NOWARNING;
415354359Sroberto		    }
415454359Sroberto	}
4155182007Sroberto
4156182007Sroberto	if (parse->generic->leap != LEAP_NOTINSYNC)
4157182007Sroberto	{
4158182007Sroberto	        /*
4159182007Sroberto		 * only good/trusted samples are interesting
4160182007Sroberto		 */
4161182007Sroberto#ifdef DEBUG
4162182007Sroberto	        if (debug > 2)
4163182007Sroberto		        {
4164182007Sroberto			        printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
4165182007Sroberto				       CLK_UNIT(parse->peer),
4166182007Sroberto				       prettydate(&reftime),
4167182007Sroberto				       prettydate(&rectime),
4168182007Sroberto				       fudge);
4169182007Sroberto			}
4170182007Sroberto#endif
4171182007Sroberto		parse->generic->lastref = reftime;
4172182007Sroberto
4173182007Sroberto		refclock_process_offset(parse->generic, reftime, rectime, fudge);
4174182007Sroberto
4175280849Scy#ifdef HAVE_PPSAPI
4176182007Sroberto		/*
4177182007Sroberto		 * pass PPS information on to PPS clock
4178182007Sroberto		 */
4179182007Sroberto		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4180182007Sroberto		        {
4181280849Scy				parse->peer->flags |= FLAG_PPS;
4182182007Sroberto				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4183182007Sroberto			}
4184280849Scy#endif
4185182007Sroberto	} else {
4186182007Sroberto	        parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4187280849Scy		parse->peer->flags &= ~FLAG_PPS;
4188182007Sroberto	}
4189182007Sroberto
419054359Sroberto	/*
4191182007Sroberto	 * ready, unless the machine wants a sample or
4192182007Sroberto	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
419354359Sroberto	 */
4194182007Sroberto	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
419554359Sroberto	    return;
419654359Sroberto
419754359Sroberto	parse->pollneeddata = 0;
419854359Sroberto
4199182007Sroberto	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4200182007Sroberto
420154359Sroberto	refclock_receive(parse->peer);
420254359Sroberto}
420356746Sroberto
420454359Sroberto/**===========================================================================
420554359Sroberto ** special code for special clocks
420654359Sroberto **/
420754359Sroberto
420854359Srobertostatic void
420954359Srobertomk_utcinfo(
421054359Sroberto	   char *t,
421154359Sroberto	   int wnt,
421254359Sroberto	   int wnlsf,
421354359Sroberto	   int dn,
421454359Sroberto	   int dtls,
4215182007Sroberto	   int dtlsf,
4216182007Sroberto	   int size
421754359Sroberto	   )
421854359Sroberto{
421954359Sroberto  l_fp leapdate;
4220182007Sroberto  char *start = t;
422154359Sroberto
4222182007Sroberto  snprintf(t, size, "current correction %d sec", dtls);
422354359Sroberto  t += strlen(t);
422454359Sroberto
422554359Sroberto  if (wnlsf < 990)
422654359Sroberto    wnlsf += 1024;
422754359Sroberto
422854359Sroberto  if (wnt < 990)
422954359Sroberto    wnt += 1024;
423054359Sroberto
423154359Sroberto  gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
423254359Sroberto
423354359Sroberto  if ((dtlsf != dtls) &&
423454359Sroberto      ((wnlsf - wnt) < 52))
423554359Sroberto    {
4236182007Sroberto	    snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
423754359Sroberto	      dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
423854359Sroberto    }
423954359Sroberto  else
424054359Sroberto    {
4241182007Sroberto	    snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
424254359Sroberto	      gmprettydate(&leapdate));
424354359Sroberto    }
424454359Sroberto}
424554359Sroberto
424654359Sroberto#ifdef CLOCK_MEINBERG
424754359Sroberto/**===========================================================================
424854359Sroberto ** Meinberg GPS166/GPS167 support
424954359Sroberto **/
425054359Sroberto
425154359Sroberto/*------------------------------------------------------------
425254359Sroberto * gps16x_message - process GPS16x messages
425354359Sroberto */
425454359Srobertostatic void
425554359Srobertogps16x_message(
425654359Sroberto	       struct parseunit *parse,
425754359Sroberto	       parsetime_t      *parsetime
425854359Sroberto	       )
425954359Sroberto{
4260182007Sroberto	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
426154359Sroberto	{
426254359Sroberto		GPS_MSG_HDR header;
426354359Sroberto		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
426454359Sroberto
426554359Sroberto#ifdef DEBUG
426654359Sroberto		if (debug > 2)
426754359Sroberto		{
426854359Sroberto			char msgbuffer[600];
426954359Sroberto
427054359Sroberto			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
427154359Sroberto			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
427254359Sroberto				CLK_UNIT(parse->peer),
427354359Sroberto				parsetime->parse_msglen,
427454359Sroberto				msgbuffer);
427554359Sroberto		}
427654359Sroberto#endif
427754359Sroberto		get_mbg_header(&bufp, &header);
427854359Sroberto		if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
427954359Sroberto		    (header.gps_len == 0 ||
428054359Sroberto		     (header.gps_len < sizeof(parsetime->parse_msg) &&
428154359Sroberto		      header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
428254359Sroberto		{
428354359Sroberto			/*
428454359Sroberto			 * clean message
428554359Sroberto			 */
428654359Sroberto			switch (header.gps_cmd)
428754359Sroberto			{
428854359Sroberto			case GPS_SW_REV:
428954359Sroberto				{
429054359Sroberto					char buffer[64];
429154359Sroberto					SW_REV gps_sw_rev;
429254359Sroberto
429354359Sroberto					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4294182007Sroberto					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
429554359Sroberto						(gps_sw_rev.code >> 8) & 0xFF,
429654359Sroberto						gps_sw_rev.code & 0xFF,
429754359Sroberto						gps_sw_rev.name[0] ? " " : "",
429854359Sroberto						gps_sw_rev.name);
4299182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
430054359Sroberto				}
430154359Sroberto			break;
430254359Sroberto
430354359Sroberto			case GPS_STAT:
430454359Sroberto				{
430554359Sroberto					static struct state
430654359Sroberto					{
430754359Sroberto						unsigned short flag; /* status flag */
430854359Sroberto						unsigned const char *string; /* bit name */
430954359Sroberto					} states[] =
431054359Sroberto					  {
431154359Sroberto						  { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
431254359Sroberto						  { TM_SYN_FLAG,    (const unsigned char *)"NO SYNC SIGNAL" },
431354359Sroberto						  { TM_NO_SYNC,     (const unsigned char *)"NO SYNC POWERUP" },
431454359Sroberto						  { TM_NO_POS,      (const unsigned char *)"NO POSITION" },
431554359Sroberto						  { 0, (const unsigned char *)"" }
431654359Sroberto					  };
431754359Sroberto					unsigned short status;
431854359Sroberto					struct state *s = states;
431954359Sroberto					char buffer[512];
432054359Sroberto					char *p, *b;
432154359Sroberto
432254359Sroberto					status = get_lsb_short(&bufp);
4323280849Scy					p = b = buffer;
4324280849Scy					p = ap(buffer, sizeof(buffer), p,
4325280849Scy					    "meinberg_gps_status=\"[0x%04x] ",
4326280849Scy					    status);
432754359Sroberto
432854359Sroberto					if (status)
432954359Sroberto					{
4330280849Scy						b = p;
433154359Sroberto						while (s->flag)
433254359Sroberto						{
433354359Sroberto							if (status & s->flag)
433454359Sroberto							{
433554359Sroberto								if (p != b)
433654359Sroberto								{
4337280849Scy									p = ap(buffer, sizeof(buffer), p, ", ");
433854359Sroberto								}
433954359Sroberto
4340280849Scy								p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
434154359Sroberto							}
434254359Sroberto							s++;
434354359Sroberto						}
4344280849Scy						p = ap(buffer, sizeof(buffer), p, "\"");
434554359Sroberto					}
434654359Sroberto					else
434754359Sroberto					{
4348280849Scy						p = ap(buffer, sizeof(buffer), p, "<OK>\"");
434954359Sroberto					}
435054359Sroberto
4351182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
435254359Sroberto				}
435354359Sroberto			break;
435454359Sroberto
435554359Sroberto			case GPS_POS_XYZ:
435654359Sroberto				{
435754359Sroberto					XYZ xyz;
435854359Sroberto					char buffer[256];
435954359Sroberto
436054359Sroberto					get_mbg_xyz(&bufp, xyz);
4361182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
436254359Sroberto						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
436354359Sroberto						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
436454359Sroberto						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
436554359Sroberto
436654359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
436754359Sroberto				}
436854359Sroberto			break;
436954359Sroberto
437054359Sroberto			case GPS_POS_LLA:
437154359Sroberto				{
437254359Sroberto					LLA lla;
437354359Sroberto					char buffer[256];
437454359Sroberto
437554359Sroberto					get_mbg_lla(&bufp, lla);
437654359Sroberto
4377182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
437854359Sroberto						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
437954359Sroberto						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
438054359Sroberto						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
438154359Sroberto
438254359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
438354359Sroberto				}
438454359Sroberto			break;
438554359Sroberto
438654359Sroberto			case GPS_TZDL:
438754359Sroberto				break;
438854359Sroberto
438954359Sroberto			case GPS_PORT_PARM:
439054359Sroberto				break;
439154359Sroberto
439254359Sroberto			case GPS_SYNTH:
439354359Sroberto				break;
439454359Sroberto
439554359Sroberto			case GPS_ANT_INFO:
439654359Sroberto				{
439754359Sroberto					ANT_INFO antinfo;
4398182007Sroberto					char buffer[512];
4399280849Scy					char *p, *q;
440054359Sroberto
440154359Sroberto					get_mbg_antinfo(&bufp, &antinfo);
4402280849Scy					p = buffer;
4403280849Scy					p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
440454359Sroberto					switch (antinfo.status)
440554359Sroberto					{
440654359Sroberto					case ANT_INVALID:
4407280849Scy						p = ap(buffer, sizeof(buffer),
4408280849Scy						    p, "<OK>");
440954359Sroberto						break;
441054359Sroberto
441154359Sroberto					case ANT_DISCONN:
4412280849Scy						q = ap(buffer, sizeof(buffer),
4413280849Scy						    p, "DISCONNECTED since ");
441454359Sroberto						NLOG(NLOG_CLOCKSTATUS)
441554359Sroberto							ERR(ERR_BADSTATUS)
441654359Sroberto							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
441754359Sroberto								CLK_UNIT(parse->peer), p);
441854359Sroberto
4419280849Scy						p = q;
4420182007Sroberto						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
442154359Sroberto						*p = '\0';
442254359Sroberto						break;
442354359Sroberto
442454359Sroberto					case ANT_RECONN:
4425280849Scy						p = ap(buffer, sizeof(buffer),
4426280849Scy						    p, "RECONNECTED on ");
4427182007Sroberto						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4428280849Scy						p = ap(buffer, sizeof(buffer),
4429280849Scy							p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
443054359Sroberto							(antinfo.delta_t < 0) ? '-' : '+',
443154359Sroberto							ABS(antinfo.delta_t) / 10000,
443254359Sroberto							ABS(antinfo.delta_t) % 10000);
4433182007Sroberto						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
443454359Sroberto						*p = '\0';
443554359Sroberto						break;
443654359Sroberto
443754359Sroberto					default:
4438280849Scy						p = ap(buffer, sizeof(buffer),
4439280849Scy						    p, "bad status 0x%04x",
4440280849Scy						    antinfo.status);
444154359Sroberto						break;
444254359Sroberto					}
444354359Sroberto
4444280849Scy					p = ap(buffer, sizeof(buffer), p, "\"");
444554359Sroberto
4446280849Scy					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
444754359Sroberto				}
444854359Sroberto			break;
444954359Sroberto
445054359Sroberto			case GPS_UCAP:
445154359Sroberto				break;
445254359Sroberto
445354359Sroberto			case GPS_CFGH:
445454359Sroberto				{
445554359Sroberto					CFGH cfgh;
4456182007Sroberto					char buffer[512];
4457182007Sroberto					char *p;
445854359Sroberto
445954359Sroberto					get_mbg_cfgh(&bufp, &cfgh);
446054359Sroberto					if (cfgh.valid)
446154359Sroberto					{
446254359Sroberto						int i;
446354359Sroberto
446454359Sroberto						p = buffer;
4465280849Scy						p = ap(buffer, sizeof(buffer),
4466280849Scy						    p, "gps_tot_51=\"");
4467182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4468280849Scy						p = ap(buffer, sizeof(buffer),
4469280849Scy						    p, "\"");
4470280849Scy						set_var(&parse->kv, buffer, sizeof(buffer), RO);
447154359Sroberto
447254359Sroberto						p = buffer;
4473280849Scy						p = ap(buffer, sizeof(buffer),
4474280849Scy						    p, "gps_tot_63=\"");
4475182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4476280849Scy						p = ap(buffer, sizeof(buffer),
4477280849Scy						    p, "\"");
4478280849Scy						set_var(&parse->kv, buffer, sizeof(buffer), RO);
447954359Sroberto
448054359Sroberto						p = buffer;
4481280849Scy						p = ap(buffer, sizeof(buffer),
4482280849Scy						    p, "gps_t0a=\"");
4483182007Sroberto						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4484280849Scy						p = ap(buffer, sizeof(buffer),
4485280849Scy						    p, "\"");
4486280849Scy						set_var(&parse->kv, buffer, sizeof(buffer), RO);
448754359Sroberto
4488182007Sroberto						for (i = MIN_SVNO; i < MAX_SVNO; i++)
448954359Sroberto						{
449054359Sroberto							p = buffer;
4491280849Scy							p = ap(buffer, sizeof(buffer), p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
449254359Sroberto							switch (cfgh.cfg[i] & 0x7)
449354359Sroberto							{
449454359Sroberto							case 0:
4495280849Scy								p = ap(buffer, sizeof(buffer), p, "BLOCK I");
449654359Sroberto								break;
449754359Sroberto							case 1:
4498280849Scy								p = ap(buffer, sizeof(buffer), p, "BLOCK II");
449954359Sroberto								break;
450054359Sroberto							default:
4501280849Scy								p = ap(buffer, sizeof(buffer), p, "bad CFG");
450254359Sroberto								break;
450354359Sroberto							}
4504280849Scy							p = ap(buffer, sizeof(buffer), p, "\"");
4505280849Scy							set_var(&parse->kv, buffer, sizeof(buffer), RO);
450654359Sroberto
450754359Sroberto							p = buffer;
4508280849Scy							p = ap(buffer, sizeof(buffer), p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
450954359Sroberto							switch ((cfgh.health[i] >> 5) & 0x7 )
451054359Sroberto							{
451154359Sroberto							case 0:
4512280849Scy								p = ap(buffer, sizeof(buffer), p, "OK;");
451354359Sroberto								break;
451454359Sroberto							case 1:
4515280849Scy								p = ap(buffer, sizeof(buffer), p, "PARITY;");
451654359Sroberto								break;
451754359Sroberto							case 2:
4518280849Scy								p = ap(buffer, sizeof(buffer), p, "TLM/HOW;");
451954359Sroberto								break;
452054359Sroberto							case 3:
4521280849Scy								p = ap(buffer, sizeof(buffer), p, "Z-COUNT;");
452254359Sroberto								break;
452354359Sroberto							case 4:
4524280849Scy								p = ap(buffer, sizeof(buffer), p, "SUBFRAME 1,2,3;");
452554359Sroberto								break;
452654359Sroberto							case 5:
4527280849Scy								p = ap(buffer, sizeof(buffer), p, "SUBFRAME 4,5;");
452854359Sroberto								break;
452954359Sroberto							case 6:
4530280849Scy								p = ap(buffer, sizeof(buffer), p, "UPLOAD BAD;");
453154359Sroberto								break;
453254359Sroberto							case 7:
4533280849Scy								p = ap(buffer, sizeof(buffer), p, "DATA BAD;");
453454359Sroberto								break;
453554359Sroberto							}
453654359Sroberto
453754359Sroberto							switch (cfgh.health[i] & 0x1F)
453854359Sroberto							{
453954359Sroberto							case 0:
4540280849Scy								p = ap(buffer, sizeof(buffer), p, "SIGNAL OK");
454154359Sroberto								break;
454254359Sroberto							case 0x1C:
4543280849Scy								p = ap(buffer, sizeof(buffer), p, "SV TEMP OUT");
454454359Sroberto								break;
454554359Sroberto							case 0x1D:
4546280849Scy								p = ap(buffer, sizeof(buffer), p, "SV WILL BE TEMP OUT");
454754359Sroberto								break;
454854359Sroberto							case 0x1E:
454954359Sroberto								break;
455054359Sroberto							case 0x1F:
4551280849Scy								p = ap(buffer, sizeof(buffer), p, "MULTIPLE ERRS");
455254359Sroberto								break;
455354359Sroberto							default:
4554280849Scy								p = ap(buffer, sizeof(buffer), p, "TRANSMISSION PROBLEMS");
455554359Sroberto								break;
455654359Sroberto							}
455754359Sroberto
4558280849Scy							p = ap(buffer, sizeof(buffer), p, "\"");
4559280849Scy							set_var(&parse->kv, buffer, sizeof(buffer), RO);
456054359Sroberto						}
456154359Sroberto					}
456254359Sroberto				}
456354359Sroberto			break;
456454359Sroberto
456554359Sroberto			case GPS_ALM:
456654359Sroberto				break;
456754359Sroberto
456854359Sroberto			case GPS_EPH:
456954359Sroberto				break;
457054359Sroberto
457154359Sroberto			case GPS_UTC:
457254359Sroberto				{
457354359Sroberto					UTC utc;
457454359Sroberto					char buffer[512];
457554359Sroberto					char *p;
457654359Sroberto
457754359Sroberto					p = buffer;
457854359Sroberto
457954359Sroberto					get_mbg_utc(&bufp, &utc);
458054359Sroberto
458154359Sroberto					if (utc.valid)
458254359Sroberto					{
4583280849Scy						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
4584280849Scy						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
458554359Sroberto						p += strlen(p);
4586280849Scy						p = ap(buffer, sizeof(buffer), p, "\"");
458754359Sroberto					}
458854359Sroberto					else
458954359Sroberto					{
4590280849Scy						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
459154359Sroberto					}
4592280849Scy					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
459354359Sroberto				}
459454359Sroberto			break;
459554359Sroberto
459654359Sroberto			case GPS_IONO:
459754359Sroberto				break;
459854359Sroberto
459954359Sroberto			case GPS_ASCII_MSG:
460054359Sroberto				{
460154359Sroberto					ASCII_MSG gps_ascii_msg;
460254359Sroberto					char buffer[128];
460354359Sroberto
460454359Sroberto					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
460554359Sroberto
460654359Sroberto					if (gps_ascii_msg.valid)
460754359Sroberto						{
460854359Sroberto							char buffer1[128];
460954359Sroberto							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
461054359Sroberto
4611182007Sroberto							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
461254359Sroberto						}
461354359Sroberto					else
4614280849Scy						snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
461554359Sroberto
4616280849Scy					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
461754359Sroberto				}
461854359Sroberto
461954359Sroberto			break;
462054359Sroberto
462154359Sroberto			default:
462254359Sroberto				break;
462354359Sroberto			}
462454359Sroberto		}
462554359Sroberto		else
462654359Sroberto		{
462754359Sroberto			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)",
462854359Sroberto				CLK_UNIT(parse->peer),
462954359Sroberto				header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
463054359Sroberto				header.gps_len,
463154359Sroberto				header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
463254359Sroberto		}
463354359Sroberto	}
463454359Sroberto
463554359Sroberto	return;
463654359Sroberto}
463754359Sroberto
463854359Sroberto/*------------------------------------------------------------
463954359Sroberto * gps16x_poll - query the reciver peridically
464054359Sroberto */
464154359Srobertostatic void
464254359Srobertogps16x_poll(
464354359Sroberto	    struct peer *peer
464454359Sroberto	    )
464554359Sroberto{
4646280849Scy	struct parseunit *parse = peer->procptr->unitptr;
464754359Sroberto
464854359Sroberto	static GPS_MSG_HDR sequence[] =
464954359Sroberto	{
465054359Sroberto		{ GPS_SW_REV,          0, 0, 0 },
465154359Sroberto		{ GPS_STAT,            0, 0, 0 },
465254359Sroberto		{ GPS_UTC,             0, 0, 0 },
465354359Sroberto		{ GPS_ASCII_MSG,       0, 0, 0 },
465454359Sroberto		{ GPS_ANT_INFO,        0, 0, 0 },
465554359Sroberto		{ GPS_CFGH,            0, 0, 0 },
465654359Sroberto		{ GPS_POS_XYZ,         0, 0, 0 },
465754359Sroberto		{ GPS_POS_LLA,         0, 0, 0 },
465854359Sroberto		{ (unsigned short)~0,  0, 0, 0 }
465954359Sroberto	};
4660280849Scy
466154359Sroberto	int rtc;
466254359Sroberto	unsigned char cmd_buffer[64];
466354359Sroberto	unsigned char *outp = cmd_buffer;
466454359Sroberto	GPS_MSG_HDR *header;
466554359Sroberto
466654359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
466754359Sroberto	{
4668280849Scy		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
466954359Sroberto	}
467054359Sroberto
467154359Sroberto	if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
467254359Sroberto		parse->localstate = 0;
467354359Sroberto
467454359Sroberto	header = sequence + parse->localstate++;
467554359Sroberto
467654359Sroberto	*outp++ = SOH;		/* start command */
467754359Sroberto
467854359Sroberto	put_mbg_header(&outp, header);
467954359Sroberto	outp = cmd_buffer + 1;
468054359Sroberto
468154359Sroberto	header->gps_hdr_csum = (short)mbg_csum(outp, 6);
468254359Sroberto	put_mbg_header(&outp, header);
468354359Sroberto
468454359Sroberto#ifdef DEBUG
468554359Sroberto	if (debug > 2)
468654359Sroberto	{
468754359Sroberto		char buffer[128];
468854359Sroberto
468954359Sroberto		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
469054359Sroberto		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
469154359Sroberto		       CLK_UNIT(parse->peer),
469254359Sroberto		       parse->localstate - 1,
469354359Sroberto		       (int)(outp - cmd_buffer),
469454359Sroberto		       buffer);
469554359Sroberto	}
469654359Sroberto#endif
469754359Sroberto
469854359Sroberto	rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
469954359Sroberto
470054359Sroberto	if (rtc < 0)
470154359Sroberto	{
470254359Sroberto		ERR(ERR_BADIO)
470354359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
470454359Sroberto	}
470554359Sroberto	else
470654359Sroberto	if (rtc != outp - cmd_buffer)
470754359Sroberto	{
470854359Sroberto		ERR(ERR_BADIO)
470954359Sroberto			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));
471054359Sroberto	}
471154359Sroberto
471254359Sroberto	clear_err(parse, ERR_BADIO);
471354359Sroberto	return;
471454359Sroberto}
471554359Sroberto
471654359Sroberto/*--------------------------------------------------
471754359Sroberto * init routine - setup timer
471854359Sroberto */
471954359Srobertostatic int
472054359Srobertogps16x_poll_init(
472154359Sroberto	struct parseunit *parse
472254359Sroberto	)
472354359Sroberto{
472454359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
472554359Sroberto	{
4726280849Scy		parse->peer->procptr->action = gps16x_poll;
472754359Sroberto		gps16x_poll(parse->peer);
472854359Sroberto	}
472954359Sroberto
473054359Sroberto	return 0;
473154359Sroberto}
473254359Sroberto
473354359Sroberto#else
473454359Srobertostatic void
473554359Srobertogps16x_message(
473654359Sroberto	       struct parseunit *parse,
473754359Sroberto	       parsetime_t      *parsetime
473854359Sroberto	       )
473954359Sroberto{}
474054359Srobertostatic int
474154359Srobertogps16x_poll_init(
474254359Sroberto	struct parseunit *parse
474354359Sroberto	)
474454359Sroberto{
474554359Sroberto	return 1;
474654359Sroberto}
474754359Sroberto#endif /* CLOCK_MEINBERG */
474854359Sroberto
474954359Sroberto/**===========================================================================
475054359Sroberto ** clock polling support
475154359Sroberto **/
475254359Sroberto
475354359Sroberto/*--------------------------------------------------
475454359Sroberto * direct poll routine
475554359Sroberto */
475654359Srobertostatic void
475754359Srobertopoll_dpoll(
475854359Sroberto	struct parseunit *parse
475954359Sroberto	)
476054359Sroberto{
476154359Sroberto	int rtc;
476254359Sroberto	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
476354359Sroberto	int   ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
476454359Sroberto
476554359Sroberto	rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
476654359Sroberto	if (rtc < 0)
476754359Sroberto	{
476854359Sroberto		ERR(ERR_BADIO)
476954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
477054359Sroberto	}
477154359Sroberto	else
477254359Sroberto	    if (rtc != ct)
477354359Sroberto	    {
477454359Sroberto		    ERR(ERR_BADIO)
477554359Sroberto			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
477654359Sroberto	    }
477754359Sroberto	clear_err(parse, ERR_BADIO);
477854359Sroberto}
477954359Sroberto
478054359Sroberto/*--------------------------------------------------
478154359Sroberto * periodic poll routine
478254359Sroberto */
478354359Srobertostatic void
478454359Srobertopoll_poll(
478554359Sroberto	struct peer *peer
478654359Sroberto	)
478754359Sroberto{
4788280849Scy	struct parseunit *parse = peer->procptr->unitptr;
478954359Sroberto
479054359Sroberto	if (parse->parse_type->cl_poll)
479154359Sroberto		parse->parse_type->cl_poll(parse);
479254359Sroberto
479354359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
479454359Sroberto	{
4795280849Scy		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
479654359Sroberto	}
479754359Sroberto}
479854359Sroberto
479954359Sroberto/*--------------------------------------------------
480054359Sroberto * init routine - setup timer
480154359Sroberto */
480254359Srobertostatic int
480354359Srobertopoll_init(
480454359Sroberto	struct parseunit *parse
480554359Sroberto	)
480654359Sroberto{
480754359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
480854359Sroberto	{
4809280849Scy		parse->peer->procptr->action = poll_poll;
481054359Sroberto		poll_poll(parse->peer);
481154359Sroberto	}
481254359Sroberto
481354359Sroberto	return 0;
481454359Sroberto}
481556746Sroberto
481654359Sroberto/**===========================================================================
481754359Sroberto ** Trimble support
481854359Sroberto **/
481954359Sroberto
482054359Sroberto/*-------------------------------------------------------------
482154359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init.
482254359Sroberto */
482354359Srobertostatic int
482454359Srobertotrimbletaip_init(
482554359Sroberto	struct parseunit *parse
482654359Sroberto	)
482754359Sroberto{
482854359Sroberto#ifdef HAVE_TERMIOS
482954359Sroberto	struct termios tio;
483054359Sroberto#endif
483154359Sroberto#ifdef HAVE_SYSV_TTYS
483254359Sroberto	struct termio tio;
483354359Sroberto#endif
483454359Sroberto	/*
483554359Sroberto	 * configure terminal line for trimble receiver
483654359Sroberto	 */
483754359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
483854359Sroberto	{
483954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
484054359Sroberto		return 0;
484154359Sroberto	}
484254359Sroberto	else
484354359Sroberto	{
484454359Sroberto		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
484554359Sroberto
484654359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
484754359Sroberto		{
484854359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
484954359Sroberto			return 0;
485054359Sroberto		}
485154359Sroberto	}
485254359Sroberto	return poll_init(parse);
485354359Sroberto}
485454359Sroberto
485554359Sroberto/*--------------------------------------------------
485654359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble
485754359Sroberto */
485854359Srobertostatic const char *taipinit[] = {
485954359Sroberto	">FPV00000000<",
486054359Sroberto	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
486154359Sroberto	">FTM00020001<",
486254359Sroberto	(char *)0
486354359Sroberto};
486454359Sroberto
486554359Srobertostatic void
486654359Srobertotrimbletaip_event(
486754359Sroberto	struct parseunit *parse,
486854359Sroberto	int event
486954359Sroberto	)
487054359Sroberto{
487154359Sroberto	switch (event)
487254359Sroberto	{
487354359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
487454359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
487554359Sroberto		    {
487654359Sroberto			    const char **iv;
487754359Sroberto
487854359Sroberto			    iv = taipinit;
487954359Sroberto			    while (*iv)
488054359Sroberto			    {
488154359Sroberto				    int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
488254359Sroberto				    if (rtc < 0)
488354359Sroberto				    {
488454359Sroberto					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
488554359Sroberto					    return;
488654359Sroberto				    }
488754359Sroberto				    else
488854359Sroberto				    {
4889280849Scy					    if (rtc != (int)strlen(*iv))
489054359Sroberto					    {
489154359Sroberto						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
489254359Sroberto							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
489354359Sroberto						    return;
489454359Sroberto					    }
489554359Sroberto				    }
489654359Sroberto				    iv++;
489754359Sroberto			    }
489854359Sroberto
489954359Sroberto			    NLOG(NLOG_CLOCKINFO)
490054359Sroberto				    ERR(ERR_BADIO)
490154359Sroberto				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
490254359Sroberto					    CLK_UNIT(parse->peer));
490354359Sroberto		    }
490454359Sroberto		    break;
490554359Sroberto
490654359Sroberto	    default:			/* ignore */
490754359Sroberto		break;
490854359Sroberto	}
490954359Sroberto}
491054359Sroberto
491154359Sroberto/*
491254359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module.
491354359Sroberto * It should support other Trimble receivers which use the Trimble Standard
491454359Sroberto * Interface Protocol (see below).
491554359Sroberto *
491654359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second
491754359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is
491854359Sroberto * coincident with the change of the GPS second. This is the same as
491954359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks
492054359Sroberto * specifically use a feature in the data message as a timing reference, but
492154359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter
492254359Sroberto * on the timing of the messages, so this driver only supports the use
492354359Sroberto * of the PPS pulse for accurate timing. Where it is determined that
492454359Sroberto * the offset is way off, when first starting up ntpd for example,
492554359Sroberto * the timing of the data stream is used until the offset becomes low enough
492656746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used.
492754359Sroberto *
492854359Sroberto * It can use either option for receiving PPS information - the 'ppsclock'
492954359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier
493054359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only
493154359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in
493254359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter
493354359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another
493454359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input,
493554359Sroberto * by whichever method, is handled in ntp_loopfilter.c
493654359Sroberto *
493754359Sroberto * The receiver uses a serial message protocol called Trimble Standard
493854359Sroberto * Interface Protocol (it can support others but this driver only supports
493954359Sroberto * TSIP). Messages in this protocol have the following form:
494054359Sroberto *
494154359Sroberto * <DLE><id> ... <data> ... <DLE><ETX>
494254359Sroberto *
494354359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
494454359Sroberto * on transmission and compressed back to one on reception. Otherwise
494554359Sroberto * the values of data bytes can be anything. The serial interface is RS-422
494654359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
494754359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single,
494854359Sroberto * and double datatypes. Integers are two bytes, sent most significant first.
494954359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent
495054359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point
495154359Sroberto * numbers (8 byte) sent sign & exponent first.
495254359Sroberto * The receiver supports a large set of messages, only a small subset of
495354359Sroberto * which are used here. From driver to receiver the following are used:
495454359Sroberto *
495554359Sroberto *  ID    Description
495654359Sroberto *
495754359Sroberto *  21    Request current time
495854359Sroberto *  22    Mode Select
495954359Sroberto *  2C    Set/Request operating parameters
496054359Sroberto *  2F    Request UTC info
496154359Sroberto *  35    Set/Request I/O options
496254359Sroberto
496354359Sroberto * From receiver to driver the following are recognised:
496454359Sroberto *
496554359Sroberto *  ID    Description
496654359Sroberto *
496754359Sroberto *  41    GPS Time
496854359Sroberto *  44    Satellite selection, PDOP, mode
496954359Sroberto *  46    Receiver health
497054359Sroberto *  4B    Machine code/status
497154359Sroberto *  4C    Report operating parameters (debug only)
497254359Sroberto *  4F    UTC correction data (used to get leap second warnings)
497354359Sroberto *  55    I/O options (debug only)
497454359Sroberto *
497554359Sroberto * All others are accepted but ignored.
497654359Sroberto *
497754359Sroberto */
497854359Sroberto
497954359Sroberto#define PI		3.1415926535898	/* lots of sig figs */
498054359Sroberto#define D2R		PI/180.0
498154359Sroberto
498254359Sroberto/*-------------------------------------------------------------------
498354359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
498454359Sroberto * interface to the receiver.
498554359Sroberto *
498654359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and
498754359Sroberto * float implementation dependend - these must be converted to portable
498854359Sroberto * versions !
498954359Sroberto *
499054359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems
499154359Sroberto * with IEEE754 floats as native floats
499254359Sroberto */
499354359Sroberto
499454359Srobertotypedef struct trimble
499554359Sroberto{
499654359Sroberto	u_long last_msg;	/* last message received */
4997182007Sroberto	u_long last_reset;	/* last time a reset was issued */
499854359Sroberto	u_char qtracking;	/* query tracking status */
499954359Sroberto	u_long ctrack;		/* current tracking set */
500054359Sroberto	u_long ltrack;		/* last tracking set */
500154359Sroberto} trimble_t;
500254359Sroberto
500354359Srobertounion uval {
500454359Sroberto	u_char  bd[8];
500554359Sroberto	int     iv;
500654359Sroberto	float   fv;
500754359Sroberto	double  dv;
500854359Sroberto};
500954359Sroberto
501054359Srobertostruct txbuf
501154359Sroberto{
501254359Sroberto	short idx;			/* index to first unused byte */
501354359Sroberto	u_char *txt;			/* pointer to actual data buffer */
501454359Sroberto};
501554359Sroberto
5016280849Scyvoid	sendcmd		(struct txbuf *buf, int c);
5017280849Scyvoid	sendbyte	(struct txbuf *buf, int b);
5018280849Scyvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5019280849Scyvoid	sendint		(struct txbuf *buf, int a);
5020280849Scyvoid	sendflt		(struct txbuf *buf, double a);
502156746Sroberto
502254359Srobertovoid
502354359Srobertosendcmd(
502454359Sroberto	struct txbuf *buf,
502554359Sroberto	int c
502654359Sroberto	)
502754359Sroberto{
502854359Sroberto	buf->txt[0] = DLE;
502954359Sroberto	buf->txt[1] = (u_char)c;
503054359Sroberto	buf->idx = 2;
503154359Sroberto}
503254359Sroberto
5033280849Scyvoid	sendcmd		(struct txbuf *buf, int c);
5034280849Scyvoid	sendbyte	(struct txbuf *buf, int b);
5035280849Scyvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5036280849Scyvoid	sendint		(struct txbuf *buf, int a);
5037280849Scyvoid	sendflt		(struct txbuf *buf, double a);
5038182007Sroberto
503954359Srobertovoid
504054359Srobertosendbyte(
504154359Sroberto	struct txbuf *buf,
504254359Sroberto	int b
504354359Sroberto	)
504454359Sroberto{
504554359Sroberto	if (b == DLE)
504654359Sroberto	    buf->txt[buf->idx++] = DLE;
504754359Sroberto	buf->txt[buf->idx++] = (u_char)b;
504854359Sroberto}
504954359Sroberto
505054359Srobertovoid
505154359Srobertosendetx(
505254359Sroberto	struct txbuf *buf,
505354359Sroberto	struct parseunit *parse
505454359Sroberto	)
505554359Sroberto{
505654359Sroberto	buf->txt[buf->idx++] = DLE;
505754359Sroberto	buf->txt[buf->idx++] = ETX;
505854359Sroberto
505954359Sroberto	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
506054359Sroberto	{
506154359Sroberto		ERR(ERR_BADIO)
506254359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
506354359Sroberto	}
506454359Sroberto	else
506554359Sroberto	{
506654359Sroberto#ifdef DEBUG
506754359Sroberto	  if (debug > 2)
506854359Sroberto	  {
506954359Sroberto		  char buffer[256];
507054359Sroberto
507154359Sroberto		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
507254359Sroberto		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
507354359Sroberto			 CLK_UNIT(parse->peer),
507454359Sroberto			 buf->idx, buffer);
507554359Sroberto	  }
507654359Sroberto#endif
507754359Sroberto		clear_err(parse, ERR_BADIO);
507854359Sroberto	}
507954359Sroberto}
508054359Sroberto
508154359Srobertovoid
508254359Srobertosendint(
508354359Sroberto	struct txbuf *buf,
508454359Sroberto	int a
508554359Sroberto	)
508654359Sroberto{
508754359Sroberto	/* send 16bit int, msbyte first */
508854359Sroberto	sendbyte(buf, (u_char)((a>>8) & 0xff));
508954359Sroberto	sendbyte(buf, (u_char)(a & 0xff));
509054359Sroberto}
509154359Sroberto
509254359Srobertovoid
509354359Srobertosendflt(
509454359Sroberto	struct txbuf *buf,
509554359Sroberto	double a
509654359Sroberto	)
509754359Sroberto{
509854359Sroberto	int i;
509954359Sroberto	union uval uval;
510054359Sroberto
510154359Sroberto	uval.fv = a;
510254359Sroberto#ifdef WORDS_BIGENDIAN
510354359Sroberto	for (i=0; i<=3; i++)
510454359Sroberto#else
510554359Sroberto	    for (i=3; i>=0; i--)
510654359Sroberto#endif
510754359Sroberto		sendbyte(buf, uval.bd[i]);
510854359Sroberto}
510954359Sroberto
511054359Sroberto#define TRIM_POS_OPT	0x13	/* output position with high precision */
511154359Sroberto#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
511254359Sroberto
511354359Sroberto/*--------------------------------------------------
511454359Sroberto * trimble TSIP setup routine
511554359Sroberto */
511654359Srobertostatic int
511754359Srobertotrimbletsip_setup(
511854359Sroberto		  struct parseunit *parse,
511954359Sroberto		  const char *reason
512056746Sroberto		  )
512154359Sroberto{
512254359Sroberto	u_char buffer[256];
512354359Sroberto	struct txbuf buf;
5124182007Sroberto	trimble_t *t = parse->localdata;
512554359Sroberto
5126182007Sroberto	if (t && t->last_reset &&
5127182007Sroberto	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
5128182007Sroberto		return 1;	/* not yet */
5129182007Sroberto	}
5130182007Sroberto
5131182007Sroberto	if (t)
5132182007Sroberto		t->last_reset = current_time;
5133182007Sroberto
513454359Sroberto	buf.txt = buffer;
513554359Sroberto
513654359Sroberto	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
513756746Sroberto	sendetx(&buf, parse);
513856746Sroberto
513954359Sroberto	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
514056746Sroberto	sendbyte(&buf, 4);	/* static */
514156746Sroberto	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
514256746Sroberto	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
514356746Sroberto	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
514456746Sroberto	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
514556746Sroberto	sendetx(&buf, parse);
514656746Sroberto
514754359Sroberto	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
5148182007Sroberto	sendbyte(&buf, 1);	/* time transfer mode */
514956746Sroberto	sendetx(&buf, parse);
515056746Sroberto
515154359Sroberto	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
515256746Sroberto	sendetx(&buf, parse);
515356746Sroberto
515454359Sroberto	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
515556746Sroberto	sendbyte(&buf, 0x2);	/* binary mode */
515656746Sroberto	sendetx(&buf, parse);
515756746Sroberto
515854359Sroberto	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
515954359Sroberto	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
516054359Sroberto	sendbyte(&buf, 0x00);	/* no velocity output */
516154359Sroberto	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
516254359Sroberto	sendbyte(&buf, 0x00);	/* no raw measurements */
516356746Sroberto	sendetx(&buf, parse);
516456746Sroberto
516554359Sroberto	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
516654359Sroberto	sendetx(&buf, parse);
516754359Sroberto
516854359Sroberto	NLOG(NLOG_CLOCKINFO)
516954359Sroberto		ERR(ERR_BADIO)
517054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
517154359Sroberto
517254359Sroberto	return 0;
517354359Sroberto}
517454359Sroberto
517554359Sroberto/*--------------------------------------------------
517654359Sroberto * TRIMBLE TSIP check routine
517754359Sroberto */
517854359Srobertostatic void
517954359Srobertotrimble_check(
518054359Sroberto	      struct peer *peer
518154359Sroberto	      )
518254359Sroberto{
5183280849Scy	struct parseunit *parse = peer->procptr->unitptr;
518454359Sroberto	trimble_t *t = parse->localdata;
518554359Sroberto	u_char buffer[256];
518654359Sroberto	struct txbuf buf;
518754359Sroberto	buf.txt = buffer;
518854359Sroberto
518954359Sroberto	if (t)
519054359Sroberto	{
519154359Sroberto		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
519254359Sroberto			(void)trimbletsip_setup(parse, "message timeout");
519354359Sroberto	}
5194182007Sroberto
519554359Sroberto	poll_poll(parse->peer);	/* emit query string and re-arm timer */
519654359Sroberto
5197182007Sroberto	if (t && t->qtracking)
519854359Sroberto	{
519954359Sroberto		u_long oldsats = t->ltrack & ~t->ctrack;
520054359Sroberto
520154359Sroberto		t->qtracking = 0;
520254359Sroberto		t->ltrack = t->ctrack;
520354359Sroberto
520454359Sroberto		if (oldsats)
520554359Sroberto		{
520654359Sroberto			int i;
520754359Sroberto
5208182007Sroberto			for (i = 0; oldsats; i++) {
520954359Sroberto				if (oldsats & (1 << i))
521054359Sroberto					{
521154359Sroberto						sendcmd(&buf, CMD_CSTATTRACK);
521254359Sroberto						sendbyte(&buf, i+1);	/* old sat */
521354359Sroberto						sendetx(&buf, parse);
521454359Sroberto					}
5215182007Sroberto				oldsats &= ~(1 << i);
5216182007Sroberto			}
521754359Sroberto		}
521854359Sroberto
521954359Sroberto		sendcmd(&buf, CMD_CSTATTRACK);
522054359Sroberto		sendbyte(&buf, 0x00);	/* current tracking set */
522154359Sroberto		sendetx(&buf, parse);
522254359Sroberto	}
522354359Sroberto}
522454359Sroberto
522554359Sroberto/*--------------------------------------------------
522654359Sroberto * TRIMBLE TSIP end routine
522754359Sroberto */
522854359Srobertostatic void
522954359Srobertotrimbletsip_end(
523054359Sroberto	      struct parseunit *parse
523154359Sroberto	      )
523254359Sroberto{	trimble_t *t = parse->localdata;
523354359Sroberto
523454359Sroberto	if (t)
523554359Sroberto	{
523654359Sroberto		free(t);
5237280849Scy		parse->localdata = NULL;
523854359Sroberto	}
5239280849Scy	parse->peer->procptr->nextaction = 0;
5240280849Scy	parse->peer->procptr->action = NULL;
524154359Sroberto}
524254359Sroberto
524354359Sroberto/*--------------------------------------------------
524454359Sroberto * TRIMBLE TSIP init routine
524554359Sroberto */
524654359Srobertostatic int
524754359Srobertotrimbletsip_init(
524854359Sroberto	struct parseunit *parse
524954359Sroberto	)
525054359Sroberto{
525154359Sroberto#if defined(VEOL) || defined(VEOL2)
525254359Sroberto#ifdef HAVE_TERMIOS
525354359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
525454359Sroberto#endif
525554359Sroberto#ifdef HAVE_SYSV_TTYS
525654359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
525754359Sroberto#endif
525854359Sroberto	/*
525954359Sroberto	 * allocate local data area
526054359Sroberto	 */
526154359Sroberto	if (!parse->localdata)
526254359Sroberto	{
526354359Sroberto		trimble_t *t;
526454359Sroberto
526554359Sroberto		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
526654359Sroberto
526754359Sroberto		if (t)
526854359Sroberto		{
526954359Sroberto			memset((char *)t, 0, sizeof(trimble_t));
527054359Sroberto			t->last_msg = current_time;
527154359Sroberto		}
527254359Sroberto	}
527354359Sroberto
5274280849Scy	parse->peer->procptr->action     = trimble_check;
5275280849Scy	parse->peer->procptr->nextaction = current_time;
527654359Sroberto
527754359Sroberto	/*
527854359Sroberto	 * configure terminal line for ICANON mode with VEOL characters
527954359Sroberto	 */
528054359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
528154359Sroberto	{
528254359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
528354359Sroberto		return 0;
528454359Sroberto	}
528554359Sroberto	else
528654359Sroberto	{
528754359Sroberto		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
528854359Sroberto		{
528954359Sroberto#ifdef VEOL
529054359Sroberto			tio.c_cc[VEOL]  = ETX;
529154359Sroberto#endif
529254359Sroberto#ifdef VEOL2
529354359Sroberto			tio.c_cc[VEOL2]  = DLE;
529454359Sroberto#endif
529556746Sroberto		}
529654359Sroberto
529754359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
529854359Sroberto		{
529954359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
530054359Sroberto			return 0;
530154359Sroberto		}
530254359Sroberto	}
530354359Sroberto#endif
530454359Sroberto	return trimbletsip_setup(parse, "initial startup");
530554359Sroberto}
530654359Sroberto
530754359Sroberto/*------------------------------------------------------------
530854359Sroberto * trimbletsip_event - handle Trimble events
530954359Sroberto * simple evente handler - attempt to re-initialize receiver
531054359Sroberto */
531154359Srobertostatic void
531254359Srobertotrimbletsip_event(
531354359Sroberto	struct parseunit *parse,
531454359Sroberto	int event
531554359Sroberto	)
531654359Sroberto{
531754359Sroberto	switch (event)
531854359Sroberto	{
531954359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
532054359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
532154359Sroberto		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
532254359Sroberto		    break;
532354359Sroberto
532454359Sroberto	    default:			/* ignore */
532554359Sroberto		break;
532654359Sroberto	}
532754359Sroberto}
532854359Sroberto
532954359Sroberto/*
533054359Sroberto * getflt, getint convert fields in the incoming data into the
533154359Sroberto * appropriate type of item
533254359Sroberto *
533354359Sroberto * CAVEAT: these routines are currently definitely byte order dependent
533454359Sroberto * and assume Representation(float) == IEEE754
533554359Sroberto * These functions MUST be converted to portable versions (especially
533654359Sroberto * converting the float representation into ntp_fp formats in order
533754359Sroberto * to avoid floating point operations at all!
533854359Sroberto */
533954359Sroberto
534054359Srobertostatic float
534154359Srobertogetflt(
534254359Sroberto	u_char *bp
534354359Sroberto	)
534454359Sroberto{
534554359Sroberto	union uval uval;
534654359Sroberto
534754359Sroberto#ifdef WORDS_BIGENDIAN
534854359Sroberto	uval.bd[0] = *bp++;
534954359Sroberto	uval.bd[1] = *bp++;
535054359Sroberto	uval.bd[2] = *bp++;
535154359Sroberto	uval.bd[3] = *bp;
535254359Sroberto#else  /* ! WORDS_BIGENDIAN */
535354359Sroberto	uval.bd[3] = *bp++;
535454359Sroberto	uval.bd[2] = *bp++;
535554359Sroberto	uval.bd[1] = *bp++;
535654359Sroberto	uval.bd[0] = *bp;
535754359Sroberto#endif /* ! WORDS_BIGENDIAN */
535854359Sroberto	return uval.fv;
535954359Sroberto}
536054359Sroberto
536154359Srobertostatic double
536254359Srobertogetdbl(
536354359Sroberto	u_char *bp
536454359Sroberto	)
536554359Sroberto{
536654359Sroberto	union uval uval;
536754359Sroberto
536854359Sroberto#ifdef WORDS_BIGENDIAN
536954359Sroberto	uval.bd[0] = *bp++;
537054359Sroberto	uval.bd[1] = *bp++;
537154359Sroberto	uval.bd[2] = *bp++;
537254359Sroberto	uval.bd[3] = *bp++;
537354359Sroberto	uval.bd[4] = *bp++;
537454359Sroberto	uval.bd[5] = *bp++;
537554359Sroberto	uval.bd[6] = *bp++;
537654359Sroberto	uval.bd[7] = *bp;
537754359Sroberto#else  /* ! WORDS_BIGENDIAN */
537854359Sroberto	uval.bd[7] = *bp++;
537954359Sroberto	uval.bd[6] = *bp++;
538054359Sroberto	uval.bd[5] = *bp++;
538154359Sroberto	uval.bd[4] = *bp++;
538254359Sroberto	uval.bd[3] = *bp++;
538354359Sroberto	uval.bd[2] = *bp++;
538454359Sroberto	uval.bd[1] = *bp++;
538554359Sroberto	uval.bd[0] = *bp;
538654359Sroberto#endif /* ! WORDS_BIGENDIAN */
538754359Sroberto	return uval.dv;
538854359Sroberto}
538954359Sroberto
539054359Srobertostatic int
539154359Srobertogetshort(
539254359Sroberto	 unsigned char *p
539354359Sroberto	 )
539454359Sroberto{
539554359Sroberto	return get_msb_short(&p);
539654359Sroberto}
539754359Sroberto
539854359Sroberto/*--------------------------------------------------
539954359Sroberto * trimbletsip_message - process trimble messages
540054359Sroberto */
540154359Sroberto#define RTOD (180.0 / 3.1415926535898)
540254359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
540354359Sroberto
540454359Srobertostatic void
540554359Srobertotrimbletsip_message(
540654359Sroberto		    struct parseunit *parse,
540754359Sroberto		    parsetime_t      *parsetime
540854359Sroberto		    )
540954359Sroberto{
541054359Sroberto	unsigned char *buffer = parsetime->parse_msg;
541154359Sroberto	unsigned int   size   = parsetime->parse_msglen;
541254359Sroberto
541354359Sroberto	if ((size < 4) ||
541454359Sroberto	    (buffer[0]      != DLE) ||
541554359Sroberto	    (buffer[size-1] != ETX) ||
541654359Sroberto	    (buffer[size-2] != DLE))
541754359Sroberto	{
541854359Sroberto#ifdef DEBUG
541954359Sroberto		if (debug > 2) {
5420280849Scy			size_t i;
542154359Sroberto
542254359Sroberto			printf("TRIMBLE BAD packet, size %d:\n	", size);
542354359Sroberto			for (i = 0; i < size; i++) {
542454359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
542554359Sroberto				if (i%16 == 15) printf("\n\t");
542654359Sroberto			}
542754359Sroberto			printf("\n");
542854359Sroberto		}
542954359Sroberto#endif
543054359Sroberto		return;
543154359Sroberto	}
543254359Sroberto	else
543354359Sroberto	{
543454359Sroberto		int var_flag;
543554359Sroberto		trimble_t *tr = parse->localdata;
543654359Sroberto		unsigned int cmd = buffer[1];
543754359Sroberto		char pbuffer[200];
543854359Sroberto		char *t = pbuffer;
543954359Sroberto		cmd_info_t *s;
544054359Sroberto
544154359Sroberto#ifdef DEBUG
544254359Sroberto		if (debug > 3) {
5443280849Scy			size_t i;
544454359Sroberto
544554359Sroberto			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
544654359Sroberto			for (i = 0; i < size; i++) {
544754359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
544854359Sroberto				if (i%16 == 15) printf("\n\t");
544954359Sroberto			}
545054359Sroberto			printf("\n");
545154359Sroberto		}
545254359Sroberto#endif
545354359Sroberto
545454359Sroberto		if (tr)
545554359Sroberto			tr->last_msg = current_time;
545654359Sroberto
545754359Sroberto		s = trimble_convert(cmd, trimble_rcmds);
545854359Sroberto
545954359Sroberto		if (s)
546054359Sroberto		{
5461280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
546254359Sroberto		}
546354359Sroberto		else
546454359Sroberto		{
5465182007Sroberto			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
546654359Sroberto			return;
546754359Sroberto		}
546854359Sroberto
546954359Sroberto		var_flag = s->varmode;
547054359Sroberto
547154359Sroberto		switch(cmd)
547254359Sroberto		{
547354359Sroberto		case CMD_RCURTIME:
5474280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
5475182007Sroberto				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5476182007Sroberto				 getflt((unsigned char *)&mb(6)));
547754359Sroberto			break;
547854359Sroberto
547954359Sroberto		case CMD_RBEST4:
5480280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
548154359Sroberto			switch (mb(0) & 0xF)
548254359Sroberto			{
548354359Sroberto			default:
5484280849Scy				t = ap(pbuffer, sizeof(pbuffer), t,
5485280849Scy				    "0x%x", mb(0) & 0x7);
548654359Sroberto				break;
548754359Sroberto
548854359Sroberto			case 1:
5489280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "0D");
549054359Sroberto				break;
549154359Sroberto
549254359Sroberto			case 3:
5493280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
549454359Sroberto				break;
549554359Sroberto
549654359Sroberto			case 4:
5497280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
549854359Sroberto				break;
549954359Sroberto			}
550054359Sroberto			if (mb(0) & 0x10)
5501280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
550254359Sroberto			else
5503280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
550454359Sroberto
5505280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
550654359Sroberto				mb(1), mb(2), mb(3), mb(4),
550754359Sroberto				getflt((unsigned char *)&mb(5)),
550854359Sroberto				getflt((unsigned char *)&mb(9)),
550954359Sroberto				getflt((unsigned char *)&mb(13)),
551054359Sroberto				getflt((unsigned char *)&mb(17)));
551154359Sroberto
551254359Sroberto			break;
551354359Sroberto
551454359Sroberto		case CMD_RVERSION:
5515280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
551654359Sroberto				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
551754359Sroberto			break;
551854359Sroberto
551954359Sroberto		case CMD_RRECVHEALTH:
552054359Sroberto		{
552154359Sroberto			static const char *msgs[] =
552254359Sroberto			{
552354359Sroberto				"Battery backup failed",
552454359Sroberto				"Signal processor error",
552554359Sroberto				"Alignment error, channel or chip 1",
552654359Sroberto				"Alignment error, channel or chip 2",
552754359Sroberto				"Antenna feed line fault",
552854359Sroberto				"Excessive ref freq. error",
552954359Sroberto				"<BIT 6>",
553054359Sroberto				"<BIT 7>"
553154359Sroberto			};
553254359Sroberto
553354359Sroberto			int i, bits;
553454359Sroberto
553554359Sroberto			switch (mb(0) & 0xFF)
553654359Sroberto			{
553754359Sroberto			default:
5538280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
553954359Sroberto				break;
554054359Sroberto			case 0x00:
5541280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes");
554254359Sroberto				break;
554354359Sroberto			case 0x01:
5544280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet");
554554359Sroberto				break;
554654359Sroberto			case 0x03:
5547280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high");
554854359Sroberto				break;
554954359Sroberto			case 0x08:
5550280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites");
555154359Sroberto				break;
555254359Sroberto			case 0x09:
5553280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite");
555454359Sroberto				break;
555554359Sroberto			case 0x0A:
5556280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites");
555754359Sroberto				break;
555854359Sroberto			case 0x0B:
5559280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites");
556054359Sroberto				break;
556154359Sroberto			case 0x0C:
5562280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable");
556354359Sroberto				break;
556454359Sroberto			}
556554359Sroberto
556654359Sroberto			bits = mb(1) & 0xFF;
556754359Sroberto
556854359Sroberto			for (i = 0; i < 8; i++)
556954359Sroberto				if (bits & (0x1<<i))
557054359Sroberto				{
5571280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
557254359Sroberto				}
557354359Sroberto		}
557454359Sroberto		break;
557554359Sroberto
557654359Sroberto		case CMD_RMESSAGE:
5577182007Sroberto			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
557854359Sroberto			break;
557954359Sroberto
558054359Sroberto		case CMD_RMACHSTAT:
558154359Sroberto		{
558254359Sroberto			static const char *msgs[] =
558354359Sroberto			{
558454359Sroberto				"Synthesizer Fault",
558554359Sroberto				"Battery Powered Time Clock Fault",
558654359Sroberto				"A-to-D Converter Fault",
558754359Sroberto				"The almanac stored in the receiver is not complete and current",
558854359Sroberto				"<BIT 4>",
558954359Sroberto				"<BIT 5",
559054359Sroberto				"<BIT 6>",
559154359Sroberto				"<BIT 7>"
559254359Sroberto			};
559354359Sroberto
559454359Sroberto			int i, bits;
559554359Sroberto
5596280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
559754359Sroberto			bits = mb(1) & 0xFF;
559854359Sroberto
559954359Sroberto			for (i = 0; i < 8; i++)
560054359Sroberto				if (bits & (0x1<<i))
560154359Sroberto				{
5602280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
560354359Sroberto				}
560454359Sroberto
5605280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
560654359Sroberto		}
560754359Sroberto		break;
560854359Sroberto
560954359Sroberto		case CMD_ROPERPARAM:
5610280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
561154359Sroberto				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
561254359Sroberto				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
561354359Sroberto			break;
561454359Sroberto
561554359Sroberto		case CMD_RUTCPARAM:
561654359Sroberto		{
561754359Sroberto			float t0t = getflt((unsigned char *)&mb(14));
561854359Sroberto			short wnt = getshort((unsigned char *)&mb(18));
561954359Sroberto			short dtls = getshort((unsigned char *)&mb(12));
562054359Sroberto			short wnlsf = getshort((unsigned char *)&mb(20));
562154359Sroberto			short dn = getshort((unsigned char *)&mb(22));
562254359Sroberto			short dtlsf = getshort((unsigned char *)&mb(24));
562354359Sroberto
562454359Sroberto			if ((int)t0t != 0)
5625280849Scy			{
5626280849Scy				mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5627280849Scy			}
562854359Sroberto			else
5629280849Scy			{
5630280849Scy			        t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
5631280849Scy			}
563254359Sroberto		}
563354359Sroberto		break;
563454359Sroberto
563554359Sroberto		case CMD_RSAT1BIAS:
5636280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
563754359Sroberto				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
563854359Sroberto			break;
563954359Sroberto
564054359Sroberto		case CMD_RIOOPTIONS:
564154359Sroberto		{
5642280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
564354359Sroberto				mb(0), mb(1), mb(2), mb(3));
564454359Sroberto			if (mb(0) != TRIM_POS_OPT ||
564554359Sroberto			    mb(2) != TRIM_TIME_OPT)
564654359Sroberto			{
564754359Sroberto				(void)trimbletsip_setup(parse, "bad io options");
564854359Sroberto			}
564954359Sroberto		}
565054359Sroberto		break;
565154359Sroberto
565254359Sroberto		case CMD_RSPOSXYZ:
565354359Sroberto		{
565454359Sroberto			double x = getflt((unsigned char *)&mb(0));
565554359Sroberto			double y = getflt((unsigned char *)&mb(4));
565654359Sroberto			double z = getflt((unsigned char *)&mb(8));
565754359Sroberto			double f = getflt((unsigned char *)&mb(12));
565854359Sroberto
565954359Sroberto			if (f > 0.0)
5660280849Scy			  t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
566154359Sroberto				  x, y, z,
566254359Sroberto				  f);
566354359Sroberto			else
5664280849Scy				return;
566554359Sroberto		}
566654359Sroberto		break;
566754359Sroberto
566854359Sroberto		case CMD_RSLLAPOS:
566954359Sroberto		{
567054359Sroberto			double lat = getflt((unsigned char *)&mb(0));
567154359Sroberto			double lng = getflt((unsigned char *)&mb(4));
567254359Sroberto			double f   = getflt((unsigned char *)&mb(12));
567354359Sroberto
567454359Sroberto			if (f > 0.0)
5675280849Scy			  t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
567654359Sroberto				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
567754359Sroberto				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
567854359Sroberto				  getflt((unsigned char *)&mb(8)));
567954359Sroberto			else
5680280849Scy				return;
568154359Sroberto		}
568254359Sroberto		break;
568354359Sroberto
568454359Sroberto		case CMD_RDOUBLEXYZ:
568554359Sroberto		{
568654359Sroberto			double x = getdbl((unsigned char *)&mb(0));
568754359Sroberto			double y = getdbl((unsigned char *)&mb(8));
568854359Sroberto			double z = getdbl((unsigned char *)&mb(16));
5689280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
569054359Sroberto				x, y, z);
569154359Sroberto		}
569254359Sroberto		break;
569354359Sroberto
569454359Sroberto		case CMD_RDOUBLELLA:
569554359Sroberto		{
569654359Sroberto			double lat = getdbl((unsigned char *)&mb(0));
569754359Sroberto			double lng = getdbl((unsigned char *)&mb(8));
5698280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
569954359Sroberto				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
570054359Sroberto				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
570154359Sroberto				getdbl((unsigned char *)&mb(16)));
570254359Sroberto		}
570354359Sroberto		break;
570454359Sroberto
570554359Sroberto		case CMD_RALLINVIEW:
570654359Sroberto		{
570754359Sroberto			int i, sats;
570854359Sroberto
5709280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
571054359Sroberto			switch (mb(0) & 0x7)
571154359Sroberto			{
571254359Sroberto			default:
5713280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
571454359Sroberto				break;
571554359Sroberto
571654359Sroberto			case 3:
5717280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
571854359Sroberto				break;
571954359Sroberto
572054359Sroberto			case 4:
5721280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
572254359Sroberto				break;
572354359Sroberto			}
572454359Sroberto			if (mb(0) & 0x8)
5725280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
572654359Sroberto			else
5727280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
572854359Sroberto
572954359Sroberto			sats = (mb(0)>>4) & 0xF;
573054359Sroberto
5731280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
573254359Sroberto				getflt((unsigned char *)&mb(1)),
573354359Sroberto				getflt((unsigned char *)&mb(5)),
573454359Sroberto				getflt((unsigned char *)&mb(9)),
573554359Sroberto				getflt((unsigned char *)&mb(13)),
573654359Sroberto				sats, (sats == 1) ? "" : "s");
573754359Sroberto
573854359Sroberto			for (i=0; i < sats; i++)
573954359Sroberto			{
5740280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
574154359Sroberto				if (tr)
574254359Sroberto					tr->ctrack |= (1 << (mb(17+i)-1));
574354359Sroberto			}
574454359Sroberto
574554359Sroberto			if (tr)
5746280849Scy			{	/* mark for tracking status query */
574754359Sroberto				tr->qtracking = 1;
574854359Sroberto			}
574954359Sroberto		}
575054359Sroberto		break;
575154359Sroberto
575254359Sroberto		case CMD_RSTATTRACK:
575354359Sroberto		{
5754280849Scy			t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
575554359Sroberto			if (getflt((unsigned char *)&mb(4)) < 0.0)
575654359Sroberto			{
5757280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
575854359Sroberto				var_flag &= ~DEF;
575954359Sroberto			}
576054359Sroberto			else
576154359Sroberto			{
5762280849Scy				t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
576354359Sroberto					(mb(1) & 0xFF)>>3,
576454359Sroberto					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
576554359Sroberto					mb(3),
576654359Sroberto					getflt((unsigned char *)&mb(4)),
576754359Sroberto					getflt((unsigned char *)&mb(12)) * RTOD,
576854359Sroberto					getflt((unsigned char *)&mb(16)) * RTOD);
576954359Sroberto				if (mb(20))
577054359Sroberto				{
577154359Sroberto					var_flag &= ~DEF;
5772280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
577354359Sroberto				}
577454359Sroberto				if (mb(22))
577554359Sroberto				{
577654359Sroberto					if (mb(22) == 1)
5777280849Scy						t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
577854359Sroberto					else
577954359Sroberto						if (mb(22) == 2)
5780280849Scy							t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
578154359Sroberto				}
578254359Sroberto				if (mb(23))
5783280849Scy					t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
578454359Sroberto			}
578554359Sroberto		}
578654359Sroberto		break;
578754359Sroberto
578854359Sroberto		default:
5789280849Scy			t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
579054359Sroberto			break;
579154359Sroberto		}
5792182007Sroberto
5793280849Scy		t = ap(pbuffer, sizeof(pbuffer), t,"\"");
579454359Sroberto		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
579554359Sroberto	}
579654359Sroberto}
579754359Sroberto
579854359Sroberto
579954359Sroberto/**============================================================
580054359Sroberto ** RAWDCF support
580154359Sroberto **/
580254359Sroberto
580354359Sroberto/*--------------------------------------------------
580456746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers
580556746Sroberto * SET DTR line
580654359Sroberto */
580754359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
580854359Srobertostatic int
580956746Srobertorawdcf_init_1(
581054359Sroberto	struct parseunit *parse
581154359Sroberto	)
581254359Sroberto{
581382498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
581454359Sroberto	/*
581554359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
581654359Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
581754359Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
581854359Sroberto	 */
581982498Sroberto	int sl232;
582082498Sroberto
582182498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
582282498Sroberto	{
582382498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
582482498Sroberto		return 0;
582582498Sroberto	}
582682498Sroberto
582754359Sroberto#ifdef TIOCM_DTR
582882498Sroberto	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
582954359Sroberto#else
583082498Sroberto	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
583154359Sroberto#endif
583254359Sroberto
583354359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
583454359Sroberto	{
583556746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
583654359Sroberto	}
583754359Sroberto	return 0;
583854359Sroberto}
583954359Sroberto#else
584054359Srobertostatic int
5841132451Srobertorawdcfdtr_init_1(
584254359Sroberto	struct parseunit *parse
584354359Sroberto	)
584454359Sroberto{
584556746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
584654359Sroberto	return 0;
584754359Sroberto}
584854359Sroberto#endif  /* DTR initialisation type */
584954359Sroberto
585054359Sroberto/*--------------------------------------------------
585156746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers
585256746Sroberto * CLR DTR line, SET RTS line
585354359Sroberto */
585456746Sroberto#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
585554359Srobertostatic int
585656746Srobertorawdcf_init_2(
585754359Sroberto	struct parseunit *parse
585854359Sroberto	)
585954359Sroberto{
586082498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
586154359Sroberto	/*
586254359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
586356746Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
586456746Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
586554359Sroberto	 */
586682498Sroberto	int sl232;
586782498Sroberto
586882498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
586982498Sroberto	{
587082498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
587182498Sroberto		return 0;
587282498Sroberto	}
587382498Sroberto
587454359Sroberto#ifdef TIOCM_RTS
587582498Sroberto	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
587654359Sroberto#else
587782498Sroberto	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
587854359Sroberto#endif
587954359Sroberto
588054359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
588154359Sroberto	{
588256746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
588354359Sroberto	}
588454359Sroberto	return 0;
588554359Sroberto}
588654359Sroberto#else
588754359Srobertostatic int
588856746Srobertorawdcf_init_2(
588954359Sroberto	struct parseunit *parse
589054359Sroberto	)
589154359Sroberto{
589256746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
589354359Sroberto	return 0;
589454359Sroberto}
589556746Sroberto#endif  /* DTR initialisation type */
589654359Sroberto
589754359Sroberto#else	/* defined(REFCLOCK) && defined(PARSE) */
5898280849ScyNONEMPTY_TRANSLATION_UNIT
589954359Sroberto#endif	/* defined(REFCLOCK) && defined(PARSE) */
590054359Sroberto
590154359Sroberto/*
590254359Sroberto * History:
590354359Sroberto *
590454359Sroberto * refclock_parse.c,v
5905280849Scy * Revision 4.81  2009/05/01 10:15:29  kardel
5906280849Scy * use new refclock_ppsapi interface
5907280849Scy *
5908182007Sroberto * Revision 4.80  2007/08/11 12:06:29  kardel
5909182007Sroberto * update comments wrt/ to PPS
5910182007Sroberto *
5911182007Sroberto * Revision 4.79  2007/08/11 11:52:23  kardel
5912182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor
5913182007Sroberto *
5914182007Sroberto * Revision 4.78  2006/12/22 20:08:27  kardel
5915182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5916182007Sroberto *
5917182007Sroberto * Revision 4.77  2006/08/05 07:44:49  kardel
5918182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5919182007Sroberto *
5920182007Sroberto * Revision 4.76  2006/06/22 18:40:47  kardel
5921182007Sroberto * clean up signedness (gcc 4)
5922182007Sroberto *
5923182007Sroberto * Revision 4.75  2006/06/22 16:58:10  kardel
5924182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5925182007Sroberto * the PPS offset. Fix sign of offset passed to kernel.
5926182007Sroberto *
5927182007Sroberto * Revision 4.74  2006/06/18 21:18:37  kardel
5928182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref
5929182007Sroberto *
5930182007Sroberto * Revision 4.73  2006/05/26 14:23:46  kardel
5931182007Sroberto * cleanup of copyright info
5932182007Sroberto *
5933182007Sroberto * Revision 4.72  2006/05/26 14:19:43  kardel
5934182007Sroberto * cleanup of ioctl cruft
5935182007Sroberto *
5936182007Sroberto * Revision 4.71  2006/05/26 14:15:57  kardel
5937182007Sroberto * delay adding refclock to async refclock io after all initializations
5938182007Sroberto *
5939182007Sroberto * Revision 4.70  2006/05/25 18:20:50  kardel
5940182007Sroberto * bug #619
5941182007Sroberto * terminate parse io engine after de-registering
5942182007Sroberto * from refclock io engine
5943182007Sroberto *
5944182007Sroberto * Revision 4.69  2006/05/25 17:28:02  kardel
5945182007Sroberto * complete refclock io structure initialization *before* inserting it into the
5946182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619)
5947182007Sroberto *
5948182007Sroberto * Revision 4.68  2006/05/01 17:02:51  kardel
5949182007Sroberto * copy receiver method also for newlwy created receive buffers
5950182007Sroberto *
5951182007Sroberto * Revision 4.67  2006/05/01 14:37:29  kardel
5952182007Sroberto * If an input buffer parses into more than one message do insert the
5953182007Sroberto * parsed message in a new input buffer instead of processing it
5954182007Sroberto * directly. This avoids deed complicated processing in signal
5955182007Sroberto * handling.
5956182007Sroberto *
5957182007Sroberto * Revision 4.66  2006/03/18 00:45:30  kardel
5958182007Sroberto * coverity fixes found in NetBSD coverity scan
5959182007Sroberto *
5960182007Sroberto * Revision 4.65  2006/01/26 06:08:33  kardel
5961182007Sroberto * output errno on PPS setup failure
5962182007Sroberto *
5963182007Sroberto * Revision 4.64  2005/11/09 20:44:47  kardel
5964182007Sroberto * utilize full PPS timestamp resolution from PPS API
5965182007Sroberto *
5966182007Sroberto * Revision 4.63  2005/10/07 22:10:25  kardel
5967182007Sroberto * bounded buffer implementation
5968182007Sroberto *
5969182007Sroberto * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5970182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5971182007Sroberto * replace almost all str* and *printf functions be their buffer bounded
5972182007Sroberto * counterparts
5973182007Sroberto *
5974182007Sroberto * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
5975182007Sroberto * limit re-set rate of trimble clocks
5976182007Sroberto *
5977182007Sroberto * Revision 4.62  2005/08/06 17:40:00  kardel
5978182007Sroberto * cleanup size handling wrt/ to buffer boundaries
5979182007Sroberto *
5980182007Sroberto * Revision 4.61  2005/07/27 21:16:19  kardel
5981182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5982182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of
5983182007Sroberto * the DCF77 clocks.
5984182007Sroberto *
5985182007Sroberto * Revision 4.60  2005/07/17 21:14:44  kardel
5986182007Sroberto * change contents of version string to include the RCS/CVS Id
5987182007Sroberto *
5988182007Sroberto * Revision 4.59  2005/07/06 06:56:38  kardel
5989182007Sroberto * syntax error
5990182007Sroberto *
5991182007Sroberto * Revision 4.58  2005/07/04 13:10:40  kardel
5992182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup
5993182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5994182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and
5995182007Sroberto *     varying structure element sizes
5996182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers
5997182007Sroberto *
5998182007Sroberto * Revision 4.57  2005/06/25 09:25:19  kardel
5999182007Sroberto * sort out log output sequence
6000182007Sroberto *
6001182007Sroberto * Revision 4.56  2005/06/14 21:47:27  kardel
6002182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel)
6003182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
6004182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state
6005182007Sroberto *
6006182007Sroberto * Revision 4.55  2005/06/02 21:28:31  kardel
6007182007Sroberto * clarify trust logic
6008182007Sroberto *
6009182007Sroberto * Revision 4.54  2005/06/02 17:06:49  kardel
6010182007Sroberto * change status reporting to use fixed refclock_report()
6011182007Sroberto *
6012182007Sroberto * Revision 4.53  2005/06/02 16:33:31  kardel
6013182007Sroberto * fix acceptance of clocks unsync clocks right at start
6014182007Sroberto *
6015182007Sroberto * Revision 4.52  2005/05/26 21:55:06  kardel
6016182007Sroberto * cleanup status reporting
6017182007Sroberto *
6018182007Sroberto * Revision 4.51  2005/05/26 19:19:14  kardel
6019182007Sroberto * implement fast refclock startup
6020182007Sroberto *
6021182007Sroberto * Revision 4.50  2005/04/16 20:51:35  kardel
6022280849Scy * set hardpps_enable = 1 when binding a kernel PPS source
6023182007Sroberto *
6024182007Sroberto * Revision 4.49  2005/04/16 17:29:26  kardel
6025182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks
6026182007Sroberto *
6027182007Sroberto * Revision 4.48  2005/04/16 16:22:27  kardel
6028182007Sroberto * bk sync 20050415 ntp-dev
6029182007Sroberto *
6030182007Sroberto * Revision 4.47  2004/11/29 10:42:48  kardel
6031182007Sroberto * bk sync ntp-dev 20041129
6032182007Sroberto *
6033182007Sroberto * Revision 4.46  2004/11/29 10:26:29  kardel
6034182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
6035182007Sroberto *
6036182007Sroberto * Revision 4.45  2004/11/14 20:53:20  kardel
6037182007Sroberto * clear PPS flags after using them
6038182007Sroberto *
6039182007Sroberto * Revision 4.44  2004/11/14 15:29:41  kardel
6040182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
6041182007Sroberto *
6042182007Sroberto * Revision 4.43  2001/05/26 22:53:16  kardel
6043182007Sroberto * 20010526 reconcilation
6044182007Sroberto *
6045182007Sroberto * Revision 4.42  2000/05/14 15:31:51  kardel
6046182007Sroberto * PPSAPI && RAWDCF modemline support
6047182007Sroberto *
6048182007Sroberto * Revision 4.41  2000/04/09 19:50:45  kardel
6049182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1
6050182007Sroberto *
6051182007Sroberto * Revision 4.40  2000/04/09 15:27:55  kardel
6052182007Sroberto * modem line fiddle in rawdcf_init_2
6053182007Sroberto *
6054182007Sroberto * Revision 4.39  2000/03/18 09:16:55  kardel
6055182007Sroberto * PPSAPI integration
6056182007Sroberto *
6057182007Sroberto * Revision 4.38  2000/03/05 20:25:06  kardel
6058182007Sroberto * support PPSAPI
6059182007Sroberto *
6060182007Sroberto * Revision 4.37  2000/03/05 20:11:14  kardel
6061182007Sroberto * 4.0.99g reconcilation
6062182007Sroberto *
606356746Sroberto * Revision 4.36  1999/11/28 17:18:20  kardel
606456746Sroberto * disabled burst mode
606556746Sroberto *
606656746Sroberto * Revision 4.35  1999/11/28 09:14:14  kardel
606756746Sroberto * RECON_4_0_98F
606856746Sroberto *
606956746Sroberto * Revision 4.34  1999/05/14 06:08:05  kardel
607056746Sroberto * store current_time in a suitable container (u_long)
607156746Sroberto *
607256746Sroberto * Revision 4.33  1999/05/13 21:48:38  kardel
607356746Sroberto * double the no response timeout interval
607456746Sroberto *
607556746Sroberto * Revision 4.32  1999/05/13 20:09:13  kardel
607656746Sroberto * complain only about missing polls after a full poll interval
607756746Sroberto *
607856746Sroberto * Revision 4.31  1999/05/13 19:59:32  kardel
607956746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF
608056746Sroberto *
608156746Sroberto * Revision 4.30  1999/02/28 20:36:43  kardel
608256746Sroberto * fixed printf fmt
608356746Sroberto *
608454359Sroberto * Revision 4.29  1999/02/28 19:58:23  kardel
608554359Sroberto * updated copyright information
608654359Sroberto *
608754359Sroberto * Revision 4.28  1999/02/28 19:01:50  kardel
608854359Sroberto * improved debug out on sent Meinberg messages
608954359Sroberto *
609054359Sroberto * Revision 4.27  1999/02/28 18:05:55  kardel
609154359Sroberto * no linux/ppsclock.h stuff
609254359Sroberto *
609354359Sroberto * Revision 4.26  1999/02/28 15:27:27  kardel
609454359Sroberto * wharton clock integration
609554359Sroberto *
609654359Sroberto * Revision 4.25  1999/02/28 14:04:46  kardel
609754359Sroberto * added missing double quotes to UTC information string
609854359Sroberto *
609954359Sroberto * Revision 4.24  1999/02/28 12:06:50  kardel
610054359Sroberto * (parse_control): using gmprettydate instead of prettydate()
610154359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information
610254359Sroberto * (gps16x_message): changed to use mk_utcinfo()
610354359Sroberto * (trimbletsip_message): changed to use mk_utcinfo()
610454359Sroberto * ignoring position information in unsynchronized mode
610554359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
610654359Sroberto *
610754359Sroberto * Revision 4.23  1999/02/23 19:47:53  kardel
610854359Sroberto * fixed #endifs
610954359Sroberto * (stream_receive): fixed formats
611054359Sroberto *
611154359Sroberto * Revision 4.22  1999/02/22 06:21:02  kardel
611254359Sroberto * use new autoconfig symbols
611354359Sroberto *
611454359Sroberto * Revision 4.21  1999/02/21 12:18:13  kardel
611554359Sroberto * 4.91f reconcilation
611654359Sroberto *
611754359Sroberto * Revision 4.20  1999/02/21 10:53:36  kardel
611854359Sroberto * initial Linux PPSkit version
611954359Sroberto *
612054359Sroberto * Revision 4.19  1999/02/07 09:10:45  kardel
612154359Sroberto * clarify STREAMS mitigation rules in comment
612254359Sroberto *
612354359Sroberto * Revision 4.18  1998/12/20 23:45:34  kardel
612454359Sroberto * fix types and warnings
612554359Sroberto *
612654359Sroberto * Revision 4.17  1998/11/15 21:24:51  kardel
612754359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG
612854359Sroberto * is not defined
612954359Sroberto *
613054359Sroberto * Revision 4.16  1998/11/15 20:28:17  kardel
613154359Sroberto * Release 4.0.73e13 reconcilation
613254359Sroberto *
613354359Sroberto * Revision 4.15  1998/08/22 21:56:08  kardel
613454359Sroberto * fixed IO handling for non-STREAM IO
613554359Sroberto *
613654359Sroberto * Revision 4.14  1998/08/16 19:00:48  kardel
613754359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
613854359Sroberto * made uval a local variable (killed one of the last globals)
613954359Sroberto * (sendetx): added logging of messages when in debug mode
614054359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization
614154359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation
614254359Sroberto * (trimbletsip_message): extended message interpretation
614354359Sroberto * (getdbl): fixed data conversion
614454359Sroberto *
614554359Sroberto * Revision 4.13  1998/08/09 22:29:13  kardel
614654359Sroberto * Trimble TSIP support
614754359Sroberto *
614854359Sroberto * Revision 4.12  1998/07/11 10:05:34  kardel
614954359Sroberto * Release 4.0.73d reconcilation
615054359Sroberto *
615154359Sroberto * Revision 4.11  1998/06/14 21:09:42  kardel
615254359Sroberto * Sun acc cleanup
615354359Sroberto *
615454359Sroberto * Revision 4.10  1998/06/13 12:36:45  kardel
615554359Sroberto * signed/unsigned, name clashes
615654359Sroberto *
615754359Sroberto * Revision 4.9  1998/06/12 15:30:00  kardel
615854359Sroberto * prototype fixes
615954359Sroberto *
616054359Sroberto * Revision 4.8  1998/06/12 11:19:42  kardel
616154359Sroberto * added direct input processing routine for refclocks in
616254359Sroberto * order to avaiod that single character io gobbles up all
616354359Sroberto * receive buffers and drops input data. (Problem started
616454359Sroberto * with fast machines so a character a buffer was possible
616554359Sroberto * one of the few cases where faster machines break existing
616654359Sroberto * allocation algorithms)
616754359Sroberto *
616854359Sroberto * Revision 4.7  1998/06/06 18:35:20  kardel
616954359Sroberto * (parse_start): added BURST mode initialisation
617054359Sroberto *
617154359Sroberto * Revision 4.6  1998/05/27 06:12:46  kardel
617254359Sroberto * RAWDCF_BASEDELAY default added
617354359Sroberto * old comment removed
617454359Sroberto * casts for ioctl()
617554359Sroberto *
617654359Sroberto * Revision 4.5  1998/05/25 22:05:09  kardel
617754359Sroberto * RAWDCF_SETDTR option removed
617854359Sroberto * clock type 14 attempts to set DTR for
617954359Sroberto * power supply of RAWDCF receivers
618054359Sroberto *
618154359Sroberto * Revision 4.4  1998/05/24 16:20:47  kardel
618254359Sroberto * updated comments referencing Meinberg clocks
618354359Sroberto * added RAWDCF clock with DTR set option as type 14
618454359Sroberto *
618554359Sroberto * Revision 4.3  1998/05/24 10:48:33  kardel
618654359Sroberto * calibrated CONRAD RAWDCF default fudge factor
618754359Sroberto *
618854359Sroberto * Revision 4.2  1998/05/24 09:59:35  kardel
618954359Sroberto * corrected version information (ntpq support)
619054359Sroberto *
619154359Sroberto * Revision 4.1  1998/05/24 09:52:31  kardel
619254359Sroberto * use fixed format only (new IO model)
619354359Sroberto * output debug to stdout instead of msyslog()
619454359Sroberto * don't include >"< in ASCII output in order not to confuse
619554359Sroberto * ntpq parsing
619654359Sroberto *
619754359Sroberto * Revision 4.0  1998/04/10 19:52:11  kardel
619854359Sroberto * Start 4.0 release version numbering
619954359Sroberto *
620054359Sroberto * Revision 1.2  1998/04/10 19:28:04  kardel
620154359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
620254359Sroberto * derived from 3.105.1.2 from V3 tree
620354359Sroberto *
620454359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
620554359Sroberto *
620654359Sroberto */
6207