154359Sroberto/*
2285612Sdelphij * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A
354359Sroberto *
4285612Sdelphij * 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 *
18285612Sdelphij * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
19285612Sdelphij * 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
51285612Sdelphij#include "ntp_types.h"
52285612Sdelphij
5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE)
5454359Sroberto
5554359Sroberto/*
5654359Sroberto * This driver currently provides the support for
57285612Sdelphij *   - Meinberg receiver DCF77 PZF535 (TCXO version)        (DCF)
58285612Sdelphij *   - Meinberg receiver DCF77 PZF535 (OCXO version)        (DCF)
59285612Sdelphij *   - Meinberg receiver DCF77 PZF509                       (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)
66285612Sdelphij *   - WHARTON 400A Series clock                            (DCF)
6754359Sroberto *
68285612Sdelphij *   - Meinberg GPS receivers                               (GPS)
6954359Sroberto *   - Trimble (TSIP and TAIP protocol)                     (GPS)
7054359Sroberto *
7154359Sroberto *   - RCC8000 MSF Receiver                                 (MSF)
72285612Sdelphij *   - VARITEXT clock                                       (MSF)
7354359Sroberto */
7454359Sroberto
7554359Sroberto/*
7654359Sroberto * Meinberg receivers are usually connected via a
77285612Sdelphij * 9600/7E1 or 19200/8N1 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:
83285612Sdelphij *      output time code every second
84285612Sdelphij *      Baud rate 9600 7E2S
8554359Sroberto *
86285612Sdelphij * Meinberg GPS receiver 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
94285612Sdelphij * oldest GPS receiver, GPS16x. For newer receiver types
95285612Sdelphij * the output string format can be configured at the device,
96285612Sdelphij * and the device name is generally GPSxxx instead of GPS16x.
9754359Sroberto *
9854359Sroberto * Meinberg can be reached via: http://www.meinberg.de/
9954359Sroberto */
10054359Sroberto
10154359Sroberto#include "ntpd.h"
10254359Sroberto#include "ntp_refclock.h"
103285612Sdelphij#include "timevalops.h"		/* includes <sys/time.h> */
10454359Sroberto#include "ntp_control.h"
105182007Sroberto#include "ntp_string.h"
10654359Sroberto
10754359Sroberto#include <stdio.h>
10854359Sroberto#include <ctype.h>
10954359Sroberto#ifndef TM_IN_SYS_TIME
11054359Sroberto# include <time.h>
11154359Sroberto#endif
11254359Sroberto
113182007Sroberto#ifdef HAVE_UNISTD_H
114182007Sroberto# include <unistd.h>
115182007Sroberto#endif
116182007Sroberto
11754359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
11854359Sroberto# include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
11954359Sroberto#endif
12054359Sroberto
12154359Sroberto#ifdef STREAM
12254359Sroberto# include <sys/stream.h>
12354359Sroberto# include <sys/stropts.h>
12454359Sroberto#endif
12554359Sroberto
12654359Sroberto#ifdef HAVE_TERMIOS
127285612Sdelphij# include <termios.h>
12854359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
12954359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
13054359Sroberto# undef HAVE_SYSV_TTYS
13154359Sroberto#endif
13254359Sroberto
13354359Sroberto#ifdef HAVE_SYSV_TTYS
13454359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
13554359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
13654359Sroberto#endif
13754359Sroberto
13854359Sroberto#ifdef HAVE_BSD_TTYS
13954359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */
14054359Sroberto# include "Bletch: BSD TTY not currently supported"
14154359Sroberto#endif
14254359Sroberto
14354359Sroberto#ifdef HAVE_SYS_IOCTL_H
14454359Sroberto# include <sys/ioctl.h>
14554359Sroberto#endif
14654359Sroberto
147182007Sroberto#ifdef HAVE_PPSAPI
148182007Sroberto# include "ppsapi_timepps.h"
149285612Sdelphij# include "refclock_atom.h"
150182007Sroberto#endif
151182007Sroberto
15254359Sroberto#ifdef PPS
153182007Sroberto# ifdef HAVE_SYS_PPSCLOCK_H
154182007Sroberto#  include <sys/ppsclock.h>
155182007Sroberto# endif
156182007Sroberto# ifdef HAVE_TIO_SERIAL_STUFF
157182007Sroberto#  include <linux/serial.h>
158182007Sroberto# endif
15954359Sroberto#endif
160182007Sroberto
161285612Sdelphij# define BUFFER_SIZE(_BUF, _PTR)       ((int)((_BUF) + sizeof(_BUF) - (_PTR)))
162285612Sdelphij# define BUFFER_SIZES(_BUF, _PTR, _SZ) ((int)((_BUF) + (_SZ) - (_PTR)))
163182007Sroberto
164182007Sroberto/*
165182007Sroberto * document type of PPS interfacing - copy of ifdef mechanism in local_input()
166182007Sroberto */
167285612Sdelphij#undef PPS_METHOD
168182007Sroberto
169182007Sroberto#ifdef HAVE_PPSAPI
170182007Sroberto#define PPS_METHOD "PPS API"
171182007Sroberto#else
172182007Sroberto#ifdef TIOCDCDTIMESTAMP
173182007Sroberto#define PPS_METHOD "TIOCDCDTIMESTAMP"
174182007Sroberto#else /* TIOCDCDTIMESTAMP */
175182007Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
176182007Sroberto#ifdef HAVE_CIOGETEV
177182007Sroberto#define PPS_METHOD "CIOGETEV"
17854359Sroberto#endif
179182007Sroberto#ifdef HAVE_TIOCGPPSEV
180182007Sroberto#define PPS_METHOD "TIOCGPPSEV"
18154359Sroberto#endif
182182007Sroberto#endif
183182007Sroberto#endif /* TIOCDCDTIMESTAMP */
184182007Sroberto#endif /* HAVE_PPSAPI */
18554359Sroberto
186285612Sdelphij/*
187285612Sdelphij * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF
188285612Sdelphij * then some more parse-specific variables are flagged to be printed with
189285612Sdelphij * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF
190285612Sdelphij * should be defined as 0.
191285612Sdelphij */
192285612Sdelphij#if 0
193285612Sdelphij# define COND_DEF   DEF   // enable this for testing
194285612Sdelphij#else
195285612Sdelphij# define COND_DEF   0     // enable this by default
196285612Sdelphij#endif
197285612Sdelphij
19854359Sroberto#include "ntp_io.h"
19954359Sroberto#include "ntp_stdlib.h"
20054359Sroberto
20154359Sroberto#include "parse.h"
20254359Sroberto#include "mbg_gps166.h"
20354359Sroberto#include "trimble.h"
20454359Sroberto#include "binio.h"
20554359Sroberto#include "ascii.h"
20654359Sroberto#include "ieee754io.h"
207182007Sroberto#include "recvbuff.h"
20854359Sroberto
209285612Sdelphijstatic char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST";
21054359Sroberto
21154359Sroberto/**===========================================================================
21254359Sroberto ** external interface to ntp mechanism
21354359Sroberto **/
21454359Sroberto
215285612Sdelphijstatic	int	parse_start	(int, struct peer *);
216285612Sdelphijstatic	void	parse_shutdown	(int, struct peer *);
217285612Sdelphijstatic	void	parse_poll	(int, struct peer *);
218285612Sdelphijstatic	void	parse_control	(int, const struct refclockstat *, struct refclockstat *, struct peer *);
21954359Sroberto
22054359Srobertostruct	refclock refclock_parse = {
22154359Sroberto	parse_start,
22254359Sroberto	parse_shutdown,
22354359Sroberto	parse_poll,
22454359Sroberto	parse_control,
225182007Sroberto	noentry,
226182007Sroberto	noentry,
22754359Sroberto	NOFLAGS
22854359Sroberto};
22954359Sroberto
23054359Sroberto/*
23154359Sroberto * Definitions
23254359Sroberto */
23354359Sroberto#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
23454359Sroberto#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
235182007Sroberto#define PARSEPPSDEVICE	"/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
23654359Sroberto
23754359Sroberto#undef ABS
23854359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
23954359Sroberto
240182007Sroberto#define PARSE_HARDPPS_DISABLE 0
241182007Sroberto#define PARSE_HARDPPS_ENABLE  1
242182007Sroberto
24354359Sroberto/**===========================================================================
24454359Sroberto ** function vector for dynamically binding io handling mechanism
24554359Sroberto **/
24654359Sroberto
24754359Srobertostruct parseunit;		/* to keep inquiring minds happy */
24854359Sroberto
24954359Srobertotypedef struct bind
25054359Sroberto{
25154359Sroberto  const char *bd_description;	                                /* name of type of binding */
252285612Sdelphij  int	(*bd_init)     (struct parseunit *);			/* initialize */
253285612Sdelphij  void	(*bd_end)      (struct parseunit *);			/* end */
254285612Sdelphij  int   (*bd_setcs)    (struct parseunit *, parsectl_t *);	/* set character size */
255285612Sdelphij  int	(*bd_disable)  (struct parseunit *);			/* disable */
256285612Sdelphij  int	(*bd_enable)   (struct parseunit *);			/* enable */
257285612Sdelphij  int	(*bd_getfmt)   (struct parseunit *, parsectl_t *);	/* get format */
258285612Sdelphij  int	(*bd_setfmt)   (struct parseunit *, parsectl_t *);	/* setfmt */
259285612Sdelphij  int	(*bd_timecode) (struct parseunit *, parsectl_t *);	/* get time code */
260285612Sdelphij  void	(*bd_receive)  (struct recvbuf *);			/* receive operation */
261285612Sdelphij  int	(*bd_io_input) (struct recvbuf *);			/* input operation */
26254359Sroberto} bind_t;
26354359Sroberto
26454359Sroberto#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
26554359Sroberto#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
26654359Sroberto#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
26754359Sroberto#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
26854359Sroberto#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
26954359Sroberto#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
27054359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
27154359Sroberto
27254359Sroberto/*
273285612Sdelphij * special handling flags
27454359Sroberto */
275285612Sdelphij#define PARSE_F_PPSONSECOND	0x00000001 /* PPS pulses are on second */
276285612Sdelphij#define PARSE_F_POWERUPTRUST	0x00000100 /* POWERUP state ist trusted for */
277285612Sdelphij                                           /* trusttime after SYNC was seen */
27854359Sroberto/**===========================================================================
27954359Sroberto ** error message regression handling
28054359Sroberto **
28154359Sroberto ** there are quite a few errors that can occur in rapid succession such as
28254359Sroberto ** noisy input data or no data at all. in order to reduce the amount of
28354359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit
28454359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a
28554359Sroberto ** configurable number of messages is displayed that way, we move on to the
28654359Sroberto ** next time unit / count for that class. a count of messages that have been
28754359Sroberto ** suppressed is held and displayed whenever a corresponding message is
28854359Sroberto ** displayed. the time units for a message class will also be displayed.
28954359Sroberto ** whenever an error condition clears we reset the error message state,
29054359Sroberto ** thus we would still generate much output on pathological conditions
29154359Sroberto ** where the system oscillates between OK and NOT OK states. coping
29254359Sroberto ** with that condition is currently considered too complicated.
29354359Sroberto **/
29454359Sroberto
29554359Sroberto#define ERR_ALL	        (unsigned)~0	/* "all" errors */
29654359Sroberto#define ERR_BADDATA	(unsigned)0	/* unusable input data/conversion errors */
29754359Sroberto#define ERR_NODATA	(unsigned)1	/* no input data */
29854359Sroberto#define ERR_BADIO	(unsigned)2	/* read/write/select errors */
29954359Sroberto#define ERR_BADSTATUS	(unsigned)3	/* unsync states */
30054359Sroberto#define ERR_BADEVENT	(unsigned)4	/* non nominal events */
30154359Sroberto#define ERR_INTERNAL	(unsigned)5	/* internal error */
30254359Sroberto#define ERR_CNT		(unsigned)(ERR_INTERNAL+1)
30354359Sroberto
30454359Sroberto#define ERR(_X_)	if (list_err(parse, (_X_)))
30554359Sroberto
30654359Srobertostruct errorregression
30754359Sroberto{
30854359Sroberto	u_long err_count;	/* number of repititions per class */
30954359Sroberto	u_long err_delay;	/* minimum delay between messages */
31054359Sroberto};
31154359Sroberto
31254359Srobertostatic struct errorregression
31354359Srobertoerr_baddata[] =			/* error messages for bad input data */
31454359Sroberto{
31554359Sroberto	{ 1,       0 },		/* output first message immediately */
31654359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
31754359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
31854359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
31954359Sroberto};
32054359Sroberto
32154359Srobertostatic struct errorregression
32254359Srobertoerr_nodata[] =			/* error messages for missing input data */
32354359Sroberto{
32454359Sroberto	{ 1,       0 },		/* output first message immediately */
32554359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
32654359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
32754359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
32854359Sroberto};
32954359Sroberto
33054359Srobertostatic struct errorregression
33154359Srobertoerr_badstatus[] =		/* unsynchronized state messages */
33254359Sroberto{
33354359Sroberto	{ 1,       0 },		/* output first message immediately */
33454359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
33554359Sroberto	{ 3,    3600 },		/* output next 3 messages in hour intervals */
33654359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
33754359Sroberto};
33854359Sroberto
33954359Srobertostatic struct errorregression
34054359Srobertoerr_badio[] =			/* io failures (bad reads, selects, ...) */
34154359Sroberto{
34254359Sroberto	{ 1,       0 },		/* output first message immediately */
34354359Sroberto	{ 5,      60 },		/* output next five messages in 60 second intervals */
34454359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
34554359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
34654359Sroberto};
34754359Sroberto
34854359Srobertostatic struct errorregression
34954359Srobertoerr_badevent[] =		/* non nominal events */
35054359Sroberto{
35154359Sroberto	{ 20,      0 },		/* output first message immediately */
35254359Sroberto	{ 6,      60 },		/* output next five messages in 60 second intervals */
35354359Sroberto	{ 5,    3600 },		/* output next 3 messages in hour intervals */
35454359Sroberto	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
35554359Sroberto};
35654359Sroberto
35754359Srobertostatic struct errorregression
35854359Srobertoerr_internal[] =		/* really bad things - basically coding/OS errors */
35954359Sroberto{
36054359Sroberto	{ 0,       0 },		/* output all messages immediately */
36154359Sroberto};
36254359Sroberto
36354359Srobertostatic struct errorregression *
36454359Srobertoerr_tbl[] =
36554359Sroberto{
36654359Sroberto	err_baddata,
36754359Sroberto	err_nodata,
36854359Sroberto	err_badio,
36954359Sroberto	err_badstatus,
37054359Sroberto	err_badevent,
37154359Sroberto	err_internal
37254359Sroberto};
37354359Sroberto
37454359Srobertostruct errorinfo
37554359Sroberto{
37654359Sroberto	u_long err_started;	/* begin time (ntp) of error condition */
37754359Sroberto	u_long err_last;	/* last time (ntp) error occurred */
37854359Sroberto	u_long err_cnt;	/* number of error repititions */
37954359Sroberto	u_long err_suppressed;	/* number of suppressed messages */
38054359Sroberto	struct errorregression *err_stage; /* current error stage */
38154359Sroberto};
38254359Sroberto
38354359Sroberto/**===========================================================================
38454359Sroberto ** refclock instance data
38554359Sroberto **/
38654359Sroberto
38754359Srobertostruct parseunit
38854359Sroberto{
38954359Sroberto	/*
39054359Sroberto	 * NTP management
39154359Sroberto	 */
39254359Sroberto	struct peer         *peer;		/* backlink to peer structure - refclock inactive if 0  */
39354359Sroberto	struct refclockproc *generic;		/* backlink to refclockproc structure */
39454359Sroberto
39554359Sroberto	/*
39654359Sroberto	 * PARSE io
39754359Sroberto	 */
39854359Sroberto	bind_t	     *binding;	        /* io handling binding */
399285612Sdelphij
40054359Sroberto	/*
40154359Sroberto	 * parse state
40254359Sroberto	 */
40354359Sroberto	parse_t	      parseio;	        /* io handling structure (user level parsing) */
40454359Sroberto
40554359Sroberto	/*
40654359Sroberto	 * type specific parameters
40754359Sroberto	 */
40854359Sroberto	struct parse_clockinfo   *parse_type;	        /* link to clock description */
40954359Sroberto
41054359Sroberto	/*
41154359Sroberto	 * clock state handling/reporting
41254359Sroberto	 */
41354359Sroberto	u_char	      flags;	        /* flags (leap_control) */
41454359Sroberto	u_long	      lastchange;       /* time (ntp) when last state change accured */
41554359Sroberto	u_long	      statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
41656746Sroberto	u_long        pollneeddata; 	/* current_time(!=0) for receive sample expected in PPS mode */
41754359Sroberto	u_short	      lastformat;       /* last format used */
41854359Sroberto	u_long        lastsync;		/* time (ntp) when clock was last seen fully synchronized */
419182007Sroberto        u_long        maxunsync;        /* max time in seconds a receiver is trusted after loosing synchronisation */
420182007Sroberto        double        ppsphaseadjust;   /* phase adjustment of PPS time stamp */
421182007Sroberto        u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
42254359Sroberto	u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
423182007Sroberto	int	      ppsfd;	        /* fd to ise for PPS io */
424182007Sroberto#ifdef HAVE_PPSAPI
425182007Sroberto        int           hardppsstate;     /* current hard pps state */
426285612Sdelphij	struct refclock_atom atom;      /* PPSAPI structure */
427182007Sroberto#endif
428182007Sroberto	parsetime_t   timedata;		/* last (parse module) data */
42954359Sroberto	void         *localdata;        /* optional local, receiver-specific data */
43054359Sroberto        unsigned long localstate;       /* private local state */
43154359Sroberto	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
43254359Sroberto	struct ctl_var *kv;	        /* additional pseudo variables */
43354359Sroberto	u_long        laststatistic;    /* time when staticstics where output */
43454359Sroberto};
43554359Sroberto
43654359Sroberto
43754359Sroberto/**===========================================================================
43854359Sroberto ** Clockinfo section all parameter for specific clock types
43954359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters
44054359Sroberto **/
44154359Sroberto
442285612Sdelphijstatic	void	poll_dpoll	(struct parseunit *);
443285612Sdelphijstatic	void	poll_poll	(struct peer *);
444285612Sdelphijstatic	int	poll_init	(struct parseunit *);
44554359Sroberto
44654359Srobertotypedef struct poll_info
44754359Sroberto{
44854359Sroberto	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
44954359Sroberto	const char *string;		/* string to send for polling */
45054359Sroberto	u_long      count;		/* number of characters in string */
45154359Sroberto} poll_info_t;
45254359Sroberto
45354359Sroberto#define NO_CL_FLAGS	0
45454359Sroberto#define NO_POLL		0
45554359Sroberto#define NO_INIT		0
45654359Sroberto#define NO_END		0
45754359Sroberto#define NO_EVENT	0
458182007Sroberto#define NO_LCLDATA	0
45954359Sroberto#define NO_MESSAGE	0
46054359Sroberto#define NO_PPSDELAY     0
46154359Sroberto
46254359Sroberto#define DCF_ID		"DCF"	/* generic DCF */
46354359Sroberto#define DCF_A_ID	"DCFa"	/* AM demodulation */
46454359Sroberto#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
46554359Sroberto#define GPS_ID		"GPS"	/* GPS receiver */
46654359Sroberto
467285612Sdelphij#define NOCLOCK_ROOTDELAY       0.0
468285612Sdelphij#define NOCLOCK_BASEDELAY       0.0
469285612Sdelphij#define NOCLOCK_DESCRIPTION     0
47054359Sroberto#define NOCLOCK_MAXUNSYNC       0
47154359Sroberto#define NOCLOCK_CFLAG           0
47254359Sroberto#define NOCLOCK_IFLAG           0
47354359Sroberto#define NOCLOCK_OFLAG           0
47454359Sroberto#define NOCLOCK_LFLAG           0
475285612Sdelphij#define NOCLOCK_ID              "TILT"
476285612Sdelphij#define NOCLOCK_POLL            NO_POLL
477285612Sdelphij#define NOCLOCK_INIT            NO_INIT
478285612Sdelphij#define NOCLOCK_END             NO_END
479285612Sdelphij#define NOCLOCK_DATA            NO_LCLDATA
480285612Sdelphij#define NOCLOCK_FORMAT          ""
481285612Sdelphij#define NOCLOCK_TYPE            CTL_SST_TS_UNSPEC
482285612Sdelphij#define NOCLOCK_SAMPLES         0
483285612Sdelphij#define NOCLOCK_KEEP            0
48454359Sroberto
48554359Sroberto#define DCF_TYPE		CTL_SST_TS_LF
48654359Sroberto#define GPS_TYPE		CTL_SST_TS_UHF
48754359Sroberto
48854359Sroberto/*
48954359Sroberto * receiver specific constants
49054359Sroberto */
49154359Sroberto#define MBG_SPEED		(B9600)
492182007Sroberto#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
49354359Sroberto#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
49454359Sroberto#define MBG_OFLAG		0
49554359Sroberto#define MBG_LFLAG		0
49654359Sroberto#define MBG_FLAGS               PARSE_F_PPSONSECOND
49754359Sroberto
49854359Sroberto/*
49954359Sroberto * Meinberg DCF77 receivers
50054359Sroberto */
50154359Sroberto#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
50254359Sroberto#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
50354359Sroberto#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
50454359Sroberto#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
50554359Sroberto#define DCFUA31_SPEED		MBG_SPEED
50654359Sroberto#define DCFUA31_CFLAG           MBG_CFLAG
50754359Sroberto#define DCFUA31_IFLAG           MBG_IFLAG
50854359Sroberto#define DCFUA31_OFLAG           MBG_OFLAG
50954359Sroberto#define DCFUA31_LFLAG           MBG_LFLAG
51054359Sroberto#define DCFUA31_SAMPLES		5
51154359Sroberto#define DCFUA31_KEEP		3
51254359Sroberto#define DCFUA31_FORMAT		"Meinberg Standard"
51354359Sroberto
51454359Sroberto/*
51554359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
51654359Sroberto */
51754359Sroberto#define	DCFPZF535_ROOTDELAY	0.0
51854359Sroberto#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
51954359Sroberto#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
52054359Sroberto#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
52154359Sroberto						    * @ 5e-8df/f we have accumulated
52254359Sroberto						    * at most 2.16 ms (thus we move to
52354359Sroberto						    * NTP synchronisation */
52454359Sroberto#define DCFPZF535_SPEED		MBG_SPEED
52554359Sroberto#define DCFPZF535_CFLAG         MBG_CFLAG
52654359Sroberto#define DCFPZF535_IFLAG         MBG_IFLAG
52754359Sroberto#define DCFPZF535_OFLAG         MBG_OFLAG
52854359Sroberto#define DCFPZF535_LFLAG         MBG_LFLAG
52954359Sroberto#define DCFPZF535_SAMPLES	       5
53054359Sroberto#define DCFPZF535_KEEP		       3
53154359Sroberto#define DCFPZF535_FORMAT	"Meinberg Standard"
53254359Sroberto
53354359Sroberto/*
53454359Sroberto * Meinberg DCF PZF535/OCXO receiver
53554359Sroberto */
53654359Sroberto#define	DCFPZF535OCXO_ROOTDELAY	0.0
53754359Sroberto#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
53854359Sroberto#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
53954359Sroberto#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
54054359Sroberto						    * @ 5e-9df/f we have accumulated
54154359Sroberto						    * at most an error of 1.73 ms
54254359Sroberto						    * (thus we move to NTP synchronisation) */
54354359Sroberto#define DCFPZF535OCXO_SPEED	    MBG_SPEED
54454359Sroberto#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
54554359Sroberto#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
54654359Sroberto#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
54754359Sroberto#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
54854359Sroberto#define DCFPZF535OCXO_SAMPLES		   5
54954359Sroberto#define DCFPZF535OCXO_KEEP	           3
55054359Sroberto#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
55154359Sroberto
55254359Sroberto/*
553285612Sdelphij * Meinberg GPS receivers
55454359Sroberto */
555285612Sdelphijstatic	void	gps16x_message	 (struct parseunit *, parsetime_t *);
556285612Sdelphijstatic  int     gps16x_poll_init (struct parseunit *);
55754359Sroberto
55854359Sroberto#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
55954359Sroberto#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
560285612Sdelphij#define	GPS16X_DESCRIPTION      "Meinberg GPS receiver"
56154359Sroberto#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
56254359Sroberto						* @ 5e-9df/f we have accumulated
56354359Sroberto						* at most an error of 1.73 ms
56454359Sroberto						* (thus we move to NTP synchronisation) */
56554359Sroberto#define GPS16X_SPEED		B19200
56654359Sroberto#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
56754359Sroberto#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
56854359Sroberto#define GPS16X_OFLAG            MBG_OFLAG
56954359Sroberto#define GPS16X_LFLAG            MBG_LFLAG
57054359Sroberto#define GPS16X_POLLRATE	6
57154359Sroberto#define GPS16X_POLLCMD	""
57254359Sroberto#define GPS16X_CMDSIZE	0
57354359Sroberto
57454359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
57554359Sroberto
57654359Sroberto#define GPS16X_INIT		gps16x_poll_init
57754359Sroberto#define GPS16X_POLL	        0
57854359Sroberto#define GPS16X_END		0
57954359Sroberto#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
58054359Sroberto#define GPS16X_MESSAGE		gps16x_message
58154359Sroberto#define GPS16X_ID		GPS_ID
58254359Sroberto#define GPS16X_FORMAT		"Meinberg GPS Extended"
58354359Sroberto#define GPS16X_SAMPLES		5
58454359Sroberto#define GPS16X_KEEP		3
58554359Sroberto
58654359Sroberto/*
58754359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
58854359Sroberto *
58954359Sroberto * This is really not the hottest clock - but before you have nothing ...
59054359Sroberto */
59154359Sroberto#define DCF7000_ROOTDELAY	0.0 /* 0 */
59254359Sroberto#define DCF7000_BASEDELAY	0.405 /* slow blow */
59354359Sroberto#define DCF7000_DESCRIPTION	"ELV DCF7000"
59454359Sroberto#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
59554359Sroberto#define DCF7000_SPEED		(B9600)
59654359Sroberto#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
59754359Sroberto#define DCF7000_IFLAG		(IGNBRK)
59854359Sroberto#define DCF7000_OFLAG		0
59954359Sroberto#define DCF7000_LFLAG		0
60054359Sroberto#define DCF7000_SAMPLES		5
60154359Sroberto#define DCF7000_KEEP		3
60254359Sroberto#define DCF7000_FORMAT		"ELV DCF7000"
60354359Sroberto
60454359Sroberto/*
60554359Sroberto * Schmid DCF Receiver Kit
60654359Sroberto *
60754359Sroberto * When the WSDCF clock is operating optimally we want the primary clock
60854359Sroberto * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
60954359Sroberto * structure is set to 290 ms and we compute delays which are at least
61054359Sroberto * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
61154359Sroberto */
61254359Sroberto#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
61354359Sroberto#define WS_POLLCMD	"\163"
61454359Sroberto#define WS_CMDSIZE	1
61554359Sroberto
61654359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
61754359Sroberto
61854359Sroberto#define WSDCF_INIT		poll_init
61954359Sroberto#define WSDCF_POLL		poll_dpoll
62054359Sroberto#define WSDCF_END		0
62154359Sroberto#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
62254359Sroberto#define	WSDCF_ROOTDELAY		0.0	/* 0 */
62354359Sroberto#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
62454359Sroberto#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
62554359Sroberto#define WSDCF_FORMAT		"Schmid"
62654359Sroberto#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
62754359Sroberto#define WSDCF_SPEED		(B1200)
62854359Sroberto#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
62954359Sroberto#define WSDCF_IFLAG		0
63054359Sroberto#define WSDCF_OFLAG		0
63154359Sroberto#define WSDCF_LFLAG		0
63254359Sroberto#define WSDCF_SAMPLES		5
63354359Sroberto#define WSDCF_KEEP		3
63454359Sroberto
63554359Sroberto/*
63654359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants
63754359Sroberto */
63854359Sroberto#define RAWDCF_FLAGS		0
63954359Sroberto#define RAWDCF_ROOTDELAY	0.0 /* 0 */
64054359Sroberto#define RAWDCF_BASEDELAY	0.258
64154359Sroberto#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
64254359Sroberto#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
64354359Sroberto#define RAWDCF_SPEED		(B50)
64454359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
64554359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */
64654359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
64754359Sroberto#else
64854359Sroberto# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
64954359Sroberto#endif
65054359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
65154359Sroberto# define RAWDCF_IFLAG		0
65254359Sroberto#else
65354359Sroberto# define RAWDCF_IFLAG		(IGNPAR)
65454359Sroberto#endif
65554359Sroberto#define RAWDCF_OFLAG		0
65654359Sroberto#define RAWDCF_LFLAG		0
65754359Sroberto#define RAWDCF_SAMPLES		20
65854359Sroberto#define RAWDCF_KEEP		12
65954359Sroberto#define RAWDCF_INIT		0
66054359Sroberto
66154359Sroberto/*
66254359Sroberto * RAW DCF variants
66354359Sroberto */
66454359Sroberto/*
66554359Sroberto * Conrad receiver
66654359Sroberto *
66754359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
66854359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232
66954359Sroberto */
67054359Sroberto#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
67154359Sroberto#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
67254359Sroberto
673182007Sroberto/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
674182007Sroberto#define GUDE_EMC_USB_V20_SPEED            (B4800)
675182007Sroberto#define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
676182007Sroberto#define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
677182007Sroberto
67854359Sroberto/*
67954359Sroberto * TimeBrick receiver
68054359Sroberto */
68154359Sroberto#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
68254359Sroberto#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
68354359Sroberto
68454359Sroberto/*
68554359Sroberto * IGEL:clock receiver
68654359Sroberto */
68754359Sroberto#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
68854359Sroberto#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
68954359Sroberto#define IGELCLOCK_SPEED		(B1200)
69054359Sroberto#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
69154359Sroberto
69254359Sroberto/*
69354359Sroberto * RAWDCF receivers that need to be powered from DTR
69454359Sroberto * (like Expert mouse clock)
69554359Sroberto */
696285612Sdelphijstatic	int	rawdcf_init_1	(struct parseunit *);
69756746Sroberto#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
698285612Sdelphij#define RAWDCFDTRSET75_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)"
69956746Sroberto#define RAWDCFDTRSET_INIT 		rawdcf_init_1
70054359Sroberto
70154359Sroberto/*
70256746Sroberto * RAWDCF receivers that need to be powered from
70356746Sroberto * DTR CLR and RTS SET
70454359Sroberto */
705285612Sdelphijstatic	int	rawdcf_init_2	(struct parseunit *);
70656746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
707285612Sdelphij#define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)"
70856746Sroberto#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
70954359Sroberto
71054359Sroberto/*
71154359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols)
71254359Sroberto */
71354359Sroberto#ifndef TRIM_POLLRATE
71454359Sroberto#define TRIM_POLLRATE	0	/* only true direct polling */
71554359Sroberto#endif
71654359Sroberto
71754359Sroberto#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
71854359Sroberto#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
71954359Sroberto
72054359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
721285612Sdelphijstatic	int	trimbletaip_init	(struct parseunit *);
722285612Sdelphijstatic	void	trimbletaip_event	(struct parseunit *, int);
72354359Sroberto
72454359Sroberto/* query time & UTC correction data */
72554359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
72654359Sroberto
72754359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
728285612Sdelphijstatic	int	trimbletsip_init	(struct parseunit *);
729285612Sdelphijstatic	void	trimbletsip_end   	(struct parseunit *);
730285612Sdelphijstatic	void	trimbletsip_message	(struct parseunit *, parsetime_t *);
731285612Sdelphijstatic	void	trimbletsip_event	(struct parseunit *, int);
73254359Sroberto
73354359Sroberto#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
734182007Sroberto#define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
73554359Sroberto
73654359Sroberto#define TRIMBLETAIP_SPEED	    (B4800)
73754359Sroberto#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
73854359Sroberto#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
73954359Sroberto#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
74054359Sroberto#define TRIMBLETAIP_LFLAG           (0)
74154359Sroberto
74254359Sroberto#define TRIMBLETSIP_SPEED	    (B9600)
74354359Sroberto#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
74454359Sroberto#define TRIMBLETSIP_IFLAG           (IGNBRK)
74554359Sroberto#define TRIMBLETSIP_OFLAG           (0)
74654359Sroberto#define TRIMBLETSIP_LFLAG           (ICANON)
74754359Sroberto
74854359Sroberto#define TRIMBLETSIP_SAMPLES	    5
74954359Sroberto#define TRIMBLETSIP_KEEP	    3
75054359Sroberto#define TRIMBLETAIP_SAMPLES	    5
75154359Sroberto#define TRIMBLETAIP_KEEP	    3
75254359Sroberto
75354359Sroberto#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
75454359Sroberto#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
75554359Sroberto
75654359Sroberto#define TRIMBLETAIP_POLL	    poll_dpoll
75754359Sroberto#define TRIMBLETSIP_POLL	    poll_dpoll
75854359Sroberto
75954359Sroberto#define TRIMBLETAIP_INIT	    trimbletaip_init
76054359Sroberto#define TRIMBLETSIP_INIT	    trimbletsip_init
76154359Sroberto
762285612Sdelphij#define TRIMBLETAIP_EVENT	    trimbletaip_event
76354359Sroberto
764285612Sdelphij#define TRIMBLETSIP_EVENT	    trimbletsip_event
76554359Sroberto#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
76654359Sroberto
76754359Sroberto#define TRIMBLETAIP_END		    0
76854359Sroberto#define TRIMBLETSIP_END		    trimbletsip_end
76954359Sroberto
77054359Sroberto#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
77154359Sroberto#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
77254359Sroberto
77354359Sroberto#define TRIMBLETAIP_ID		    GPS_ID
77454359Sroberto#define TRIMBLETSIP_ID		    GPS_ID
77554359Sroberto
77654359Sroberto#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
77754359Sroberto#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
77854359Sroberto
77954359Sroberto#define TRIMBLETAIP_ROOTDELAY        0x0
78054359Sroberto#define TRIMBLETSIP_ROOTDELAY        0x0
78154359Sroberto
78254359Sroberto#define TRIMBLETAIP_BASEDELAY        0.0
78354359Sroberto#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
78454359Sroberto
78554359Sroberto#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
78654359Sroberto#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
78754359Sroberto
78854359Sroberto#define TRIMBLETAIP_MAXUNSYNC        0
78954359Sroberto#define TRIMBLETSIP_MAXUNSYNC        0
79054359Sroberto
79154359Sroberto#define TRIMBLETAIP_EOL		    '<'
79254359Sroberto
79354359Sroberto/*
79454359Sroberto * RadioCode Clocks RCC 800 receiver
79554359Sroberto */
79654359Sroberto#define RCC_POLLRATE   0       /* only true direct polling */
79754359Sroberto#define RCC_POLLCMD    "\r"
79854359Sroberto#define RCC_CMDSIZE    1
79954359Sroberto
80054359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
80154359Sroberto#define RCC8000_FLAGS		0
80254359Sroberto#define RCC8000_POLL            poll_dpoll
80354359Sroberto#define RCC8000_INIT            poll_init
80454359Sroberto#define RCC8000_END             0
80554359Sroberto#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
80654359Sroberto#define RCC8000_ROOTDELAY       0.0
80754359Sroberto#define RCC8000_BASEDELAY       0.0
80854359Sroberto#define RCC8000_ID              "MSF"
80954359Sroberto#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
81054359Sroberto#define RCC8000_FORMAT          "Radiocode RCC8000"
81154359Sroberto#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
81254359Sroberto#define RCC8000_SPEED		(B2400)
81354359Sroberto#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
81454359Sroberto#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
81554359Sroberto#define RCC8000_OFLAG           0
81654359Sroberto#define RCC8000_LFLAG           0
81754359Sroberto#define RCC8000_SAMPLES         5
81854359Sroberto#define RCC8000_KEEP	        3
81954359Sroberto
82054359Sroberto/*
821285612Sdelphij * Hopf Radio clock 6021 Format
82254359Sroberto *
82354359Sroberto */
82454359Sroberto#define HOPF6021_ROOTDELAY	0.0
82554359Sroberto#define HOPF6021_BASEDELAY	0.0
82654359Sroberto#define HOPF6021_DESCRIPTION	"HOPF 6021"
82754359Sroberto#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
82854359Sroberto#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
82954359Sroberto#define HOPF6021_SPEED         (B9600)
83054359Sroberto#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
83154359Sroberto#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
83254359Sroberto#define HOPF6021_OFLAG		0
83354359Sroberto#define HOPF6021_LFLAG		0
83454359Sroberto#define HOPF6021_FLAGS          0
83554359Sroberto#define HOPF6021_SAMPLES        5
83654359Sroberto#define HOPF6021_KEEP	        3
83754359Sroberto
83854359Sroberto/*
83954359Sroberto * Diem's Computime Radio Clock Receiver
84054359Sroberto */
84154359Sroberto#define COMPUTIME_FLAGS       0
84254359Sroberto#define COMPUTIME_ROOTDELAY   0.0
84354359Sroberto#define COMPUTIME_BASEDELAY   0.0
84454359Sroberto#define COMPUTIME_ID          DCF_ID
84554359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
84654359Sroberto#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
84754359Sroberto#define COMPUTIME_TYPE        DCF_TYPE
84854359Sroberto#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
84954359Sroberto#define COMPUTIME_SPEED       (B9600)
85054359Sroberto#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
85154359Sroberto#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
85254359Sroberto#define COMPUTIME_OFLAG       0
85354359Sroberto#define COMPUTIME_LFLAG       0
85454359Sroberto#define COMPUTIME_SAMPLES     5
85554359Sroberto#define COMPUTIME_KEEP        3
85654359Sroberto
85754359Sroberto/*
85854359Sroberto * Varitext Radio Clock Receiver
85954359Sroberto */
86054359Sroberto#define VARITEXT_FLAGS       0
86154359Sroberto#define VARITEXT_ROOTDELAY   0.0
86254359Sroberto#define VARITEXT_BASEDELAY   0.0
86354359Sroberto#define VARITEXT_ID          "MSF"
86454359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver"
86554359Sroberto#define VARITEXT_FORMAT      "Varitext Radio Clock"
86654359Sroberto#define VARITEXT_TYPE        DCF_TYPE
86754359Sroberto#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
86854359Sroberto#define VARITEXT_SPEED       (B9600)
86954359Sroberto#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
87054359Sroberto#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
87154359Sroberto#define VARITEXT_OFLAG       0
87254359Sroberto#define VARITEXT_LFLAG       0
87354359Sroberto#define VARITEXT_SAMPLES     32
87454359Sroberto#define VARITEXT_KEEP        20
87554359Sroberto
876285612Sdelphij/*
877285612Sdelphij * SEL240x Satellite Sychronized Clock
878285612Sdelphij */
879285612Sdelphij#define SEL240X_POLLRATE	0 /* only true direct polling */
880285612Sdelphij#define SEL240X_POLLCMD		"BUB8"
881285612Sdelphij#define SEL240X_CMDSIZE		4
882285612Sdelphij
883285612Sdelphijstatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE,
884285612Sdelphij	                                SEL240X_POLLCMD,
885285612Sdelphij					SEL240X_CMDSIZE };
886285612Sdelphij#define SEL240X_FLAGS		(PARSE_F_PPSONSECOND)
887285612Sdelphij#define SEL240X_POLL		poll_dpoll
888285612Sdelphij#define SEL240X_INIT		poll_init
889285612Sdelphij#define SEL240X_END		0
890285612Sdelphij#define SEL240X_DATA            ((void *)(&sel240x_pollinfo))
891285612Sdelphij#define SEL240X_ROOTDELAY	0.0
892285612Sdelphij#define SEL240X_BASEDELAY	0.0
893285612Sdelphij#define SEL240X_ID		GPS_ID
894285612Sdelphij#define SEL240X_DESCRIPTION	"SEL240x Satellite Synchronized Clock"
895285612Sdelphij#define SEL240X_FORMAT		"SEL B8"
896285612Sdelphij#define SEL240X_MAXUNSYNC	60*60*12 /* only trust clock for 12 hours */
897285612Sdelphij#define SEL240X_SPEED		(B9600)
898285612Sdelphij#define SEL240X_CFLAG		(CS8|CREAD|CLOCAL)
899285612Sdelphij#define SEL240X_IFLAG		(IGNBRK|IGNPAR)
900285612Sdelphij#define SEL240X_OFLAG		(0)
901285612Sdelphij#define SEL240X_LFLAG		(0)
902285612Sdelphij#define SEL240X_SAMPLES		5
903285612Sdelphij#define SEL240X_KEEP		3
904285612Sdelphij
90554359Srobertostatic struct parse_clockinfo
90654359Sroberto{
907285612Sdelphij	u_long  cl_flags;		/* operation flags (PPS interpretation, trust handling) */
908285612Sdelphij  void  (*cl_poll)    (struct parseunit *);			/* active poll routine */
909285612Sdelphij  int   (*cl_init)    (struct parseunit *);			/* active poll init routine */
910285612Sdelphij  void  (*cl_event)   (struct parseunit *, int);		/* special event handling (e.g. reset clock) */
911285612Sdelphij  void  (*cl_end)     (struct parseunit *);			/* active poll end routine */
912285612Sdelphij  void  (*cl_message) (struct parseunit *, parsetime_t *);	/* process a lower layer message */
91354359Sroberto	void   *cl_data;		/* local data area for "poll" mechanism */
91454359Sroberto	double    cl_rootdelay;		/* rootdelay */
91554359Sroberto	double    cl_basedelay;		/* current offset by which the RS232
91654359Sroberto				time code is delayed from the actual time */
91754359Sroberto	const char *cl_id;		/* ID code */
91854359Sroberto	const char *cl_description;		/* device name */
91954359Sroberto	const char *cl_format;		/* fixed format */
92054359Sroberto	u_char  cl_type;		/* clock type (ntp control) */
921132451Sroberto	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
92254359Sroberto	u_long  cl_speed;		/* terminal input & output baudrate */
92354359Sroberto	u_long  cl_cflag;             /* terminal control flags */
92454359Sroberto	u_long  cl_iflag;             /* terminal input flags */
92554359Sroberto	u_long  cl_oflag;             /* terminal output flags */
92654359Sroberto	u_long  cl_lflag;             /* terminal local flags */
92754359Sroberto	u_long  cl_samples;	      /* samples for median filter */
92854359Sroberto	u_long  cl_keep;              /* samples for median filter to keep */
92954359Sroberto} parse_clockinfo[] =
93054359Sroberto{
93154359Sroberto	{				/* mode 0 */
93254359Sroberto		MBG_FLAGS,
93354359Sroberto		NO_POLL,
93454359Sroberto		NO_INIT,
93554359Sroberto		NO_EVENT,
93654359Sroberto		NO_END,
93754359Sroberto		NO_MESSAGE,
938182007Sroberto		NO_LCLDATA,
93954359Sroberto		DCFPZF535_ROOTDELAY,
94054359Sroberto		DCFPZF535_BASEDELAY,
94154359Sroberto		DCF_P_ID,
94254359Sroberto		DCFPZF535_DESCRIPTION,
94354359Sroberto		DCFPZF535_FORMAT,
94454359Sroberto		DCF_TYPE,
94554359Sroberto		DCFPZF535_MAXUNSYNC,
94654359Sroberto		DCFPZF535_SPEED,
94754359Sroberto		DCFPZF535_CFLAG,
94854359Sroberto		DCFPZF535_IFLAG,
94954359Sroberto		DCFPZF535_OFLAG,
95054359Sroberto		DCFPZF535_LFLAG,
95154359Sroberto		DCFPZF535_SAMPLES,
95254359Sroberto		DCFPZF535_KEEP
95354359Sroberto	},
95454359Sroberto	{				/* mode 1 */
95554359Sroberto		MBG_FLAGS,
95654359Sroberto		NO_POLL,
95754359Sroberto		NO_INIT,
95854359Sroberto		NO_EVENT,
95954359Sroberto		NO_END,
96054359Sroberto		NO_MESSAGE,
961182007Sroberto		NO_LCLDATA,
96254359Sroberto		DCFPZF535OCXO_ROOTDELAY,
96354359Sroberto		DCFPZF535OCXO_BASEDELAY,
96454359Sroberto		DCF_P_ID,
96554359Sroberto		DCFPZF535OCXO_DESCRIPTION,
96654359Sroberto		DCFPZF535OCXO_FORMAT,
96754359Sroberto		DCF_TYPE,
96854359Sroberto		DCFPZF535OCXO_MAXUNSYNC,
96954359Sroberto		DCFPZF535OCXO_SPEED,
97054359Sroberto		DCFPZF535OCXO_CFLAG,
97154359Sroberto		DCFPZF535OCXO_IFLAG,
97254359Sroberto		DCFPZF535OCXO_OFLAG,
97354359Sroberto		DCFPZF535OCXO_LFLAG,
97454359Sroberto		DCFPZF535OCXO_SAMPLES,
97554359Sroberto		DCFPZF535OCXO_KEEP
97654359Sroberto	},
97754359Sroberto	{				/* mode 2 */
97854359Sroberto		MBG_FLAGS,
97954359Sroberto		NO_POLL,
98054359Sroberto		NO_INIT,
98154359Sroberto		NO_EVENT,
98254359Sroberto		NO_END,
98354359Sroberto		NO_MESSAGE,
984182007Sroberto		NO_LCLDATA,
98554359Sroberto		DCFUA31_ROOTDELAY,
98654359Sroberto		DCFUA31_BASEDELAY,
98754359Sroberto		DCF_A_ID,
98854359Sroberto		DCFUA31_DESCRIPTION,
98954359Sroberto		DCFUA31_FORMAT,
99054359Sroberto		DCF_TYPE,
99154359Sroberto		DCFUA31_MAXUNSYNC,
99254359Sroberto		DCFUA31_SPEED,
99354359Sroberto		DCFUA31_CFLAG,
99454359Sroberto		DCFUA31_IFLAG,
99554359Sroberto		DCFUA31_OFLAG,
99654359Sroberto		DCFUA31_LFLAG,
99754359Sroberto		DCFUA31_SAMPLES,
99854359Sroberto		DCFUA31_KEEP
99954359Sroberto	},
100054359Sroberto	{				/* mode 3 */
100154359Sroberto		MBG_FLAGS,
100254359Sroberto		NO_POLL,
100354359Sroberto		NO_INIT,
100454359Sroberto		NO_EVENT,
100554359Sroberto		NO_END,
100654359Sroberto		NO_MESSAGE,
1007182007Sroberto		NO_LCLDATA,
100854359Sroberto		DCF7000_ROOTDELAY,
100954359Sroberto		DCF7000_BASEDELAY,
101054359Sroberto		DCF_A_ID,
101154359Sroberto		DCF7000_DESCRIPTION,
101254359Sroberto		DCF7000_FORMAT,
101354359Sroberto		DCF_TYPE,
101454359Sroberto		DCF7000_MAXUNSYNC,
101554359Sroberto		DCF7000_SPEED,
101654359Sroberto		DCF7000_CFLAG,
101754359Sroberto		DCF7000_IFLAG,
101854359Sroberto		DCF7000_OFLAG,
101954359Sroberto		DCF7000_LFLAG,
102054359Sroberto		DCF7000_SAMPLES,
102154359Sroberto		DCF7000_KEEP
102254359Sroberto	},
102354359Sroberto	{				/* mode 4 */
102454359Sroberto		NO_CL_FLAGS,
102554359Sroberto		WSDCF_POLL,
102654359Sroberto		WSDCF_INIT,
102754359Sroberto		NO_EVENT,
102854359Sroberto		WSDCF_END,
102954359Sroberto		NO_MESSAGE,
103054359Sroberto		WSDCF_DATA,
103154359Sroberto		WSDCF_ROOTDELAY,
103254359Sroberto		WSDCF_BASEDELAY,
103354359Sroberto		DCF_A_ID,
103454359Sroberto		WSDCF_DESCRIPTION,
103554359Sroberto		WSDCF_FORMAT,
103654359Sroberto		DCF_TYPE,
103754359Sroberto		WSDCF_MAXUNSYNC,
103854359Sroberto		WSDCF_SPEED,
103954359Sroberto		WSDCF_CFLAG,
104054359Sroberto		WSDCF_IFLAG,
104154359Sroberto		WSDCF_OFLAG,
104254359Sroberto		WSDCF_LFLAG,
104354359Sroberto		WSDCF_SAMPLES,
104454359Sroberto		WSDCF_KEEP
104554359Sroberto	},
104654359Sroberto	{				/* mode 5 */
104754359Sroberto		RAWDCF_FLAGS,
104854359Sroberto		NO_POLL,
104954359Sroberto		RAWDCF_INIT,
105054359Sroberto		NO_EVENT,
105154359Sroberto		NO_END,
105254359Sroberto		NO_MESSAGE,
1053182007Sroberto		NO_LCLDATA,
105454359Sroberto		RAWDCF_ROOTDELAY,
105554359Sroberto		CONRAD_BASEDELAY,
105654359Sroberto		DCF_A_ID,
105754359Sroberto		CONRAD_DESCRIPTION,
105854359Sroberto		RAWDCF_FORMAT,
105954359Sroberto		DCF_TYPE,
106054359Sroberto		RAWDCF_MAXUNSYNC,
106154359Sroberto		RAWDCF_SPEED,
106254359Sroberto		RAWDCF_CFLAG,
106354359Sroberto		RAWDCF_IFLAG,
106454359Sroberto		RAWDCF_OFLAG,
106554359Sroberto		RAWDCF_LFLAG,
106654359Sroberto		RAWDCF_SAMPLES,
106754359Sroberto		RAWDCF_KEEP
106854359Sroberto	},
106954359Sroberto	{				/* mode 6 */
107054359Sroberto		RAWDCF_FLAGS,
107154359Sroberto		NO_POLL,
107254359Sroberto		RAWDCF_INIT,
107354359Sroberto		NO_EVENT,
107454359Sroberto		NO_END,
107554359Sroberto		NO_MESSAGE,
1076182007Sroberto		NO_LCLDATA,
107754359Sroberto		RAWDCF_ROOTDELAY,
107854359Sroberto		TIMEBRICK_BASEDELAY,
107954359Sroberto		DCF_A_ID,
108054359Sroberto		TIMEBRICK_DESCRIPTION,
108154359Sroberto		RAWDCF_FORMAT,
108254359Sroberto		DCF_TYPE,
108354359Sroberto		RAWDCF_MAXUNSYNC,
108454359Sroberto		RAWDCF_SPEED,
108554359Sroberto		RAWDCF_CFLAG,
108654359Sroberto		RAWDCF_IFLAG,
108754359Sroberto		RAWDCF_OFLAG,
108854359Sroberto		RAWDCF_LFLAG,
108954359Sroberto		RAWDCF_SAMPLES,
109054359Sroberto		RAWDCF_KEEP
109154359Sroberto	},
109254359Sroberto	{				/* mode 7 */
109354359Sroberto		MBG_FLAGS,
109454359Sroberto		GPS16X_POLL,
109554359Sroberto		GPS16X_INIT,
109654359Sroberto		NO_EVENT,
109754359Sroberto		GPS16X_END,
109854359Sroberto		GPS16X_MESSAGE,
109954359Sroberto		GPS16X_DATA,
110054359Sroberto		GPS16X_ROOTDELAY,
110154359Sroberto		GPS16X_BASEDELAY,
110254359Sroberto		GPS16X_ID,
110354359Sroberto		GPS16X_DESCRIPTION,
110454359Sroberto		GPS16X_FORMAT,
110554359Sroberto		GPS_TYPE,
110654359Sroberto		GPS16X_MAXUNSYNC,
110754359Sroberto		GPS16X_SPEED,
110854359Sroberto		GPS16X_CFLAG,
110954359Sroberto		GPS16X_IFLAG,
111054359Sroberto		GPS16X_OFLAG,
111154359Sroberto		GPS16X_LFLAG,
111254359Sroberto		GPS16X_SAMPLES,
111354359Sroberto		GPS16X_KEEP
111454359Sroberto	},
111554359Sroberto	{				/* mode 8 */
111654359Sroberto		RAWDCF_FLAGS,
111754359Sroberto		NO_POLL,
111854359Sroberto		NO_INIT,
111954359Sroberto		NO_EVENT,
112054359Sroberto		NO_END,
112154359Sroberto		NO_MESSAGE,
1122182007Sroberto		NO_LCLDATA,
112354359Sroberto		RAWDCF_ROOTDELAY,
112454359Sroberto		IGELCLOCK_BASEDELAY,
112554359Sroberto		DCF_A_ID,
112654359Sroberto		IGELCLOCK_DESCRIPTION,
112754359Sroberto		RAWDCF_FORMAT,
112854359Sroberto		DCF_TYPE,
112954359Sroberto		RAWDCF_MAXUNSYNC,
113054359Sroberto		IGELCLOCK_SPEED,
113154359Sroberto		IGELCLOCK_CFLAG,
113254359Sroberto		RAWDCF_IFLAG,
113354359Sroberto		RAWDCF_OFLAG,
113454359Sroberto		RAWDCF_LFLAG,
113554359Sroberto		RAWDCF_SAMPLES,
113654359Sroberto		RAWDCF_KEEP
113754359Sroberto	},
113854359Sroberto	{				/* mode 9 */
113954359Sroberto		TRIMBLETAIP_FLAGS,
114054359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
114154359Sroberto		NO_POLL,
114254359Sroberto#else
114354359Sroberto		TRIMBLETAIP_POLL,
114454359Sroberto#endif
114554359Sroberto		TRIMBLETAIP_INIT,
114654359Sroberto		TRIMBLETAIP_EVENT,
114754359Sroberto		TRIMBLETAIP_END,
114854359Sroberto		NO_MESSAGE,
114954359Sroberto		TRIMBLETAIP_DATA,
115054359Sroberto		TRIMBLETAIP_ROOTDELAY,
115154359Sroberto		TRIMBLETAIP_BASEDELAY,
115254359Sroberto		TRIMBLETAIP_ID,
115354359Sroberto		TRIMBLETAIP_DESCRIPTION,
115454359Sroberto		TRIMBLETAIP_FORMAT,
115554359Sroberto		GPS_TYPE,
115654359Sroberto		TRIMBLETAIP_MAXUNSYNC,
115754359Sroberto		TRIMBLETAIP_SPEED,
115854359Sroberto		TRIMBLETAIP_CFLAG,
115954359Sroberto		TRIMBLETAIP_IFLAG,
116054359Sroberto		TRIMBLETAIP_OFLAG,
116154359Sroberto		TRIMBLETAIP_LFLAG,
116254359Sroberto		TRIMBLETAIP_SAMPLES,
116354359Sroberto		TRIMBLETAIP_KEEP
116454359Sroberto	},
116554359Sroberto	{				/* mode 10 */
116654359Sroberto		TRIMBLETSIP_FLAGS,
116754359Sroberto#if TRIM_POLLRATE		/* DHD940515: Allow user config */
116854359Sroberto		NO_POLL,
116954359Sroberto#else
117054359Sroberto		TRIMBLETSIP_POLL,
117154359Sroberto#endif
117254359Sroberto		TRIMBLETSIP_INIT,
117354359Sroberto		TRIMBLETSIP_EVENT,
117454359Sroberto		TRIMBLETSIP_END,
117554359Sroberto		TRIMBLETSIP_MESSAGE,
117654359Sroberto		TRIMBLETSIP_DATA,
117754359Sroberto		TRIMBLETSIP_ROOTDELAY,
117854359Sroberto		TRIMBLETSIP_BASEDELAY,
117954359Sroberto		TRIMBLETSIP_ID,
118054359Sroberto		TRIMBLETSIP_DESCRIPTION,
118154359Sroberto		TRIMBLETSIP_FORMAT,
118254359Sroberto		GPS_TYPE,
118354359Sroberto		TRIMBLETSIP_MAXUNSYNC,
118454359Sroberto		TRIMBLETSIP_SPEED,
118554359Sroberto		TRIMBLETSIP_CFLAG,
118654359Sroberto		TRIMBLETSIP_IFLAG,
118754359Sroberto		TRIMBLETSIP_OFLAG,
118854359Sroberto		TRIMBLETSIP_LFLAG,
118954359Sroberto		TRIMBLETSIP_SAMPLES,
119054359Sroberto		TRIMBLETSIP_KEEP
119154359Sroberto	},
119254359Sroberto	{                             /* mode 11 */
119354359Sroberto		NO_CL_FLAGS,
119454359Sroberto		RCC8000_POLL,
119554359Sroberto		RCC8000_INIT,
119654359Sroberto		NO_EVENT,
119754359Sroberto		RCC8000_END,
119854359Sroberto		NO_MESSAGE,
119954359Sroberto		RCC8000_DATA,
120054359Sroberto		RCC8000_ROOTDELAY,
120154359Sroberto		RCC8000_BASEDELAY,
120254359Sroberto		RCC8000_ID,
120354359Sroberto		RCC8000_DESCRIPTION,
120454359Sroberto		RCC8000_FORMAT,
120554359Sroberto		DCF_TYPE,
120654359Sroberto		RCC8000_MAXUNSYNC,
120754359Sroberto		RCC8000_SPEED,
120854359Sroberto		RCC8000_CFLAG,
120954359Sroberto		RCC8000_IFLAG,
121054359Sroberto		RCC8000_OFLAG,
121154359Sroberto		RCC8000_LFLAG,
121254359Sroberto		RCC8000_SAMPLES,
121354359Sroberto		RCC8000_KEEP
121454359Sroberto	},
121554359Sroberto	{                             /* mode 12 */
121654359Sroberto		HOPF6021_FLAGS,
1217285612Sdelphij		NO_POLL,
121854359Sroberto		NO_INIT,
121954359Sroberto		NO_EVENT,
122054359Sroberto		NO_END,
122154359Sroberto		NO_MESSAGE,
1222182007Sroberto		NO_LCLDATA,
122354359Sroberto		HOPF6021_ROOTDELAY,
122454359Sroberto		HOPF6021_BASEDELAY,
122554359Sroberto		DCF_ID,
122654359Sroberto		HOPF6021_DESCRIPTION,
122754359Sroberto		HOPF6021_FORMAT,
122854359Sroberto		DCF_TYPE,
122954359Sroberto		HOPF6021_MAXUNSYNC,
123054359Sroberto		HOPF6021_SPEED,
123154359Sroberto		HOPF6021_CFLAG,
123254359Sroberto		HOPF6021_IFLAG,
123354359Sroberto		HOPF6021_OFLAG,
123454359Sroberto		HOPF6021_LFLAG,
123554359Sroberto		HOPF6021_SAMPLES,
123654359Sroberto		HOPF6021_KEEP
123754359Sroberto	},
123854359Sroberto	{                            /* mode 13 */
123954359Sroberto		COMPUTIME_FLAGS,
124054359Sroberto		NO_POLL,
124154359Sroberto		NO_INIT,
124254359Sroberto		NO_EVENT,
124354359Sroberto		NO_END,
124454359Sroberto		NO_MESSAGE,
1245182007Sroberto		NO_LCLDATA,
124654359Sroberto		COMPUTIME_ROOTDELAY,
124754359Sroberto		COMPUTIME_BASEDELAY,
124854359Sroberto		COMPUTIME_ID,
124954359Sroberto		COMPUTIME_DESCRIPTION,
125054359Sroberto		COMPUTIME_FORMAT,
125154359Sroberto		COMPUTIME_TYPE,
125254359Sroberto		COMPUTIME_MAXUNSYNC,
125354359Sroberto		COMPUTIME_SPEED,
125454359Sroberto		COMPUTIME_CFLAG,
125554359Sroberto		COMPUTIME_IFLAG,
125654359Sroberto		COMPUTIME_OFLAG,
125754359Sroberto		COMPUTIME_LFLAG,
125854359Sroberto		COMPUTIME_SAMPLES,
125954359Sroberto		COMPUTIME_KEEP
126054359Sroberto	},
126154359Sroberto	{				/* mode 14 */
126254359Sroberto		RAWDCF_FLAGS,
126354359Sroberto		NO_POLL,
126456746Sroberto		RAWDCFDTRSET_INIT,
126554359Sroberto		NO_EVENT,
126654359Sroberto		NO_END,
126754359Sroberto		NO_MESSAGE,
1268182007Sroberto		NO_LCLDATA,
126954359Sroberto		RAWDCF_ROOTDELAY,
127054359Sroberto		RAWDCF_BASEDELAY,
127154359Sroberto		DCF_A_ID,
127256746Sroberto		RAWDCFDTRSET_DESCRIPTION,
127354359Sroberto		RAWDCF_FORMAT,
127454359Sroberto		DCF_TYPE,
127554359Sroberto		RAWDCF_MAXUNSYNC,
127654359Sroberto		RAWDCF_SPEED,
127754359Sroberto		RAWDCF_CFLAG,
127854359Sroberto		RAWDCF_IFLAG,
127954359Sroberto		RAWDCF_OFLAG,
128054359Sroberto		RAWDCF_LFLAG,
128154359Sroberto		RAWDCF_SAMPLES,
128254359Sroberto		RAWDCF_KEEP
128354359Sroberto	},
128454359Sroberto	{				/* mode 15 */
128556746Sroberto		0,				/* operation flags (io modes) */
128682498Sroberto  		NO_POLL,			/* active poll routine */
128782498Sroberto		NO_INIT,			/* active poll init routine */
128856746Sroberto  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
128956746Sroberto  		NO_END,				/* active poll end routine */
129056746Sroberto  		NO_MESSAGE,			/* process a lower layer message */
1291182007Sroberto		NO_LCLDATA,			/* local data area for "poll" mechanism */
129256746Sroberto		0,				/* rootdelay */
129382498Sroberto		11.0 /* bits */ / 9600,		/* current offset by which the RS232
129456746Sroberto				           	time code is delayed from the actual time */
129556746Sroberto		DCF_ID,				/* ID code */
129656746Sroberto		"WHARTON 400A Series clock",	/* device name */
129782498Sroberto		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
129856746Sroberto			/* Must match a format-name in a libparse/clk_xxx.c file */
129956746Sroberto		DCF_TYPE,			/* clock type (ntp control) */
1300132451Sroberto		(1*60*60),		        /* time to trust oscillator after losing synch */
130156746Sroberto		B9600,				/* terminal input & output baudrate */
130256746Sroberto		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
130356746Sroberto		0,				/* terminal input flags */
130456746Sroberto		0,				/* terminal output flags */
130556746Sroberto		0,				/* terminal local flags */
130656746Sroberto		5,				/* samples for median filter */
130756746Sroberto		3,				/* samples for median filter to keep */
130854359Sroberto	},
130956746Sroberto	{				/* mode 16 - RAWDCF RTS set, DTR clr */
131056746Sroberto		RAWDCF_FLAGS,
131156746Sroberto		NO_POLL,
131256746Sroberto		RAWDCFDTRCLRRTSSET_INIT,
131356746Sroberto		NO_EVENT,
131456746Sroberto		NO_END,
131556746Sroberto		NO_MESSAGE,
1316182007Sroberto		NO_LCLDATA,
131756746Sroberto		RAWDCF_ROOTDELAY,
131856746Sroberto		RAWDCF_BASEDELAY,
131956746Sroberto		DCF_A_ID,
132056746Sroberto		RAWDCFDTRCLRRTSSET_DESCRIPTION,
132156746Sroberto		RAWDCF_FORMAT,
132256746Sroberto		DCF_TYPE,
132356746Sroberto		RAWDCF_MAXUNSYNC,
132456746Sroberto		RAWDCF_SPEED,
132556746Sroberto		RAWDCF_CFLAG,
132656746Sroberto		RAWDCF_IFLAG,
132756746Sroberto		RAWDCF_OFLAG,
132856746Sroberto		RAWDCF_LFLAG,
132956746Sroberto		RAWDCF_SAMPLES,
133056746Sroberto		RAWDCF_KEEP
133156746Sroberto	},
133256746Sroberto        {                            /* mode 17 */
133354359Sroberto                VARITEXT_FLAGS,
133454359Sroberto                NO_POLL,
133554359Sroberto                NO_INIT,
133654359Sroberto                NO_EVENT,
133754359Sroberto                NO_END,
133854359Sroberto                NO_MESSAGE,
1339182007Sroberto                NO_LCLDATA,
134054359Sroberto                VARITEXT_ROOTDELAY,
134154359Sroberto                VARITEXT_BASEDELAY,
134254359Sroberto                VARITEXT_ID,
134354359Sroberto                VARITEXT_DESCRIPTION,
134454359Sroberto                VARITEXT_FORMAT,
134554359Sroberto                VARITEXT_TYPE,
134654359Sroberto                VARITEXT_MAXUNSYNC,
134754359Sroberto                VARITEXT_SPEED,
134854359Sroberto                VARITEXT_CFLAG,
134954359Sroberto                VARITEXT_IFLAG,
135054359Sroberto                VARITEXT_OFLAG,
135154359Sroberto                VARITEXT_LFLAG,
135254359Sroberto                VARITEXT_SAMPLES,
135354359Sroberto                VARITEXT_KEEP
1354182007Sroberto        },
1355182007Sroberto	{				/* mode 18 */
1356182007Sroberto		MBG_FLAGS,
1357182007Sroberto		NO_POLL,
1358182007Sroberto		NO_INIT,
1359182007Sroberto		NO_EVENT,
1360182007Sroberto		GPS16X_END,
1361182007Sroberto		GPS16X_MESSAGE,
1362182007Sroberto		GPS16X_DATA,
1363182007Sroberto		GPS16X_ROOTDELAY,
1364182007Sroberto		GPS16X_BASEDELAY,
1365182007Sroberto		GPS16X_ID,
1366182007Sroberto		GPS16X_DESCRIPTION,
1367182007Sroberto		GPS16X_FORMAT,
1368182007Sroberto		GPS_TYPE,
1369182007Sroberto		GPS16X_MAXUNSYNC,
1370182007Sroberto		GPS16X_SPEED,
1371182007Sroberto		GPS16X_CFLAG,
1372182007Sroberto		GPS16X_IFLAG,
1373182007Sroberto		GPS16X_OFLAG,
1374182007Sroberto		GPS16X_LFLAG,
1375182007Sroberto		GPS16X_SAMPLES,
1376182007Sroberto		GPS16X_KEEP
1377182007Sroberto	},
1378182007Sroberto	{				/* mode 19 */
1379182007Sroberto		RAWDCF_FLAGS,
1380182007Sroberto		NO_POLL,
1381182007Sroberto		RAWDCF_INIT,
1382182007Sroberto		NO_EVENT,
1383182007Sroberto		NO_END,
1384182007Sroberto		NO_MESSAGE,
1385182007Sroberto		NO_LCLDATA,
1386182007Sroberto		RAWDCF_ROOTDELAY,
1387182007Sroberto		GUDE_EMC_USB_V20_BASEDELAY,
1388182007Sroberto		DCF_A_ID,
1389182007Sroberto		GUDE_EMC_USB_V20_DESCRIPTION,
1390182007Sroberto		RAWDCF_FORMAT,
1391182007Sroberto		DCF_TYPE,
1392182007Sroberto		RAWDCF_MAXUNSYNC,
1393182007Sroberto		GUDE_EMC_USB_V20_SPEED,
1394182007Sroberto		RAWDCF_CFLAG,
1395182007Sroberto		RAWDCF_IFLAG,
1396182007Sroberto		RAWDCF_OFLAG,
1397182007Sroberto		RAWDCF_LFLAG,
1398182007Sroberto		RAWDCF_SAMPLES,
1399182007Sroberto		RAWDCF_KEEP
1400182007Sroberto	},
1401285612Sdelphij	{				/* mode 20, like mode 14 but driven by 75 baud */
1402285612Sdelphij		RAWDCF_FLAGS,
1403285612Sdelphij		NO_POLL,
1404285612Sdelphij		RAWDCFDTRSET_INIT,
1405285612Sdelphij		NO_EVENT,
1406285612Sdelphij		NO_END,
1407285612Sdelphij		NO_MESSAGE,
1408285612Sdelphij		NO_LCLDATA,
1409285612Sdelphij		RAWDCF_ROOTDELAY,
1410285612Sdelphij		RAWDCF_BASEDELAY,
1411285612Sdelphij		DCF_A_ID,
1412285612Sdelphij		RAWDCFDTRSET75_DESCRIPTION,
1413285612Sdelphij		RAWDCF_FORMAT,
1414285612Sdelphij		DCF_TYPE,
1415285612Sdelphij		RAWDCF_MAXUNSYNC,
1416285612Sdelphij		B75,
1417285612Sdelphij		RAWDCF_CFLAG,
1418285612Sdelphij		RAWDCF_IFLAG,
1419285612Sdelphij		RAWDCF_OFLAG,
1420285612Sdelphij		RAWDCF_LFLAG,
1421285612Sdelphij		RAWDCF_SAMPLES,
1422285612Sdelphij		RAWDCF_KEEP
1423285612Sdelphij	},
1424285612Sdelphij	{				/* mode 21, like mode 16 but driven by 75 baud
1425285612Sdelphij					 - RAWDCF RTS set, DTR clr */
1426285612Sdelphij		RAWDCF_FLAGS,
1427285612Sdelphij		NO_POLL,
1428285612Sdelphij		RAWDCFDTRCLRRTSSET_INIT,
1429285612Sdelphij		NO_EVENT,
1430285612Sdelphij		NO_END,
1431285612Sdelphij		NO_MESSAGE,
1432285612Sdelphij		NO_LCLDATA,
1433285612Sdelphij		RAWDCF_ROOTDELAY,
1434285612Sdelphij		RAWDCF_BASEDELAY,
1435285612Sdelphij		DCF_A_ID,
1436285612Sdelphij		RAWDCFDTRCLRRTSSET75_DESCRIPTION,
1437285612Sdelphij		RAWDCF_FORMAT,
1438285612Sdelphij		DCF_TYPE,
1439285612Sdelphij		RAWDCF_MAXUNSYNC,
1440285612Sdelphij		B75,
1441285612Sdelphij		RAWDCF_CFLAG,
1442285612Sdelphij		RAWDCF_IFLAG,
1443285612Sdelphij		RAWDCF_OFLAG,
1444285612Sdelphij		RAWDCF_LFLAG,
1445285612Sdelphij		RAWDCF_SAMPLES,
1446285612Sdelphij		RAWDCF_KEEP
1447285612Sdelphij	},
1448285612Sdelphij	{				/* mode 22 - like 2 with POWERUP trust */
1449285612Sdelphij		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1450285612Sdelphij		NO_POLL,
1451285612Sdelphij		NO_INIT,
1452285612Sdelphij		NO_EVENT,
1453285612Sdelphij		NO_END,
1454285612Sdelphij		NO_MESSAGE,
1455285612Sdelphij		NO_LCLDATA,
1456285612Sdelphij		DCFUA31_ROOTDELAY,
1457285612Sdelphij		DCFUA31_BASEDELAY,
1458285612Sdelphij		DCF_A_ID,
1459285612Sdelphij		DCFUA31_DESCRIPTION,
1460285612Sdelphij		DCFUA31_FORMAT,
1461285612Sdelphij		DCF_TYPE,
1462285612Sdelphij		DCFUA31_MAXUNSYNC,
1463285612Sdelphij		DCFUA31_SPEED,
1464285612Sdelphij		DCFUA31_CFLAG,
1465285612Sdelphij		DCFUA31_IFLAG,
1466285612Sdelphij		DCFUA31_OFLAG,
1467285612Sdelphij		DCFUA31_LFLAG,
1468285612Sdelphij		DCFUA31_SAMPLES,
1469285612Sdelphij		DCFUA31_KEEP
1470285612Sdelphij	},
1471285612Sdelphij	{				/* mode 23 - like 7 with POWERUP trust */
1472285612Sdelphij		MBG_FLAGS | PARSE_F_POWERUPTRUST,
1473285612Sdelphij		GPS16X_POLL,
1474285612Sdelphij		GPS16X_INIT,
1475285612Sdelphij		NO_EVENT,
1476285612Sdelphij		GPS16X_END,
1477285612Sdelphij		GPS16X_MESSAGE,
1478285612Sdelphij		GPS16X_DATA,
1479285612Sdelphij		GPS16X_ROOTDELAY,
1480285612Sdelphij		GPS16X_BASEDELAY,
1481285612Sdelphij		GPS16X_ID,
1482285612Sdelphij		GPS16X_DESCRIPTION,
1483285612Sdelphij		GPS16X_FORMAT,
1484285612Sdelphij		GPS_TYPE,
1485285612Sdelphij		GPS16X_MAXUNSYNC,
1486285612Sdelphij		GPS16X_SPEED,
1487285612Sdelphij		GPS16X_CFLAG,
1488285612Sdelphij		GPS16X_IFLAG,
1489285612Sdelphij		GPS16X_OFLAG,
1490285612Sdelphij		GPS16X_LFLAG,
1491285612Sdelphij		GPS16X_SAMPLES,
1492285612Sdelphij		GPS16X_KEEP
1493285612Sdelphij	},
1494285612Sdelphij	{				/* mode 24 */
1495285612Sdelphij		SEL240X_FLAGS,
1496285612Sdelphij		SEL240X_POLL,
1497285612Sdelphij		SEL240X_INIT,
1498285612Sdelphij		NO_EVENT,
1499285612Sdelphij		SEL240X_END,
1500285612Sdelphij		NO_MESSAGE,
1501285612Sdelphij		SEL240X_DATA,
1502285612Sdelphij		SEL240X_ROOTDELAY,
1503285612Sdelphij		SEL240X_BASEDELAY,
1504285612Sdelphij		SEL240X_ID,
1505285612Sdelphij		SEL240X_DESCRIPTION,
1506285612Sdelphij		SEL240X_FORMAT,
1507285612Sdelphij		GPS_TYPE,
1508285612Sdelphij		SEL240X_MAXUNSYNC,
1509285612Sdelphij		SEL240X_SPEED,
1510285612Sdelphij		SEL240X_CFLAG,
1511285612Sdelphij		SEL240X_IFLAG,
1512285612Sdelphij		SEL240X_OFLAG,
1513285612Sdelphij		SEL240X_LFLAG,
1514285612Sdelphij		SEL240X_SAMPLES,
1515285612Sdelphij		SEL240X_KEEP
1516285612Sdelphij	},
151754359Sroberto};
151854359Sroberto
151954359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
152054359Sroberto
1521132451Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
152254359Sroberto#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
152354359Sroberto#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1524132451Sroberto#define CLK_PPS(x)	(((x)->ttl) & 0x80)
152554359Sroberto
152654359Sroberto/*
152754359Sroberto * Other constant stuff
152854359Sroberto */
152954359Sroberto#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
153054359Sroberto
153154359Sroberto#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
153254359Sroberto
153354359Srobertostatic int notice = 0;
153454359Sroberto
153554359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
153654359Sroberto
1537285612Sdelphijstatic void parse_event   (struct parseunit *, int);
1538285612Sdelphijstatic void parse_process (struct parseunit *, parsetime_t *);
1539285612Sdelphijstatic void clear_err     (struct parseunit *, u_long);
1540285612Sdelphijstatic int  list_err      (struct parseunit *, u_long);
1541285612Sdelphijstatic char * l_mktime    (u_long);
154254359Sroberto
154354359Sroberto/**===========================================================================
154454359Sroberto ** implementation error message regression module
154554359Sroberto **/
154654359Srobertostatic void
154754359Srobertoclear_err(
154854359Sroberto	struct parseunit *parse,
154954359Sroberto	u_long            lstate
155054359Sroberto	)
155154359Sroberto{
155254359Sroberto	if (lstate == ERR_ALL)
155354359Sroberto	{
1554285612Sdelphij		size_t i;
155554359Sroberto
155654359Sroberto		for (i = 0; i < ERR_CNT; i++)
155754359Sroberto		{
155854359Sroberto			parse->errors[i].err_stage   = err_tbl[i];
155954359Sroberto			parse->errors[i].err_cnt     = 0;
156054359Sroberto			parse->errors[i].err_last    = 0;
156154359Sroberto			parse->errors[i].err_started = 0;
156254359Sroberto			parse->errors[i].err_suppressed = 0;
156354359Sroberto		}
156454359Sroberto	}
156554359Sroberto	else
156654359Sroberto	{
156754359Sroberto		parse->errors[lstate].err_stage   = err_tbl[lstate];
156854359Sroberto		parse->errors[lstate].err_cnt     = 0;
156954359Sroberto		parse->errors[lstate].err_last    = 0;
157054359Sroberto		parse->errors[lstate].err_started = 0;
157154359Sroberto		parse->errors[lstate].err_suppressed = 0;
157254359Sroberto	}
157354359Sroberto}
157454359Sroberto
157554359Srobertostatic int
157654359Srobertolist_err(
157754359Sroberto	struct parseunit *parse,
157854359Sroberto	u_long            lstate
157954359Sroberto	)
158054359Sroberto{
158154359Sroberto	int do_it;
158254359Sroberto	struct errorinfo *err = &parse->errors[lstate];
158354359Sroberto
158454359Sroberto	if (err->err_started == 0)
158554359Sroberto	{
158654359Sroberto		err->err_started = current_time;
158754359Sroberto	}
158854359Sroberto
158954359Sroberto	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
159054359Sroberto
159154359Sroberto	if (do_it)
159254359Sroberto	    err->err_cnt++;
1593285612Sdelphij
159454359Sroberto	if (err->err_stage->err_count &&
159554359Sroberto	    (err->err_cnt >= err->err_stage->err_count))
159654359Sroberto	{
159754359Sroberto		err->err_stage++;
159854359Sroberto		err->err_cnt = 0;
159954359Sroberto	}
160054359Sroberto
160154359Sroberto	if (!err->err_cnt && do_it)
160254359Sroberto	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
160354359Sroberto		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
160454359Sroberto
160554359Sroberto	if (!do_it)
160654359Sroberto	    err->err_suppressed++;
160754359Sroberto	else
160854359Sroberto	    err->err_last = current_time;
160954359Sroberto
161054359Sroberto	if (do_it && err->err_suppressed)
161154359Sroberto	{
161254359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
161354359Sroberto			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
161454359Sroberto			l_mktime(current_time - err->err_started));
161554359Sroberto		err->err_suppressed = 0;
161654359Sroberto	}
1617285612Sdelphij
161854359Sroberto	return do_it;
161954359Sroberto}
162054359Sroberto
162154359Sroberto/*--------------------------------------------------
162254359Sroberto * mkreadable - make a printable ascii string (without
162354359Sroberto * embedded quotes so that the ntpq protocol isn't
162454359Sroberto * fooled
162554359Sroberto */
162654359Sroberto#ifndef isprint
162754359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
162854359Sroberto#endif
162954359Sroberto
163054359Srobertostatic char *
163154359Srobertomkreadable(
163254359Sroberto	char  *buffer,
1633293650Sglebius	size_t blen,
163454359Sroberto	const char  *src,
1635293650Sglebius	size_t srclen,
163654359Sroberto	int hex
163754359Sroberto	)
163854359Sroberto{
1639285612Sdelphij	static const char ellipsis[] = "...";
164054359Sroberto	char *b    = buffer;
1641285612Sdelphij	char *endb = NULL;
164254359Sroberto
164354359Sroberto	if (blen < 4)
1644285612Sdelphij		return NULL;		/* don't bother with mini buffers */
164554359Sroberto
1646285612Sdelphij	endb = buffer + blen - sizeof(ellipsis);
164754359Sroberto
164854359Sroberto	blen--;			/* account for '\0' */
164954359Sroberto
165054359Sroberto	while (blen && srclen--)
165154359Sroberto	{
165254359Sroberto		if (!hex &&             /* no binary only */
165354359Sroberto		    (*src != '\\') &&   /* no plain \ */
165454359Sroberto		    (*src != '"') &&    /* no " */
1655285612Sdelphij		    isprint((unsigned char)*src))	/* only printables */
165654359Sroberto		{			/* they are easy... */
165754359Sroberto			*buffer++ = *src++;
165854359Sroberto			blen--;
165954359Sroberto		}
166054359Sroberto		else
166154359Sroberto		{
166254359Sroberto			if (blen < 4)
166354359Sroberto			{
166454359Sroberto				while (blen--)
166554359Sroberto				{
166654359Sroberto					*buffer++ = '.';
166754359Sroberto				}
166854359Sroberto				*buffer = '\0';
166954359Sroberto				return b;
167054359Sroberto			}
167154359Sroberto			else
167254359Sroberto			{
167354359Sroberto				if (*src == '\\')
167454359Sroberto				{
1675285612Sdelphij					memcpy(buffer, "\\\\", 2);
167654359Sroberto					buffer += 2;
167754359Sroberto					blen   -= 2;
167854359Sroberto					src++;
167954359Sroberto				}
168054359Sroberto				else
168154359Sroberto				{
1682285612Sdelphij					snprintf(buffer, blen, "\\x%02x", *src++);
168354359Sroberto					blen   -= 4;
168454359Sroberto					buffer += 4;
168554359Sroberto				}
168654359Sroberto			}
168754359Sroberto		}
168854359Sroberto		if (srclen && !blen && endb) /* overflow - set last chars to ... */
1689285612Sdelphij			memcpy(endb, ellipsis, sizeof(ellipsis));
169054359Sroberto	}
169154359Sroberto
169254359Sroberto	*buffer = '\0';
169354359Sroberto	return b;
169454359Sroberto}
169554359Sroberto
169654359Sroberto
169754359Sroberto/*--------------------------------------------------
169854359Sroberto * mkascii - make a printable ascii string
169954359Sroberto * assumes (unless defined better) 7-bit ASCII
170054359Sroberto */
170154359Srobertostatic char *
170254359Srobertomkascii(
170354359Sroberto	char  *buffer,
170454359Sroberto	long  blen,
170554359Sroberto	const char  *src,
170654359Sroberto	u_long  srclen
170754359Sroberto	)
170854359Sroberto{
170954359Sroberto	return mkreadable(buffer, blen, src, srclen, 0);
171054359Sroberto}
171154359Sroberto
171254359Sroberto/**===========================================================================
171354359Sroberto ** implementation of i/o handling methods
171454359Sroberto ** (all STREAM, partial STREAM, user level)
171554359Sroberto **/
171654359Sroberto
171754359Sroberto/*
171854359Sroberto * define possible io handling methods
171954359Sroberto */
172054359Sroberto#ifdef STREAM
1721285612Sdelphijstatic int  ppsclock_init   (struct parseunit *);
1722285612Sdelphijstatic int  stream_init     (struct parseunit *);
1723285612Sdelphijstatic void stream_end      (struct parseunit *);
1724285612Sdelphijstatic int  stream_enable   (struct parseunit *);
1725285612Sdelphijstatic int  stream_disable  (struct parseunit *);
1726285612Sdelphijstatic int  stream_setcs    (struct parseunit *, parsectl_t *);
1727285612Sdelphijstatic int  stream_getfmt   (struct parseunit *, parsectl_t *);
1728285612Sdelphijstatic int  stream_setfmt   (struct parseunit *, parsectl_t *);
1729285612Sdelphijstatic int  stream_timecode (struct parseunit *, parsectl_t *);
1730285612Sdelphijstatic void stream_receive  (struct recvbuf *);
173154359Sroberto#endif
173254359Sroberto
1733285612Sdelphijstatic int  local_init     (struct parseunit *);
1734285612Sdelphijstatic void local_end      (struct parseunit *);
1735285612Sdelphijstatic int  local_nop      (struct parseunit *);
1736285612Sdelphijstatic int  local_setcs    (struct parseunit *, parsectl_t *);
1737285612Sdelphijstatic int  local_getfmt   (struct parseunit *, parsectl_t *);
1738285612Sdelphijstatic int  local_setfmt   (struct parseunit *, parsectl_t *);
1739285612Sdelphijstatic int  local_timecode (struct parseunit *, parsectl_t *);
1740285612Sdelphijstatic void local_receive  (struct recvbuf *);
1741285612Sdelphijstatic int  local_input    (struct recvbuf *);
1742285612Sdelphij
174354359Srobertostatic bind_t io_bindings[] =
174454359Sroberto{
174554359Sroberto#ifdef STREAM
174654359Sroberto	{
174754359Sroberto		"parse STREAM",
174854359Sroberto		stream_init,
174954359Sroberto		stream_end,
175054359Sroberto		stream_setcs,
175154359Sroberto		stream_disable,
175254359Sroberto		stream_enable,
175354359Sroberto		stream_getfmt,
175454359Sroberto		stream_setfmt,
175554359Sroberto		stream_timecode,
175654359Sroberto		stream_receive,
175754359Sroberto		0,
175854359Sroberto	},
175954359Sroberto	{
176054359Sroberto		"ppsclock STREAM",
176154359Sroberto		ppsclock_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#endif
177354359Sroberto	{
177454359Sroberto		"normal",
177554359Sroberto		local_init,
177654359Sroberto		local_end,
177754359Sroberto		local_setcs,
177854359Sroberto		local_nop,
177954359Sroberto		local_nop,
178054359Sroberto		local_getfmt,
178154359Sroberto		local_setfmt,
178254359Sroberto		local_timecode,
178354359Sroberto		local_receive,
178454359Sroberto		local_input,
178554359Sroberto	},
178654359Sroberto	{
178754359Sroberto		(char *)0,
1788285612Sdelphij		NULL,
1789285612Sdelphij		NULL,
1790285612Sdelphij		NULL,
1791285612Sdelphij		NULL,
1792285612Sdelphij		NULL,
1793285612Sdelphij		NULL,
1794285612Sdelphij		NULL,
1795285612Sdelphij		NULL,
1796285612Sdelphij		NULL,
1797285612Sdelphij		NULL,
179854359Sroberto	}
179954359Sroberto};
180054359Sroberto
180154359Sroberto#ifdef STREAM
180254359Sroberto
180354359Sroberto/*--------------------------------------------------
180454359Sroberto * ppsclock STREAM init
180554359Sroberto */
180654359Srobertostatic int
180754359Srobertoppsclock_init(
180854359Sroberto	struct parseunit *parse
180954359Sroberto	)
181054359Sroberto{
181154359Sroberto        static char m1[] = "ppsclocd";
181254359Sroberto	static char m2[] = "ppsclock";
1813285612Sdelphij
181454359Sroberto	/*
181554359Sroberto	 * now push the parse streams module
181654359Sroberto	 * it will ensure exclusive access to the device
181754359Sroberto	 */
1818182007Sroberto	if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1819182007Sroberto	    ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
182054359Sroberto	{
182154359Sroberto		if (errno != EINVAL)
182256746Sroberto		{
182356746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
182456746Sroberto				CLK_UNIT(parse->peer));
182554359Sroberto		}
182654359Sroberto		return 0;
182754359Sroberto	}
182854359Sroberto	if (!local_init(parse))
182954359Sroberto	{
1830182007Sroberto		(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
183154359Sroberto		return 0;
183254359Sroberto	}
183354359Sroberto
183454359Sroberto	parse->flags |= PARSE_PPSCLOCK;
183554359Sroberto	return 1;
183654359Sroberto}
183754359Sroberto
183854359Sroberto/*--------------------------------------------------
183954359Sroberto * parse STREAM init
184054359Sroberto */
184154359Srobertostatic int
184254359Srobertostream_init(
184354359Sroberto	struct parseunit *parse
184454359Sroberto	)
184554359Sroberto{
184654359Sroberto	static char m1[] = "parse";
184754359Sroberto	/*
184854359Sroberto	 * now push the parse streams module
184954359Sroberto	 * to test whether it is there (neat interface 8-( )
185054359Sroberto	 */
185154359Sroberto	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
185254359Sroberto	{
185354359Sroberto		if (errno != EINVAL) /* accept non-existence */
185456746Sroberto		{
185556746Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
185654359Sroberto		}
185754359Sroberto		return 0;
185854359Sroberto	}
185954359Sroberto	else
186054359Sroberto	{
186154359Sroberto		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
186254359Sroberto		    /* empty loop */;
186354359Sroberto
186454359Sroberto		/*
186554359Sroberto		 * now push it a second time after we have removed all
186654359Sroberto		 * module garbage
186754359Sroberto		 */
186854359Sroberto		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
186954359Sroberto		{
187054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
187154359Sroberto			return 0;
187254359Sroberto		}
187354359Sroberto		else
187454359Sroberto		{
187554359Sroberto			return 1;
187654359Sroberto		}
187754359Sroberto	}
187854359Sroberto}
187954359Sroberto
188054359Sroberto/*--------------------------------------------------
188154359Sroberto * parse STREAM end
188254359Sroberto */
188354359Srobertostatic void
188454359Srobertostream_end(
188554359Sroberto	struct parseunit *parse
188654359Sroberto	)
188754359Sroberto{
188854359Sroberto	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
188954359Sroberto	    /* empty loop */;
189054359Sroberto}
189154359Sroberto
189254359Sroberto/*--------------------------------------------------
189354359Sroberto * STREAM setcs
189454359Sroberto */
189554359Srobertostatic int
189654359Srobertostream_setcs(
189754359Sroberto	struct parseunit *parse,
189854359Sroberto	parsectl_t  *tcl
189954359Sroberto	)
190054359Sroberto{
190154359Sroberto	struct strioctl strioc;
1902285612Sdelphij
190354359Sroberto	strioc.ic_cmd     = PARSEIOC_SETCS;
190454359Sroberto	strioc.ic_timout  = 0;
190554359Sroberto	strioc.ic_dp      = (char *)tcl;
190654359Sroberto	strioc.ic_len     = sizeof (*tcl);
190754359Sroberto
190854359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
190954359Sroberto	{
191054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
191154359Sroberto		return 0;
191254359Sroberto	}
191354359Sroberto	return 1;
191454359Sroberto}
191554359Sroberto
191654359Sroberto/*--------------------------------------------------
191754359Sroberto * STREAM enable
191854359Sroberto */
191954359Srobertostatic int
192054359Srobertostream_enable(
192154359Sroberto	struct parseunit *parse
192254359Sroberto	)
192354359Sroberto{
192454359Sroberto	struct strioctl strioc;
1925285612Sdelphij
192654359Sroberto	strioc.ic_cmd     = PARSEIOC_ENABLE;
192754359Sroberto	strioc.ic_timout  = 0;
192854359Sroberto	strioc.ic_dp      = (char *)0;
192954359Sroberto	strioc.ic_len     = 0;
193054359Sroberto
193154359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
193254359Sroberto	{
193354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
193454359Sroberto		return 0;
193554359Sroberto	}
193654359Sroberto	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
193754359Sroberto	return 1;
193854359Sroberto}
193954359Sroberto
194054359Sroberto/*--------------------------------------------------
194154359Sroberto * STREAM disable
194254359Sroberto */
194354359Srobertostatic int
194454359Srobertostream_disable(
194554359Sroberto	struct parseunit *parse
194654359Sroberto	)
194754359Sroberto{
194854359Sroberto	struct strioctl strioc;
1949285612Sdelphij
195054359Sroberto	strioc.ic_cmd     = PARSEIOC_DISABLE;
195154359Sroberto	strioc.ic_timout  = 0;
195254359Sroberto	strioc.ic_dp      = (char *)0;
195354359Sroberto	strioc.ic_len     = 0;
195454359Sroberto
195554359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
195654359Sroberto	{
195754359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
195854359Sroberto		return 0;
195954359Sroberto	}
196054359Sroberto	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
196154359Sroberto	return 1;
196254359Sroberto}
196354359Sroberto
196454359Sroberto/*--------------------------------------------------
196554359Sroberto * STREAM getfmt
196654359Sroberto */
196754359Srobertostatic int
196854359Srobertostream_getfmt(
196954359Sroberto	struct parseunit *parse,
197054359Sroberto	parsectl_t  *tcl
197154359Sroberto	)
197254359Sroberto{
197354359Sroberto	struct strioctl strioc;
1974285612Sdelphij
197554359Sroberto	strioc.ic_cmd     = PARSEIOC_GETFMT;
197654359Sroberto	strioc.ic_timout  = 0;
197754359Sroberto	strioc.ic_dp      = (char *)tcl;
197854359Sroberto	strioc.ic_len     = sizeof (*tcl);
197954359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
198054359Sroberto	{
198154359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
198254359Sroberto		return 0;
198354359Sroberto	}
198454359Sroberto	return 1;
198554359Sroberto}
198654359Sroberto
198754359Sroberto/*--------------------------------------------------
198854359Sroberto * STREAM setfmt
198954359Sroberto */
199054359Srobertostatic int
199154359Srobertostream_setfmt(
199254359Sroberto	struct parseunit *parse,
199354359Sroberto	parsectl_t  *tcl
199454359Sroberto	)
199554359Sroberto{
199654359Sroberto	struct strioctl strioc;
1997285612Sdelphij
199854359Sroberto	strioc.ic_cmd     = PARSEIOC_SETFMT;
199954359Sroberto	strioc.ic_timout  = 0;
200054359Sroberto	strioc.ic_dp      = (char *)tcl;
200154359Sroberto	strioc.ic_len     = sizeof (*tcl);
200254359Sroberto
200354359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
200454359Sroberto	{
200554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
200654359Sroberto		return 0;
200754359Sroberto	}
200854359Sroberto	return 1;
200954359Sroberto}
201054359Sroberto
201154359Sroberto
201254359Sroberto/*--------------------------------------------------
201354359Sroberto * STREAM timecode
201454359Sroberto */
201554359Srobertostatic int
201654359Srobertostream_timecode(
201754359Sroberto	struct parseunit *parse,
201854359Sroberto	parsectl_t  *tcl
201954359Sroberto	)
202054359Sroberto{
202154359Sroberto	struct strioctl strioc;
2022285612Sdelphij
202354359Sroberto	strioc.ic_cmd     = PARSEIOC_TIMECODE;
202454359Sroberto	strioc.ic_timout  = 0;
202554359Sroberto	strioc.ic_dp      = (char *)tcl;
202654359Sroberto	strioc.ic_len     = sizeof (*tcl);
2027285612Sdelphij
202854359Sroberto	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
202954359Sroberto	{
203054359Sroberto		ERR(ERR_INTERNAL)
203154359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
203254359Sroberto		return 0;
203354359Sroberto	}
203454359Sroberto	clear_err(parse, ERR_INTERNAL);
203554359Sroberto	return 1;
203654359Sroberto}
203754359Sroberto
203854359Sroberto/*--------------------------------------------------
203954359Sroberto * STREAM receive
204054359Sroberto */
204154359Srobertostatic void
204254359Srobertostream_receive(
204354359Sroberto	struct recvbuf *rbufp
204454359Sroberto	)
204554359Sroberto{
2046285612Sdelphij	struct parseunit * parse;
204754359Sroberto	parsetime_t parsetime;
204854359Sroberto
2049285612Sdelphij	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
205054359Sroberto	if (!parse->peer)
205154359Sroberto	    return;
205254359Sroberto
205354359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
205454359Sroberto	{
205554359Sroberto		ERR(ERR_BADIO)
205654359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
205754359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
205854359Sroberto		parse_event(parse, CEVNT_BADREPLY);
205954359Sroberto		return;
206054359Sroberto	}
206154359Sroberto	clear_err(parse, ERR_BADIO);
2062285612Sdelphij
206354359Sroberto	memmove((caddr_t)&parsetime,
206454359Sroberto		(caddr_t)rbufp->recv_buffer,
206554359Sroberto		sizeof(parsetime_t));
206654359Sroberto
206754359Sroberto#ifdef DEBUG
206854359Sroberto	if (debug > 3)
206954359Sroberto	  {
207054359Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
207154359Sroberto		   CLK_UNIT(parse->peer),
207254359Sroberto		   (unsigned int)parsetime.parse_status,
207354359Sroberto		   (unsigned int)parsetime.parse_state,
2074182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_sec,
2075182007Sroberto		   (unsigned long)parsetime.parse_time.tv.tv_usec,
2076182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_sec,
2077182007Sroberto		   (unsigned long)parsetime.parse_stime.tv.tv_usec,
2078182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_sec,
2079182007Sroberto		   (unsigned long)parsetime.parse_ptime.tv.tv_usec);
208054359Sroberto	  }
208154359Sroberto#endif
208254359Sroberto
208354359Sroberto	/*
208454359Sroberto	 * switch time stamp world - be sure to normalize small usec field
208554359Sroberto	 * errors.
208654359Sroberto	 */
208754359Sroberto
2088285612Sdelphij	parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv);
208954359Sroberto
209054359Sroberto	if (PARSE_TIMECODE(parsetime.parse_state))
209154359Sroberto	{
2092285612Sdelphij		parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv);
209354359Sroberto	}
209454359Sroberto
209554359Sroberto	if (PARSE_PPS(parsetime.parse_state))
2096285612Sdelphij	{
2097285612Sdelphij		parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv);
2098285612Sdelphij	}
209954359Sroberto
210054359Sroberto	parse_process(parse, &parsetime);
210154359Sroberto}
210254359Sroberto#endif
210354359Sroberto
210454359Sroberto/*--------------------------------------------------
210554359Sroberto * local init
210654359Sroberto */
210754359Srobertostatic int
210854359Srobertolocal_init(
210954359Sroberto	struct parseunit *parse
211054359Sroberto	)
211154359Sroberto{
211254359Sroberto	return parse_ioinit(&parse->parseio);
211354359Sroberto}
211454359Sroberto
211554359Sroberto/*--------------------------------------------------
211654359Sroberto * local end
211754359Sroberto */
211854359Srobertostatic void
211954359Srobertolocal_end(
212054359Sroberto	struct parseunit *parse
212154359Sroberto	)
212254359Sroberto{
212354359Sroberto	parse_ioend(&parse->parseio);
212454359Sroberto}
212554359Sroberto
212654359Sroberto
212754359Sroberto/*--------------------------------------------------
212854359Sroberto * local nop
212954359Sroberto */
213054359Srobertostatic int
213154359Srobertolocal_nop(
213254359Sroberto	struct parseunit *parse
213354359Sroberto	)
213454359Sroberto{
213554359Sroberto	return 1;
213654359Sroberto}
213754359Sroberto
213854359Sroberto/*--------------------------------------------------
213954359Sroberto * local setcs
214054359Sroberto */
214154359Srobertostatic int
214254359Srobertolocal_setcs(
214354359Sroberto	struct parseunit *parse,
214454359Sroberto	parsectl_t  *tcl
214554359Sroberto	)
214654359Sroberto{
214754359Sroberto	return parse_setcs(tcl, &parse->parseio);
214854359Sroberto}
214954359Sroberto
215054359Sroberto/*--------------------------------------------------
215154359Sroberto * local getfmt
215254359Sroberto */
215354359Srobertostatic int
215454359Srobertolocal_getfmt(
215554359Sroberto	struct parseunit *parse,
215654359Sroberto	parsectl_t  *tcl
215754359Sroberto	)
215854359Sroberto{
215954359Sroberto	return parse_getfmt(tcl, &parse->parseio);
216054359Sroberto}
216154359Sroberto
216254359Sroberto/*--------------------------------------------------
216354359Sroberto * local setfmt
216454359Sroberto */
216554359Srobertostatic int
216654359Srobertolocal_setfmt(
216754359Sroberto	struct parseunit *parse,
216854359Sroberto	parsectl_t  *tcl
216954359Sroberto	)
217054359Sroberto{
217154359Sroberto	return parse_setfmt(tcl, &parse->parseio);
217254359Sroberto}
217354359Sroberto
217454359Sroberto/*--------------------------------------------------
217554359Sroberto * local timecode
217654359Sroberto */
217754359Srobertostatic int
217854359Srobertolocal_timecode(
217954359Sroberto	struct parseunit *parse,
218054359Sroberto	parsectl_t  *tcl
218154359Sroberto	)
218254359Sroberto{
218354359Sroberto	return parse_timecode(tcl, &parse->parseio);
218454359Sroberto}
218554359Sroberto
218654359Sroberto
218754359Sroberto/*--------------------------------------------------
218854359Sroberto * local input
218954359Sroberto */
219054359Srobertostatic int
219154359Srobertolocal_input(
219254359Sroberto	struct recvbuf *rbufp
219354359Sroberto	)
219454359Sroberto{
2195285612Sdelphij	struct parseunit * parse;
2196285612Sdelphij
219754359Sroberto	int count;
219854359Sroberto	unsigned char *s;
219954359Sroberto	timestamp_t ts;
220054359Sroberto
2201285612Sdelphij	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
220254359Sroberto	if (!parse->peer)
220354359Sroberto		return 0;
220454359Sroberto
220554359Sroberto	/*
220654359Sroberto	 * eat all characters, parsing then and feeding complete samples
220754359Sroberto	 */
220854359Sroberto	count = rbufp->recv_length;
220954359Sroberto	s = (unsigned char *)rbufp->recv_buffer;
221054359Sroberto	ts.fp = rbufp->recv_time;
221154359Sroberto
221254359Sroberto	while (count--)
221354359Sroberto	{
221454359Sroberto		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
221554359Sroberto		{
2216182007Sroberto			struct recvbuf *buf;
221754359Sroberto
221854359Sroberto			/*
221954359Sroberto			 * got something good to eat
222054359Sroberto			 */
222154359Sroberto			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
222254359Sroberto			{
2223182007Sroberto#ifdef HAVE_PPSAPI
2224182007Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2225182007Sroberto				{
2226182007Sroberto					struct timespec pps_timeout;
2227182007Sroberto					pps_info_t      pps_info;
2228285612Sdelphij
2229182007Sroberto					pps_timeout.tv_sec  = 0;
2230182007Sroberto					pps_timeout.tv_nsec = 0;
2231182007Sroberto
2232285612Sdelphij					if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
2233182007Sroberto							   &pps_timeout) == 0)
2234182007Sroberto					{
2235182007Sroberto						if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2236182007Sroberto						{
2237182007Sroberto							double dtemp;
2238182007Sroberto
2239182007Sroberto						        struct timespec pts;
2240182007Sroberto							/*
2241182007Sroberto							 * add PPS time stamp if available via ppsclock module
2242182007Sroberto							 * and not supplied already.
2243182007Sroberto							 */
2244182007Sroberto							if (parse->flags & PARSE_CLEAR)
2245182007Sroberto							  pts = pps_info.clear_timestamp;
2246182007Sroberto							else
2247182007Sroberto							  pts = pps_info.assert_timestamp;
2248182007Sroberto
2249285612Sdelphij							parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970);
2250182007Sroberto
2251285612Sdelphij							dtemp = (double) pts.tv_nsec / 1e9;
2252182007Sroberto							if (dtemp < 0.) {
2253182007Sroberto								dtemp += 1;
2254182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2255182007Sroberto							}
2256182007Sroberto							if (dtemp > 1.) {
2257182007Sroberto								dtemp -= 1;
2258182007Sroberto								parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2259182007Sroberto							}
2260285612Sdelphij							parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC);
2261182007Sroberto
2262285612Sdelphij							parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2263182007Sroberto#ifdef DEBUG
2264182007Sroberto							if (debug > 3)
2265182007Sroberto							{
2266182007Sroberto								printf(
2267301256Sdelphij								       "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n",
2268301256Sdelphij								       (long)rbufp->fd,
2269182007Sroberto								       (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2270182007Sroberto								       lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2271182007Sroberto							}
2272182007Sroberto#endif
2273182007Sroberto						}
2274182007Sroberto#ifdef DEBUG
2275182007Sroberto						else
2276182007Sroberto						{
2277182007Sroberto							if (debug > 3)
2278182007Sroberto							{
2279182007Sroberto								printf(
2280301256Sdelphij								       "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2281301256Sdelphij								       (long)rbufp->fd,
2282182007Sroberto								       (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2283182007Sroberto							}
2284182007Sroberto						}
2285182007Sroberto#endif
2286182007Sroberto						parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2287182007Sroberto					}
2288182007Sroberto#ifdef DEBUG
2289182007Sroberto					else
2290182007Sroberto					{
2291182007Sroberto						if (debug > 3)
2292182007Sroberto						{
2293182007Sroberto							printf(
2294301256Sdelphij							       "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n",
2295301256Sdelphij							       (long)rbufp->fd,
2296182007Sroberto							       errno);
2297182007Sroberto						}
2298182007Sroberto					}
2299182007Sroberto#endif
2300182007Sroberto				}
2301182007Sroberto#else
230254359Sroberto#ifdef TIOCDCDTIMESTAMP
230354359Sroberto				struct timeval dcd_time;
2304285612Sdelphij
2305182007Sroberto				if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
230654359Sroberto				{
230754359Sroberto					l_fp tstmp;
2308285612Sdelphij
230954359Sroberto					TVTOTS(&dcd_time, &tstmp);
231054359Sroberto					tstmp.l_ui += JAN_1970;
231154359Sroberto					L_SUB(&ts.fp, &tstmp);
231254359Sroberto					if (ts.fp.l_ui == 0)
231354359Sroberto					{
231454359Sroberto#ifdef DEBUG
231554359Sroberto						if (debug)
231654359Sroberto						{
231754359Sroberto							printf(
231854359Sroberto							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2319182007Sroberto							       parse->ppsfd,
232054359Sroberto							       lfptoa(&tstmp, 6));
232154359Sroberto							printf(" sigio %s\n",
232254359Sroberto							       lfptoa(&ts.fp, 6));
232354359Sroberto						}
232454359Sroberto#endif
232554359Sroberto						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
232654359Sroberto						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
232754359Sroberto					}
232854359Sroberto				}
232954359Sroberto#else /* TIOCDCDTIMESTAMP */
233054359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
233154359Sroberto				if (parse->flags & PARSE_PPSCLOCK)
2332182007Sroberto				  {
2333182007Sroberto				    l_fp tts;
2334182007Sroberto				    struct ppsclockev ev;
233554359Sroberto
233654359Sroberto#ifdef HAVE_CIOGETEV
2337182007Sroberto				    if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
233854359Sroberto#endif
233954359Sroberto#ifdef HAVE_TIOCGPPSEV
2340182007Sroberto				    if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
234154359Sroberto#endif
234254359Sroberto					{
2343182007Sroberto					  if (ev.serial != parse->ppsserial)
2344182007Sroberto					    {
2345182007Sroberto					      /*
2346182007Sroberto					       * add PPS time stamp if available via ppsclock module
2347182007Sroberto					       * and not supplied already.
2348182007Sroberto					       */
2349182007Sroberto					      if (!buftvtots((const char *)&ev.tv, &tts))
235054359Sroberto						{
2351182007Sroberto						  ERR(ERR_BADDATA)
2352182007Sroberto						    msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
235354359Sroberto						}
2354182007Sroberto					      else
2355182007Sroberto						{
2356182007Sroberto						  parse->parseio.parse_dtime.parse_ptime.fp = tts;
2357182007Sroberto						  parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2358182007Sroberto						}
2359182007Sroberto					    }
2360182007Sroberto					  parse->ppsserial = ev.serial;
236154359Sroberto					}
2362182007Sroberto				  }
236354359Sroberto#endif
236454359Sroberto#endif /* TIOCDCDTIMESTAMP */
2365182007Sroberto#endif /* !HAVE_PPSAPI */
236654359Sroberto			}
236754359Sroberto			if (count)
236854359Sroberto			{	/* simulate receive */
2369182007Sroberto				buf = get_free_recv_buffer();
2370182007Sroberto				if (buf != NULL) {
2371182007Sroberto					memmove((caddr_t)buf->recv_buffer,
2372182007Sroberto						(caddr_t)&parse->parseio.parse_dtime,
2373182007Sroberto						sizeof(parsetime_t));
2374182007Sroberto					buf->recv_length  = sizeof(parsetime_t);
2375182007Sroberto					buf->recv_time    = rbufp->recv_time;
2376285612Sdelphij#ifndef HAVE_IO_COMPLETION_PORT
2377182007Sroberto					buf->srcadr       = rbufp->srcadr;
2378285612Sdelphij#endif
2379182007Sroberto					buf->dstadr       = rbufp->dstadr;
2380182007Sroberto					buf->receiver     = rbufp->receiver;
2381182007Sroberto					buf->fd           = rbufp->fd;
2382182007Sroberto					buf->X_from_where = rbufp->X_from_where;
2383285612Sdelphij					parse->generic->io.recvcount++;
2384285612Sdelphij					packets_received++;
2385182007Sroberto					add_full_recv_buffer(buf);
2386285612Sdelphij#ifdef HAVE_IO_COMPLETION_PORT
2387285612Sdelphij					SetEvent(WaitableIoEventHandle);
2388285612Sdelphij#endif
2389182007Sroberto				}
239054359Sroberto				parse_iodone(&parse->parseio);
239154359Sroberto			}
239254359Sroberto			else
239354359Sroberto			{
239456746Sroberto				memmove((caddr_t)rbufp->recv_buffer,
239556746Sroberto					(caddr_t)&parse->parseio.parse_dtime,
239656746Sroberto					sizeof(parsetime_t));
239756746Sroberto				parse_iodone(&parse->parseio);
239854359Sroberto				rbufp->recv_length = sizeof(parsetime_t);
239954359Sroberto				return 1; /* got something & in place return */
240054359Sroberto			}
240154359Sroberto		}
240254359Sroberto	}
240354359Sroberto	return 0;		/* nothing to pass up */
240454359Sroberto}
240554359Sroberto
240654359Sroberto/*--------------------------------------------------
240754359Sroberto * local receive
240854359Sroberto */
240954359Srobertostatic void
241054359Srobertolocal_receive(
241154359Sroberto	struct recvbuf *rbufp
241254359Sroberto	)
241354359Sroberto{
2414285612Sdelphij	struct parseunit * parse;
241554359Sroberto	parsetime_t parsetime;
241654359Sroberto
2417285612Sdelphij	parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
241854359Sroberto	if (!parse->peer)
241954359Sroberto	    return;
242054359Sroberto
242154359Sroberto	if (rbufp->recv_length != sizeof(parsetime_t))
242254359Sroberto	{
242354359Sroberto		ERR(ERR_BADIO)
242454359Sroberto			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
242554359Sroberto				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
242654359Sroberto		parse_event(parse, CEVNT_BADREPLY);
242754359Sroberto		return;
242854359Sroberto	}
242954359Sroberto	clear_err(parse, ERR_BADIO);
2430285612Sdelphij
243154359Sroberto	memmove((caddr_t)&parsetime,
243254359Sroberto		(caddr_t)rbufp->recv_buffer,
243354359Sroberto		sizeof(parsetime_t));
243454359Sroberto
243554359Sroberto#ifdef DEBUG
243654359Sroberto	if (debug > 3)
243754359Sroberto	  {
2438182007Sroberto	    printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
243954359Sroberto		   CLK_UNIT(parse->peer),
244054359Sroberto		   (unsigned int)parsetime.parse_status,
244154359Sroberto		   (unsigned int)parsetime.parse_state,
2442182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_ui,
2443182007Sroberto		   (unsigned long)parsetime.parse_time.fp.l_uf,
2444182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_ui,
2445182007Sroberto		   (unsigned long)parsetime.parse_stime.fp.l_uf,
2446182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_ui,
2447182007Sroberto		   (unsigned long)parsetime.parse_ptime.fp.l_uf);
244854359Sroberto	  }
244954359Sroberto#endif
245054359Sroberto
245154359Sroberto	parse_process(parse, &parsetime);
245254359Sroberto}
245354359Sroberto
245454359Sroberto/*--------------------------------------------------
245554359Sroberto * init_iobinding - find and initialize lower layers
245654359Sroberto */
245754359Srobertostatic bind_t *
245854359Srobertoinit_iobinding(
245954359Sroberto	struct parseunit *parse
246054359Sroberto	)
246154359Sroberto{
246254359Sroberto  bind_t *b = io_bindings;
246354359Sroberto
246454359Sroberto	while (b->bd_description != (char *)0)
246554359Sroberto	{
246654359Sroberto		if ((*b->bd_init)(parse))
246754359Sroberto		{
246854359Sroberto			return b;
246954359Sroberto		}
247054359Sroberto		b++;
247154359Sroberto	}
247254359Sroberto	return (bind_t *)0;
247354359Sroberto}
247454359Sroberto
247554359Sroberto/**===========================================================================
247654359Sroberto ** support routines
247754359Sroberto **/
247854359Sroberto
2479285612Sdelphijstatic NTP_PRINTF(4, 5) char *
2480285612Sdelphijap(char *buffer, size_t len, char *pos, const char *fmt, ...)
2481285612Sdelphij{
2482285612Sdelphij	va_list va;
2483285612Sdelphij	int l;
2484285612Sdelphij	size_t rem = len - (pos - buffer);
2485285612Sdelphij
2486285612Sdelphij	if (rem == 0)
2487285612Sdelphij		return pos;
2488285612Sdelphij
2489285612Sdelphij	va_start(va, fmt);
2490285612Sdelphij	l = vsnprintf(pos, rem, fmt, va);
2491285612Sdelphij	va_end(va);
2492285612Sdelphij
2493285612Sdelphij	if (l != -1) {
2494285612Sdelphij		rem--;
2495285612Sdelphij		if (rem >= (size_t)l)
2496285612Sdelphij			pos += l;
2497285612Sdelphij		else
2498285612Sdelphij			pos += rem;
2499285612Sdelphij	}
2500285612Sdelphij
2501285612Sdelphij	return pos;
2502285612Sdelphij}
2503285612Sdelphij
250454359Sroberto/*--------------------------------------------------
250554359Sroberto * convert a flag field to a string
250654359Sroberto */
250754359Srobertostatic char *
250854359Srobertoparsestate(
250954359Sroberto	u_long lstate,
2510182007Sroberto	char *buffer,
2511182007Sroberto	int size
251254359Sroberto	)
251354359Sroberto{
251454359Sroberto	static struct bits
251554359Sroberto	{
251654359Sroberto		u_long      bit;
251754359Sroberto		const char *name;
251854359Sroberto	} flagstrings[] =
251954359Sroberto	  {
252056746Sroberto		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
252156746Sroberto		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
252256746Sroberto		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
252356746Sroberto		  { PARSEB_DST,        "DST" },
252456746Sroberto		  { PARSEB_UTC,        "UTC DISPLAY" },
252556746Sroberto		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
252656746Sroberto		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
252754359Sroberto		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
2528285612Sdelphij		  { PARSEB_CALLBIT,    "CALL BIT" },
252956746Sroberto		  { PARSEB_TIMECODE,   "TIME CODE" },
253056746Sroberto		  { PARSEB_PPS,        "PPS" },
253156746Sroberto		  { PARSEB_POSITION,   "POSITION" },
2532285612Sdelphij		  { 0,		       NULL }
253354359Sroberto	  };
253454359Sroberto
253554359Sroberto	static struct sbits
253654359Sroberto	{
253754359Sroberto		u_long      bit;
253854359Sroberto		const char *name;
253954359Sroberto	} sflagstrings[] =
254054359Sroberto	  {
254154359Sroberto		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
254254359Sroberto		  { PARSEB_S_PPS,      "PPS SIGNAL" },
2543285612Sdelphij		  { PARSEB_S_CALLBIT,  "CALLBIT" },
254454359Sroberto		  { PARSEB_S_POSITION, "POSITION" },
2545285612Sdelphij		  { 0,		       NULL }
254654359Sroberto	  };
254754359Sroberto	int i;
2548182007Sroberto	char *s, *t;
254954359Sroberto
255054359Sroberto	*buffer = '\0';
2551182007Sroberto	s = t = buffer;
255254359Sroberto
255354359Sroberto	i = 0;
255454359Sroberto	while (flagstrings[i].bit)
255554359Sroberto	{
255654359Sroberto		if (flagstrings[i].bit & lstate)
255754359Sroberto		{
2558182007Sroberto			if (s != t)
2559285612Sdelphij				t = ap(buffer, size, t, "; ");
2560285612Sdelphij			t = ap(buffer, size, t, "%s", flagstrings[i].name);
256154359Sroberto		}
256254359Sroberto		i++;
256354359Sroberto	}
256454359Sroberto
2565285612Sdelphij	if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION))
256654359Sroberto	{
2567182007Sroberto		if (s != t)
2568285612Sdelphij			t = ap(buffer, size, t, "; ");
256954359Sroberto
2570285612Sdelphij		t = ap(buffer, size, t, "(");
257154359Sroberto
2572285612Sdelphij		s = t;
257354359Sroberto
257454359Sroberto		i = 0;
257554359Sroberto		while (sflagstrings[i].bit)
257654359Sroberto		{
257754359Sroberto			if (sflagstrings[i].bit & lstate)
257854359Sroberto			{
257954359Sroberto				if (t != s)
258054359Sroberto				{
2581285612Sdelphij					t = ap(buffer, size, t, "; ");
258254359Sroberto				}
2583285612Sdelphij
2584285612Sdelphij				t = ap(buffer, size, t, "%s",
2585285612Sdelphij				    sflagstrings[i].name);
258654359Sroberto			}
258754359Sroberto			i++;
258854359Sroberto		}
2589285612Sdelphij		t = ap(buffer, size, t, ")");
2590289997Sglebius		/* t is unused here, but if we don't track it and
2591289997Sglebius		 * need it later, that's a bug waiting to happen.
2592289997Sglebius		 */
259354359Sroberto	}
259454359Sroberto	return buffer;
259554359Sroberto}
259654359Sroberto
259754359Sroberto/*--------------------------------------------------
259854359Sroberto * convert a status flag field to a string
259954359Sroberto */
260054359Srobertostatic char *
260154359Srobertoparsestatus(
260254359Sroberto	u_long lstate,
2603182007Sroberto	char *buffer,
2604182007Sroberto	int size
260554359Sroberto	)
260654359Sroberto{
260754359Sroberto	static struct bits
260854359Sroberto	{
260954359Sroberto		u_long      bit;
261054359Sroberto		const char *name;
261154359Sroberto	} flagstrings[] =
261254359Sroberto	  {
261354359Sroberto		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
261454359Sroberto		  { CVT_NONE,    "NO CONVERSION" },
261554359Sroberto		  { CVT_FAIL,    "CONVERSION FAILED" },
261654359Sroberto		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
261754359Sroberto		  { CVT_BADDATE, "DATE ILLEGAL" },
261854359Sroberto		  { CVT_BADTIME, "TIME ILLEGAL" },
261954359Sroberto		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2620285612Sdelphij		  { 0,		 NULL }
262154359Sroberto	  };
262254359Sroberto	int i;
2623285612Sdelphij	char *t;
262454359Sroberto
2625285612Sdelphij	t = buffer;
262654359Sroberto	*buffer = '\0';
262754359Sroberto
262854359Sroberto	i = 0;
262954359Sroberto	while (flagstrings[i].bit)
263054359Sroberto	{
263154359Sroberto		if (flagstrings[i].bit & lstate)
263254359Sroberto		{
2633285612Sdelphij			if (t != buffer)
2634285612Sdelphij				t = ap(buffer, size, t, "; ");
2635285612Sdelphij			t = ap(buffer, size, t, "%s", flagstrings[i].name);
263654359Sroberto		}
263754359Sroberto		i++;
263854359Sroberto	}
263954359Sroberto
264054359Sroberto	return buffer;
264154359Sroberto}
264254359Sroberto
264354359Sroberto/*--------------------------------------------------
264454359Sroberto * convert a clock status flag field to a string
264554359Sroberto */
264654359Srobertostatic const char *
264754359Srobertoclockstatus(
264854359Sroberto	u_long lstate
264954359Sroberto	)
265054359Sroberto{
265154359Sroberto	static char buffer[20];
265254359Sroberto	static struct status
265354359Sroberto	{
265454359Sroberto		u_long      value;
265554359Sroberto		const char *name;
265654359Sroberto	} flagstrings[] =
265754359Sroberto	  {
265854359Sroberto		  { CEVNT_NOMINAL, "NOMINAL" },
265954359Sroberto		  { CEVNT_TIMEOUT, "NO RESPONSE" },
266054359Sroberto		  { CEVNT_BADREPLY,"BAD FORMAT" },
266154359Sroberto		  { CEVNT_FAULT,   "FAULT" },
266254359Sroberto		  { CEVNT_PROP,    "PROPAGATION DELAY" },
266354359Sroberto		  { CEVNT_BADDATE, "ILLEGAL DATE" },
266454359Sroberto		  { CEVNT_BADTIME, "ILLEGAL TIME" },
2665285612Sdelphij		  { (unsigned)~0L, NULL }
266654359Sroberto	  };
266754359Sroberto	int i;
266854359Sroberto
266954359Sroberto	i = 0;
2670285612Sdelphij	while (flagstrings[i].value != (u_int)~0)
267154359Sroberto	{
267254359Sroberto		if (flagstrings[i].value == lstate)
267354359Sroberto		{
267454359Sroberto			return flagstrings[i].name;
267554359Sroberto		}
267654359Sroberto		i++;
267754359Sroberto	}
267854359Sroberto
2679182007Sroberto	snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
268054359Sroberto
268154359Sroberto	return buffer;
268254359Sroberto}
268354359Sroberto
268454359Sroberto
268554359Sroberto/*--------------------------------------------------
268654359Sroberto * l_mktime - make representation of a relative time
268754359Sroberto */
268854359Srobertostatic char *
268954359Srobertol_mktime(
269054359Sroberto	u_long delta
269154359Sroberto	)
269254359Sroberto{
269354359Sroberto	u_long tmp, m, s;
269454359Sroberto	static char buffer[40];
2695182007Sroberto	char *t;
269654359Sroberto
269754359Sroberto	buffer[0] = '\0';
2698285612Sdelphij	t = buffer;
269954359Sroberto
270054359Sroberto	if ((tmp = delta / (60*60*24)) != 0)
270154359Sroberto	{
2702285612Sdelphij		t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp);
270354359Sroberto		delta -= tmp * 60*60*24;
270454359Sroberto	}
270554359Sroberto
270654359Sroberto	s = delta % 60;
270754359Sroberto	delta /= 60;
270854359Sroberto	m = delta % 60;
270954359Sroberto	delta /= 60;
271054359Sroberto
2711285612Sdelphij	t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
2712285612Sdelphij	     (int)delta, (int)m, (int)s);
271354359Sroberto
271454359Sroberto	return buffer;
271554359Sroberto}
271654359Sroberto
271754359Sroberto
271854359Sroberto/*--------------------------------------------------
271954359Sroberto * parse_statistics - list summary of clock states
272054359Sroberto */
272154359Srobertostatic void
272254359Srobertoparse_statistics(
272354359Sroberto	struct parseunit *parse
272454359Sroberto	)
272554359Sroberto{
272654359Sroberto	int i;
272754359Sroberto
272854359Sroberto	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
272954359Sroberto		{
273054359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
273154359Sroberto				CLK_UNIT(parse->peer),
273254359Sroberto				l_mktime(current_time - parse->generic->timestarted));
273354359Sroberto
273454359Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
273554359Sroberto				CLK_UNIT(parse->peer),
273654359Sroberto				clockstatus(parse->generic->currentstatus));
273754359Sroberto
273854359Sroberto			for (i = 0; i <= CEVNT_MAX; i++)
273954359Sroberto			{
274054359Sroberto				u_long s_time;
274154359Sroberto				u_long percent, d = current_time - parse->generic->timestarted;
274254359Sroberto
274354359Sroberto				percent = s_time = PARSE_STATETIME(parse, i);
274454359Sroberto
274554359Sroberto				while (((u_long)(~0) / 10000) < percent)
274654359Sroberto				{
274754359Sroberto					percent /= 10;
274854359Sroberto					d       /= 10;
274954359Sroberto				}
275054359Sroberto
275154359Sroberto				if (d)
275254359Sroberto				    percent = (percent * 10000) / d;
275354359Sroberto				else
275454359Sroberto				    percent = 10000;
275554359Sroberto
275654359Sroberto				if (s_time)
275754359Sroberto				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
275854359Sroberto					    CLK_UNIT(parse->peer),
275954359Sroberto					    clockstatus((unsigned int)i),
276054359Sroberto					    l_mktime(s_time),
276154359Sroberto					    percent / 100, percent % 100);
276254359Sroberto			}
276354359Sroberto		}
276454359Sroberto}
276554359Sroberto
276654359Sroberto/*--------------------------------------------------
276754359Sroberto * cparse_statistics - wrapper for statistics call
276854359Sroberto */
276954359Srobertostatic void
277054359Srobertocparse_statistics(
2771182007Sroberto        struct parseunit *parse
277254359Sroberto	)
277354359Sroberto{
277454359Sroberto	if (parse->laststatistic + PARSESTATISTICS < current_time)
277554359Sroberto		parse_statistics(parse);
277654359Sroberto	parse->laststatistic = current_time;
277754359Sroberto}
277854359Sroberto
277954359Sroberto/**===========================================================================
278054359Sroberto ** ntp interface routines
278154359Sroberto **/
278254359Sroberto
278354359Sroberto/*--------------------------------------------------
278454359Sroberto * parse_shutdown - shut down a PARSE clock
278554359Sroberto */
278654359Srobertostatic void
278754359Srobertoparse_shutdown(
278854359Sroberto	int unit,
278954359Sroberto	struct peer *peer
279054359Sroberto	)
279154359Sroberto{
2792285612Sdelphij	struct parseunit *parse = NULL;
279354359Sroberto
2794182007Sroberto	if (peer && peer->procptr)
2795285612Sdelphij		parse = peer->procptr->unitptr;
2796182007Sroberto
2797182007Sroberto	if (!parse)
279854359Sroberto	{
2799182007Sroberto		/* nothing to clean up */
280054359Sroberto		return;
280154359Sroberto	}
280254359Sroberto
2803285612Sdelphij	if (!parse->peer)
2804182007Sroberto	{
2805182007Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2806182007Sroberto		return;
2807182007Sroberto	}
2808182007Sroberto
2809182007Sroberto#ifdef HAVE_PPSAPI
2810182007Sroberto	if (parse->flags & PARSE_PPSCLOCK)
2811182007Sroberto	{
2812285612Sdelphij		(void)time_pps_destroy(parse->atom.handle);
2813182007Sroberto	}
2814182007Sroberto#endif
2815182007Sroberto	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2816285612Sdelphij		(void)closeserial(parse->ppsfd);  /* close separate PPS source */
2817182007Sroberto
281854359Sroberto	/*
281954359Sroberto	 * print statistics a last time and
282054359Sroberto	 * stop statistics machine
282154359Sroberto	 */
282254359Sroberto	parse_statistics(parse);
282354359Sroberto
282454359Sroberto	if (parse->parse_type->cl_end)
282554359Sroberto	{
282654359Sroberto		parse->parse_type->cl_end(parse);
282754359Sroberto	}
2828285612Sdelphij
2829182007Sroberto	/*
2830182007Sroberto	 * cleanup before leaving this world
2831182007Sroberto	 */
283254359Sroberto	if (parse->binding)
283354359Sroberto	    PARSE_END(parse);
283454359Sroberto
283554359Sroberto	/*
283654359Sroberto	 * Tell the I/O module to turn us off.  We're history.
283754359Sroberto	 */
283854359Sroberto	io_closeclock(&parse->generic->io);
283954359Sroberto
284054359Sroberto	free_varlist(parse->kv);
2841285612Sdelphij
284254359Sroberto	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
284354359Sroberto		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
284454359Sroberto			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
284554359Sroberto
284654359Sroberto	parse->peer = (struct peer *)0; /* unused now */
2847182007Sroberto	peer->procptr->unitptr = (caddr_t)0;
284854359Sroberto	free(parse);
284954359Sroberto}
285054359Sroberto
2851182007Sroberto#ifdef HAVE_PPSAPI
2852182007Sroberto/*----------------------------------------
2853182007Sroberto * set up HARDPPS via PPSAPI
2854182007Sroberto */
2855182007Srobertostatic void
2856182007Srobertoparse_hardpps(
2857182007Sroberto	      struct parseunit *parse,
2858182007Sroberto	      int mode
2859182007Sroberto	      )
2860182007Sroberto{
2861182007Sroberto        if (parse->hardppsstate == mode)
2862182007Sroberto	        return;
2863182007Sroberto
2864182007Sroberto	if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2865182007Sroberto		int	i = 0;
2866182007Sroberto
2867285612Sdelphij		if (mode == PARSE_HARDPPS_ENABLE)
2868182007Sroberto		        {
2869182007Sroberto			        if (parse->flags & PARSE_CLEAR)
2870182007Sroberto				        i = PPS_CAPTURECLEAR;
2871182007Sroberto				else
2872182007Sroberto				        i = PPS_CAPTUREASSERT;
2873182007Sroberto			}
2874285612Sdelphij
2875285612Sdelphij		if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
2876182007Sroberto		    PPS_TSFMT_TSPEC) < 0) {
2877182007Sroberto		        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2878182007Sroberto				CLK_UNIT(parse->peer));
2879182007Sroberto		} else {
2880182007Sroberto		        NLOG(NLOG_CLOCKINFO)
2881182007Sroberto		                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2882182007Sroberto					CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2883182007Sroberto			/*
2884182007Sroberto			 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2885182007Sroberto			 */
2886182007Sroberto			if (mode == PARSE_HARDPPS_ENABLE)
2887285612Sdelphij			        hardpps_enable = 1;
2888182007Sroberto		}
2889182007Sroberto	}
2890182007Sroberto
2891182007Sroberto	parse->hardppsstate = mode;
2892182007Sroberto}
2893182007Sroberto
2894182007Sroberto/*----------------------------------------
2895182007Sroberto * set up PPS via PPSAPI
2896182007Sroberto */
2897182007Srobertostatic int
2898182007Srobertoparse_ppsapi(
2899182007Sroberto	     struct parseunit *parse
2900182007Sroberto	)
2901182007Sroberto{
2902285612Sdelphij	int cap, mode_ppsoffset;
2903285612Sdelphij	const char *cp;
2904182007Sroberto
2905285612Sdelphij	parse->flags &= (u_char) (~PARSE_PPSCLOCK);
2906285612Sdelphij
2907285612Sdelphij	/*
2908285612Sdelphij	 * collect PPSAPI offset capability - should move into generic handling
2909285612Sdelphij	 */
2910285612Sdelphij	if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
2911182007Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2912182007Sroberto			CLK_UNIT(parse->peer));
2913285612Sdelphij
2914182007Sroberto		return 0;
2915182007Sroberto	}
2916182007Sroberto
2917285612Sdelphij	/*
2918285612Sdelphij	 * initialize generic PPSAPI interface
2919285612Sdelphij	 *
2920285612Sdelphij	 * we leave out CLK_FLAG3 as time_pps_kcbind()
2921285612Sdelphij	 * is handled here for now. Ideally this should also
2922285612Sdelphij	 * be part of the generic PPSAPI interface
2923285612Sdelphij	 */
2924285612Sdelphij	if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
2925182007Sroberto		return 0;
2926182007Sroberto
2927182007Sroberto	/* nb. only turn things on, if someone else has turned something
2928182007Sroberto	 *	on before we get here, leave it alone!
2929182007Sroberto	 */
2930182007Sroberto
2931182007Sroberto	if (parse->flags & PARSE_CLEAR) {
2932182007Sroberto		cp = "CLEAR";
2933285612Sdelphij		mode_ppsoffset = PPS_OFFSETCLEAR;
2934182007Sroberto	} else {
2935182007Sroberto		cp = "ASSERT";
2936285612Sdelphij		mode_ppsoffset = PPS_OFFSETASSERT;
2937182007Sroberto	}
2938182007Sroberto
2939182007Sroberto	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2940182007Sroberto		CLK_UNIT(parse->peer), cp);
2941182007Sroberto
2942285612Sdelphij	if (!(mode_ppsoffset & cap)) {
2943182007Sroberto	  msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2944182007Sroberto		  CLK_UNIT(parse->peer), cp, cap);
2945285612Sdelphij		mode_ppsoffset = 0;
2946182007Sroberto	} else {
2947285612Sdelphij		if (mode_ppsoffset == PPS_OFFSETCLEAR)
2948285612Sdelphij			{
2949285612Sdelphij				parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2950285612Sdelphij				parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2951182007Sroberto			}
2952285612Sdelphij
2953285612Sdelphij		if (mode_ppsoffset == PPS_OFFSETASSERT)
2954285612Sdelphij			{
2955285612Sdelphij				parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust);
2956285612Sdelphij				parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust));
2957182007Sroberto			}
2958182007Sroberto	}
2959182007Sroberto
2960285612Sdelphij	parse->atom.pps_params.mode |= mode_ppsoffset;
2961182007Sroberto
2962285612Sdelphij	if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
2963182007Sroberto	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2964182007Sroberto		  CLK_UNIT(parse->peer));
2965182007Sroberto		return 0;
2966182007Sroberto	}
2967182007Sroberto
2968182007Sroberto	parse->flags |= PARSE_PPSCLOCK;
2969182007Sroberto	return 1;
2970182007Sroberto}
2971182007Sroberto#else
2972182007Sroberto#define parse_hardpps(_PARSE_, _MODE_) /* empty */
2973182007Sroberto#endif
2974182007Sroberto
297554359Sroberto/*--------------------------------------------------
297654359Sroberto * parse_start - open the PARSE devices and initialize data for processing
297754359Sroberto */
297854359Srobertostatic int
297954359Srobertoparse_start(
298054359Sroberto	int sysunit,
298154359Sroberto	struct peer *peer
298254359Sroberto	)
298354359Sroberto{
298454359Sroberto	u_int unit;
298554359Sroberto	int fd232;
298654359Sroberto#ifdef HAVE_TERMIOS
298754359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
298854359Sroberto#endif
298954359Sroberto#ifdef HAVE_SYSV_TTYS
299054359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
299154359Sroberto#endif
299254359Sroberto	struct parseunit * parse;
299354359Sroberto	char parsedev[sizeof(PARSEDEVICE)+20];
2994182007Sroberto	char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
299554359Sroberto	parsectl_t tmp_ctl;
299654359Sroberto	u_int type;
299754359Sroberto
2998182007Sroberto	/*
2999182007Sroberto	 * get out Copyright information once
3000182007Sroberto	 */
3001182007Sroberto	if (!notice)
3002182007Sroberto        {
3003182007Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3004285612Sdelphij			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2015, Frank Kardel");
3005182007Sroberto		notice = 1;
3006182007Sroberto	}
3007182007Sroberto
300854359Sroberto	type = CLK_TYPE(peer);
300954359Sroberto	unit = CLK_UNIT(peer);
301054359Sroberto
3011285612Sdelphij	if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0))
301254359Sroberto	{
301354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
301454359Sroberto			unit, CLK_REALTYPE(peer), ncltypes-1);
301554359Sroberto		return 0;
301654359Sroberto	}
301754359Sroberto
301854359Sroberto	/*
301954359Sroberto	 * Unit okay, attempt to open the device.
302054359Sroberto	 */
3021182007Sroberto	(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
3022182007Sroberto	(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
302354359Sroberto
302454359Sroberto#ifndef O_NOCTTY
302554359Sroberto#define O_NOCTTY 0
302654359Sroberto#endif
3027285612Sdelphij#ifndef O_NONBLOCK
3028285612Sdelphij#define O_NONBLOCK 0
302954359Sroberto#endif
303054359Sroberto
3031285612Sdelphij	fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3032285612Sdelphij
303354359Sroberto	if (fd232 == -1)
303454359Sroberto	{
303554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
303654359Sroberto		return 0;
303754359Sroberto	}
303854359Sroberto
3039285612Sdelphij	parse = emalloc_zero(sizeof(*parse));
304054359Sroberto
304154359Sroberto	parse->generic = peer->procptr;	 /* link up */
304254359Sroberto	parse->generic->unitptr = (caddr_t)parse; /* link down */
304354359Sroberto
304454359Sroberto	/*
304554359Sroberto	 * Set up the structures
304654359Sroberto	 */
304754359Sroberto	parse->generic->timestarted    = current_time;
304854359Sroberto	parse->lastchange     = current_time;
304954359Sroberto
305054359Sroberto	parse->flags          = 0;
305154359Sroberto	parse->pollneeddata   = 0;
305254359Sroberto	parse->laststatistic  = current_time;
305354359Sroberto	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
3054182007Sroberto	parse->timedata.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
305554359Sroberto	parse->lastmissed     = 0;	/* assume got everything */
305654359Sroberto	parse->ppsserial      = 0;
3057182007Sroberto	parse->ppsfd	      = -1;
305854359Sroberto	parse->localdata      = (void *)0;
305954359Sroberto	parse->localstate     = 0;
306054359Sroberto	parse->kv             = (struct ctl_var *)0;
306154359Sroberto
306254359Sroberto	clear_err(parse, ERR_ALL);
3063285612Sdelphij
306454359Sroberto	parse->parse_type     = &parse_clockinfo[type];
3065285612Sdelphij
3066182007Sroberto	parse->maxunsync      = parse->parse_type->cl_maxunsync;
3067182007Sroberto
306854359Sroberto	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
306954359Sroberto
307054359Sroberto	parse->generic->fudgetime2 = 0.0;
3071182007Sroberto	parse->ppsphaseadjust = parse->generic->fudgetime2;
307254359Sroberto
3073182007Sroberto	parse->generic->clockdesc  = parse->parse_type->cl_description;
307454359Sroberto
307554359Sroberto	peer->rootdelay       = parse->parse_type->cl_rootdelay;
307654359Sroberto	peer->sstclktype      = parse->parse_type->cl_type;
307754359Sroberto	peer->precision       = sys_precision;
3078285612Sdelphij
307954359Sroberto	peer->stratum         = STRATUM_REFCLOCK;
3080182007Sroberto
308154359Sroberto	if (peer->stratum <= 1)
308254359Sroberto	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
308354359Sroberto	else
308454359Sroberto	    parse->generic->refid = htonl(PARSEHSREFID);
3085285612Sdelphij
308654359Sroberto	parse->generic->io.fd = fd232;
3087285612Sdelphij
308854359Sroberto	parse->peer = peer;		/* marks it also as busy */
308954359Sroberto
309054359Sroberto	/*
309154359Sroberto	 * configure terminal line
309254359Sroberto	 */
309354359Sroberto	if (TTY_GETATTR(fd232, &tio) == -1)
309454359Sroberto	{
309554359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
309654359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
309754359Sroberto		return 0;
309854359Sroberto	}
309954359Sroberto	else
310054359Sroberto	{
310154359Sroberto#ifndef _PC_VDISABLE
310254359Sroberto		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
310354359Sroberto#else
310454359Sroberto		int disablec;
310554359Sroberto		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
310654359Sroberto
310754359Sroberto		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
310854359Sroberto		if (disablec == -1 && errno)
310954359Sroberto		{
311054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
311154359Sroberto			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
311254359Sroberto		}
311354359Sroberto		else
311454359Sroberto		    if (disablec != -1)
311554359Sroberto			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
311654359Sroberto#endif
311754359Sroberto
311854359Sroberto#if defined (VMIN) || defined(VTIME)
311954359Sroberto		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
312054359Sroberto		{
312154359Sroberto#ifdef VMIN
312254359Sroberto			tio.c_cc[VMIN]   = 1;
312354359Sroberto#endif
312454359Sroberto#ifdef VTIME
312554359Sroberto			tio.c_cc[VTIME]  = 0;
312654359Sroberto#endif
312754359Sroberto		}
312854359Sroberto#endif
312954359Sroberto
3130285612Sdelphij		tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag;
3131285612Sdelphij		tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag;
3132285612Sdelphij		tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag;
3133285612Sdelphij		tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag;
313454359Sroberto
3135285612Sdelphij
313654359Sroberto#ifdef HAVE_TERMIOS
3137285612Sdelphij		if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) ||
3138285612Sdelphij		    (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1))
313954359Sroberto		{
314054359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
314154359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
314254359Sroberto			return 0;
314354359Sroberto		}
314454359Sroberto#else
314554359Sroberto		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
314654359Sroberto#endif
314754359Sroberto
3148182007Sroberto		/*
3149182007Sroberto		 * set up pps device
3150182007Sroberto		 * if the PARSEPPSDEVICE can be opened that will be used
3151182007Sroberto		 * for PPS else PARSEDEVICE will be used
3152182007Sroberto		 */
3153285612Sdelphij		parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3154182007Sroberto
3155182007Sroberto		if (parse->ppsfd == -1)
3156182007Sroberto		{
3157182007Sroberto			parse->ppsfd = fd232;
3158182007Sroberto		}
3159182007Sroberto
3160182007Sroberto/*
3161182007Sroberto * Linux PPS - the old way
3162182007Sroberto */
316354359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
316454359Sroberto		{
3165182007Sroberto			struct serial_struct	ss;
3166182007Sroberto			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
3167182007Sroberto			    (
316854359Sroberto#ifdef ASYNC_LOW_LATENCY
3169182007Sroberto			     ss.flags |= ASYNC_LOW_LATENCY,
317054359Sroberto#endif
3171182007Sroberto#ifndef HAVE_PPSAPI
317254359Sroberto#ifdef ASYNC_PPS_CD_NEG
3173182007Sroberto			     ss.flags |= ASYNC_PPS_CD_NEG,
317454359Sroberto#endif
3175182007Sroberto#endif
3176182007Sroberto			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3177182007Sroberto				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3178182007Sroberto				msyslog(LOG_NOTICE,
3179182007Sroberto					"refclock_parse: optional PPS processing not available");
3180182007Sroberto			} else {
3181182007Sroberto				parse->flags    |= PARSE_PPSCLOCK;
3182182007Sroberto#ifdef ASYNC_PPS_CD_NEG
3183182007Sroberto				NLOG(NLOG_CLOCKINFO)
3184182007Sroberto				  msyslog(LOG_INFO,
3185182007Sroberto					  "refclock_parse: PPS detection on");
3186182007Sroberto#endif
3187182007Sroberto			}
318854359Sroberto		}
318954359Sroberto#endif
3190182007Sroberto
3191182007Sroberto/*
3192182007Sroberto * SUN the Solaris way
3193182007Sroberto */
319454359Sroberto#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
319554359Sroberto		if (CLK_PPS(parse->peer))
3196182007Sroberto		    {
3197182007Sroberto			int i = 1;
3198285612Sdelphij
3199182007Sroberto			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3200182007Sroberto			    {
3201182007Sroberto				parse->flags |= PARSE_PPSCLOCK;
3202182007Sroberto			    }
3203182007Sroberto		    }
320454359Sroberto#endif
320554359Sroberto
3206182007Sroberto/*
3207182007Sroberto * PPS via PPSAPI
3208182007Sroberto */
3209182007Sroberto#if defined(HAVE_PPSAPI)
3210182007Sroberto		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3211182007Sroberto		if (CLK_PPS(parse->peer))
3212182007Sroberto		{
3213285612Sdelphij		  if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3214182007Sroberto		    {
3215182007Sroberto		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3216182007Sroberto		    }
3217182007Sroberto		  else
3218182007Sroberto		    {
3219182007Sroberto		      parse_ppsapi(parse);
3220182007Sroberto		    }
3221182007Sroberto		}
3222182007Sroberto#endif
3223182007Sroberto
322454359Sroberto		if (TTY_SETATTR(fd232, &tio) == -1)
322554359Sroberto		{
322654359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
322754359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
322854359Sroberto			return 0;
322954359Sroberto		}
323054359Sroberto	}
323154359Sroberto
323254359Sroberto	/*
3233182007Sroberto	 * pick correct input machine
323454359Sroberto	 */
3235285612Sdelphij	parse->generic->io.srcclock = peer;
323654359Sroberto	parse->generic->io.datalen = 0;
3237285612Sdelphij
323854359Sroberto	parse->binding = init_iobinding(parse);
323954359Sroberto
324054359Sroberto	if (parse->binding == (bind_t *)0)
324154359Sroberto		{
324254359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
324354359Sroberto			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
324454359Sroberto			return 0;			/* well, ok - special initialisation broke */
3245285612Sdelphij		}
324654359Sroberto
3247182007Sroberto	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3248182007Sroberto	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3249182007Sroberto
325054359Sroberto	/*
325154359Sroberto	 * as we always(?) get 8 bit chars we want to be
325254359Sroberto	 * sure, that the upper bits are zero for less
325354359Sroberto	 * than 8 bit I/O - so we pass that information on.
325454359Sroberto	 * note that there can be only one bit count format
325554359Sroberto	 * per file descriptor
325654359Sroberto	 */
325754359Sroberto
325854359Sroberto	switch (tio.c_cflag & CSIZE)
325954359Sroberto	{
326054359Sroberto	    case CS5:
326154359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
326254359Sroberto		break;
326354359Sroberto
326454359Sroberto	    case CS6:
326554359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
326654359Sroberto		break;
326754359Sroberto
326854359Sroberto	    case CS7:
326954359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
327054359Sroberto		break;
327154359Sroberto
327254359Sroberto	    case CS8:
327354359Sroberto		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
327454359Sroberto		break;
327554359Sroberto	}
327654359Sroberto
327754359Sroberto	if (!PARSE_SETCS(parse, &tmp_ctl))
327854359Sroberto	{
327954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
328054359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
328154359Sroberto		return 0;			/* well, ok - special initialisation broke */
328254359Sroberto	}
328354359Sroberto
3284285612Sdelphij	strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3285285612Sdelphij	tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer);
3286285612Sdelphij
328754359Sroberto	if (!PARSE_SETFMT(parse, &tmp_ctl))
328854359Sroberto	{
328954359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
329054359Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
329154359Sroberto		return 0;			/* well, ok - special initialisation broke */
329254359Sroberto	}
3293285612Sdelphij
329454359Sroberto	/*
329554359Sroberto	 * get rid of all IO accumulated so far
329654359Sroberto	 */
329754359Sroberto#ifdef HAVE_TERMIOS
329854359Sroberto	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
329954359Sroberto#else
3300182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH)
330154359Sroberto	{
330254359Sroberto		int flshcmd = TCIOFLUSH;
330354359Sroberto
330454359Sroberto		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
330554359Sroberto	}
330654359Sroberto#endif
330754359Sroberto#endif
330856746Sroberto
330954359Sroberto	/*
331054359Sroberto	 * try to do any special initializations
331154359Sroberto	 */
331254359Sroberto	if (parse->parse_type->cl_init)
331354359Sroberto		{
331454359Sroberto			if (parse->parse_type->cl_init(parse))
331554359Sroberto				{
331654359Sroberto					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
331754359Sroberto					return 0;		/* well, ok - special initialisation broke */
331854359Sroberto				}
331954359Sroberto		}
3320285612Sdelphij
332154359Sroberto	/*
3322182007Sroberto	 * Insert in async io device list.
332354359Sroberto	 */
3324182007Sroberto	if (!io_addclock(&parse->generic->io))
332554359Sroberto        {
3326182007Sroberto		msyslog(LOG_ERR,
3327182007Sroberto			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3328182007Sroberto		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3329182007Sroberto		return 0;
333054359Sroberto	}
333154359Sroberto
333254359Sroberto	/*
333354359Sroberto	 * print out configuration
333454359Sroberto	 */
333554359Sroberto	NLOG(NLOG_CLOCKINFO)
333654359Sroberto		{
333754359Sroberto			/* conditional if clause for conditional syslog */
3338182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
333954359Sroberto				CLK_UNIT(parse->peer),
3340182007Sroberto				parse->parse_type->cl_description, parsedev,
3341182007Sroberto				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
334254359Sroberto
3343182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
334454359Sroberto				CLK_UNIT(parse->peer),
3345182007Sroberto				parse->peer->stratum,
3346182007Sroberto				l_mktime(parse->maxunsync), parse->peer->precision);
334754359Sroberto
3348182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
334954359Sroberto				CLK_UNIT(parse->peer),
335054359Sroberto				parse->parse_type->cl_rootdelay,
335154359Sroberto				parse->generic->fudgetime1,
3352182007Sroberto				parse->ppsphaseadjust,
3353182007Sroberto                                parse->binding->bd_description);
335454359Sroberto
3355182007Sroberto			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
335654359Sroberto				parse->parse_type->cl_format);
3357182007Sroberto                        msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3358182007Sroberto				CLK_PPS(parse->peer) ? "" : "NO ",
3359182007Sroberto				CLK_PPS(parse->peer) ?
3360182007Sroberto#ifdef PPS_METHOD
3361182007Sroberto				" (implementation " PPS_METHOD ")"
3362182007Sroberto#else
3363182007Sroberto				""
336454359Sroberto#endif
3365182007Sroberto				: ""
3366182007Sroberto				);
336754359Sroberto		}
336854359Sroberto
336954359Sroberto	return 1;
337054359Sroberto}
337154359Sroberto
337254359Sroberto/*--------------------------------------------------
3373182007Sroberto * parse_ctl - process changes on flags/time values
3374182007Sroberto */
3375182007Srobertostatic void
3376182007Srobertoparse_ctl(
3377182007Sroberto	    struct parseunit *parse,
3378285612Sdelphij	    const struct refclockstat *in
3379182007Sroberto	    )
3380182007Sroberto{
3381182007Sroberto        if (in)
3382182007Sroberto	{
3383182007Sroberto		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3384182007Sroberto		{
3385285612Sdelphij		  u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4;
3386285612Sdelphij		  parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask);
3387182007Sroberto#if defined(HAVE_PPSAPI)
3388182007Sroberto		  if (CLK_PPS(parse->peer))
3389182007Sroberto		    {
3390182007Sroberto		      parse_ppsapi(parse);
3391182007Sroberto		    }
3392182007Sroberto#endif
3393182007Sroberto		}
3394285612Sdelphij
3395182007Sroberto		if (in->haveflags & CLK_HAVETIME1)
3396182007Sroberto                {
3397182007Sroberto		  parse->generic->fudgetime1 = in->fudgetime1;
3398182007Sroberto		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3399182007Sroberto			  CLK_UNIT(parse->peer),
3400182007Sroberto			  parse->generic->fudgetime1);
3401182007Sroberto		}
3402285612Sdelphij
3403182007Sroberto		if (in->haveflags & CLK_HAVETIME2)
3404182007Sroberto                {
3405182007Sroberto		  parse->generic->fudgetime2 = in->fudgetime2;
3406285612Sdelphij		  if (parse->flags & PARSE_TRUSTTIME)
3407182007Sroberto		    {
3408182007Sroberto		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3409182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3410182007Sroberto			      CLK_UNIT(parse->peer),
3411182007Sroberto			      l_mktime(parse->maxunsync));
3412182007Sroberto		    }
3413182007Sroberto		  else
3414182007Sroberto		    {
3415182007Sroberto		      parse->ppsphaseadjust = in->fudgetime2;
3416182007Sroberto		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3417182007Sroberto			  CLK_UNIT(parse->peer),
3418182007Sroberto			      parse->ppsphaseadjust);
3419182007Sroberto#if defined(HAVE_PPSAPI)
3420182007Sroberto		      if (CLK_PPS(parse->peer))
3421182007Sroberto		      {
3422182007Sroberto			      parse_ppsapi(parse);
3423182007Sroberto		      }
3424182007Sroberto#endif
3425182007Sroberto		    }
3426182007Sroberto		}
3427182007Sroberto	}
3428182007Sroberto}
3429182007Sroberto
3430182007Sroberto/*--------------------------------------------------
343154359Sroberto * parse_poll - called by the transmit procedure
343254359Sroberto */
343354359Srobertostatic void
343454359Srobertoparse_poll(
343554359Sroberto	int unit,
343654359Sroberto	struct peer *peer
343754359Sroberto	)
343854359Sroberto{
3439285612Sdelphij	struct parseunit *parse = peer->procptr->unitptr;
344054359Sroberto
344154359Sroberto	if (peer != parse->peer)
344254359Sroberto	{
344354359Sroberto		msyslog(LOG_ERR,
344454359Sroberto			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
344554359Sroberto			unit);
344654359Sroberto		return;
344754359Sroberto	}
344854359Sroberto
344954359Sroberto	/*
345054359Sroberto	 * Update clock stat counters
345154359Sroberto	 */
345254359Sroberto	parse->generic->polls++;
345354359Sroberto
3454285612Sdelphij	if (parse->pollneeddata &&
3455285612Sdelphij	    ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
345654359Sroberto	{
345754359Sroberto		/*
345856746Sroberto		 * start worrying when exceeding a poll inteval
345954359Sroberto		 * bad news - didn't get a response last time
346054359Sroberto		 */
346154359Sroberto		parse->lastmissed = current_time;
346254359Sroberto		parse_event(parse, CEVNT_TIMEOUT);
3463285612Sdelphij
346454359Sroberto		ERR(ERR_NODATA)
3465182007Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
346654359Sroberto	}
346754359Sroberto
346854359Sroberto	/*
346954359Sroberto	 * we just mark that we want the next sample for the clock filter
347054359Sroberto	 */
347156746Sroberto	parse->pollneeddata = current_time;
347254359Sroberto
347354359Sroberto	if (parse->parse_type->cl_poll)
347454359Sroberto	{
347554359Sroberto		parse->parse_type->cl_poll(parse);
347654359Sroberto	}
347754359Sroberto
347854359Sroberto	cparse_statistics(parse);
347954359Sroberto
348054359Sroberto	return;
348154359Sroberto}
348254359Sroberto
348354359Sroberto#define LEN_STATES 300		/* length of state string */
348454359Sroberto
348554359Sroberto/*--------------------------------------------------
348654359Sroberto * parse_control - set fudge factors, return statistics
348754359Sroberto */
348854359Srobertostatic void
348954359Srobertoparse_control(
349054359Sroberto	int unit,
3491285612Sdelphij	const struct refclockstat *in,
349254359Sroberto	struct refclockstat *out,
349354359Sroberto	struct peer *peer
349454359Sroberto	)
349554359Sroberto{
3496285612Sdelphij	struct parseunit *parse = peer->procptr->unitptr;
349754359Sroberto	parsectl_t tmpctl;
349854359Sroberto
349954359Sroberto	static char outstatus[400];	/* status output buffer */
350054359Sroberto
350154359Sroberto	if (out)
350254359Sroberto	{
350354359Sroberto		out->lencode       = 0;
350454359Sroberto		out->p_lastcode    = 0;
350554359Sroberto		out->kv_list       = (struct ctl_var *)0;
350654359Sroberto	}
350754359Sroberto
350854359Sroberto	if (!parse || !parse->peer)
350954359Sroberto	{
351054359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
351154359Sroberto			unit);
351254359Sroberto		return;
351354359Sroberto	}
351454359Sroberto
351554359Sroberto	unit = CLK_UNIT(parse->peer);
351654359Sroberto
3517182007Sroberto	/*
3518182007Sroberto	 * handle changes
3519182007Sroberto	 */
3520182007Sroberto	parse_ctl(parse, in);
3521285612Sdelphij
3522182007Sroberto	/*
3523182007Sroberto	 * supply data
3524182007Sroberto	 */
352554359Sroberto	if (out)
352654359Sroberto	{
352754359Sroberto		u_long sum = 0;
3528182007Sroberto		char *tt, *start;
352954359Sroberto		int i;
353054359Sroberto
353154359Sroberto		outstatus[0] = '\0';
353254359Sroberto
353354359Sroberto		out->type       = REFCLK_PARSE;
353454359Sroberto
353554359Sroberto		/*
3536182007Sroberto		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3537182007Sroberto		 */
3538182007Sroberto		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3539182007Sroberto
3540182007Sroberto		/*
354154359Sroberto		 * figure out skew between PPS and RS232 - just for informational
3542182007Sroberto		 * purposes
354354359Sroberto		 */
3544182007Sroberto		if (PARSE_SYNC(parse->timedata.parse_state))
354554359Sroberto		{
3546182007Sroberto			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
354754359Sroberto			{
354854359Sroberto				l_fp off;
354954359Sroberto
355054359Sroberto				/*
355154359Sroberto				 * we have a PPS and RS232 signal - calculate the skew
355254359Sroberto				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
355354359Sroberto				 */
3554182007Sroberto				off = parse->timedata.parse_stime.fp;
3555182007Sroberto				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
355654359Sroberto				tt = add_var(&out->kv_list, 80, RO);
3557182007Sroberto				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
355854359Sroberto			}
355954359Sroberto		}
356054359Sroberto
3561182007Sroberto		if (PARSE_PPS(parse->timedata.parse_state))
356254359Sroberto		{
356354359Sroberto			tt = add_var(&out->kv_list, 80, RO|DEF);
3564182007Sroberto			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
356554359Sroberto		}
356654359Sroberto
3567182007Sroberto		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3568285612Sdelphij		tt = ap(start, 128, tt, "refclock_time=\"");
356954359Sroberto
3570182007Sroberto		if (parse->timedata.parse_time.fp.l_ui == 0)
357154359Sroberto		{
3572285612Sdelphij			tt = ap(start, 128, tt, "<UNDEFINED>\"");
357354359Sroberto		}
357454359Sroberto		else
357554359Sroberto		{
3576285612Sdelphij			tt = ap(start, 128, tt, "%s\"",
3577285612Sdelphij			    gmprettydate(&parse->timedata.parse_time.fp));
357854359Sroberto		}
357954359Sroberto
358054359Sroberto		if (!PARSE_GETTIMECODE(parse, &tmpctl))
358154359Sroberto		{
358254359Sroberto			ERR(ERR_INTERNAL)
358354359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
358454359Sroberto		}
358554359Sroberto		else
358654359Sroberto		{
3587182007Sroberto			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3588285612Sdelphij			tt = ap(start, 512, tt, "refclock_status=\"");
358954359Sroberto
359054359Sroberto			/*
359154359Sroberto			 * copy PPS flags from last read transaction (informational only)
359254359Sroberto			 */
3593182007Sroberto			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
359454359Sroberto				(PARSEB_PPS|PARSEB_S_PPS);
359554359Sroberto
3596285612Sdelphij			(void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
359754359Sroberto
3598285612Sdelphij			tt += strlen(tt);
359954359Sroberto
3600285612Sdelphij			tt = ap(start, 512, tt, "\"");
3601285612Sdelphij
360254359Sroberto			if (tmpctl.parsegettc.parse_count)
360354359Sroberto			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3604182007Sroberto				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
360554359Sroberto
360654359Sroberto		}
3607285612Sdelphij
360854359Sroberto		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3609285612Sdelphij
361054359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
361154359Sroberto		{
361254359Sroberto			ERR(ERR_INTERNAL)
361354359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
361454359Sroberto		}
361554359Sroberto		else
361654359Sroberto		{
3617330141Sdelphij			int count = tmpctl.parseformat.parse_count;
3618330141Sdelphij			if (count)
3619330141Sdelphij				--count;
362054359Sroberto
3621285612Sdelphij			start = tt = add_var(&out->kv_list, 80, RO|DEF);
3622285612Sdelphij			tt = ap(start, 80, tt, "refclock_format=\"");
3623285612Sdelphij
3624285612Sdelphij			if (count > 0) {
3625285612Sdelphij				tt = ap(start, 80, tt, "%*.*s",
3626285612Sdelphij			        	count,
3627285612Sdelphij			        	count,
3628285612Sdelphij			        	tmpctl.parseformat.parse_buffer);
3629285612Sdelphij			}
3630285612Sdelphij
3631285612Sdelphij			tt = ap(start, 80, tt, "\"");
363254359Sroberto		}
363354359Sroberto
363454359Sroberto		/*
363554359Sroberto		 * gather state statistics
363654359Sroberto		 */
363754359Sroberto
363854359Sroberto		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3639285612Sdelphij		tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
364054359Sroberto
364154359Sroberto		for (i = 0; i <= CEVNT_MAX; i++)
364254359Sroberto		{
364354359Sroberto			u_long s_time;
364454359Sroberto			u_long d = current_time - parse->generic->timestarted;
364554359Sroberto			u_long percent;
364654359Sroberto
364754359Sroberto			percent = s_time = PARSE_STATETIME(parse, i);
364854359Sroberto
364954359Sroberto			while (((u_long)(~0) / 10000) < percent)
365054359Sroberto			{
365154359Sroberto				percent /= 10;
365254359Sroberto				d       /= 10;
365354359Sroberto			}
3654285612Sdelphij
365554359Sroberto			if (d)
365654359Sroberto			    percent = (percent * 10000) / d;
365754359Sroberto			else
365854359Sroberto			    percent = 10000;
365954359Sroberto
366054359Sroberto			if (s_time)
366154359Sroberto			{
366254359Sroberto				char item[80];
366354359Sroberto				int count;
3664285612Sdelphij
3665182007Sroberto				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
366654359Sroberto					sum ? "; " : "",
366754359Sroberto					(parse->generic->currentstatus == i) ? "*" : "",
366854359Sroberto					clockstatus((unsigned int)i),
366954359Sroberto					l_mktime(s_time),
367054359Sroberto					(int)(percent / 100), (int)(percent % 100));
3671285612Sdelphij				if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start)))
367254359Sroberto					{
3673285612Sdelphij						tt = ap(start, LEN_STATES, tt,
3674285612Sdelphij						    "%s", item);
367554359Sroberto					}
367654359Sroberto				sum += s_time;
367754359Sroberto			}
367854359Sroberto		}
3679285612Sdelphij
3680316069Sdelphij		ap(start, LEN_STATES, tt, "; running time: %s\"", l_mktime(sum));
3681285612Sdelphij
368254359Sroberto		tt = add_var(&out->kv_list, 32, RO);
3683182007Sroberto		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
3684285612Sdelphij
368554359Sroberto		tt = add_var(&out->kv_list, 80, RO);
3686182007Sroberto		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
368754359Sroberto
368854359Sroberto		tt = add_var(&out->kv_list, 128, RO);
3689182007Sroberto		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3690285612Sdelphij
369154359Sroberto		{
369254359Sroberto			struct ctl_var *k;
3693285612Sdelphij
369454359Sroberto			k = parse->kv;
369554359Sroberto			while (k && !(k->flags & EOV))
369654359Sroberto			{
369754359Sroberto				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
369854359Sroberto				k++;
369954359Sroberto			}
370054359Sroberto		}
3701285612Sdelphij
3702285612Sdelphij		out->lencode       = (u_short) strlen(outstatus);
370354359Sroberto		out->p_lastcode    = outstatus;
370454359Sroberto	}
370554359Sroberto}
370654359Sroberto
370754359Sroberto/**===========================================================================
370854359Sroberto ** processing routines
370954359Sroberto **/
371054359Sroberto
371154359Sroberto/*--------------------------------------------------
371254359Sroberto * event handling - note that nominal events will also be posted
3713182007Sroberto * keep track of state dwelling times
371454359Sroberto */
371554359Srobertostatic void
371654359Srobertoparse_event(
371754359Sroberto	struct parseunit *parse,
371854359Sroberto	int event
371954359Sroberto	)
372054359Sroberto{
372154359Sroberto	if (parse->generic->currentstatus != (u_char) event)
372254359Sroberto	{
372354359Sroberto		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
372454359Sroberto		parse->lastchange              = current_time;
372554359Sroberto
372654359Sroberto		if (parse->parse_type->cl_event)
372754359Sroberto		    parse->parse_type->cl_event(parse, event);
3728285612Sdelphij
3729182007Sroberto		if (event == CEVNT_NOMINAL)
373054359Sroberto		{
373154359Sroberto			NLOG(NLOG_CLOCKSTATUS)
373254359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
373354359Sroberto					CLK_UNIT(parse->peer));
373454359Sroberto		}
373554359Sroberto
3736182007Sroberto		refclock_report(parse->peer, event);
373754359Sroberto	}
373854359Sroberto}
373954359Sroberto
374054359Sroberto/*--------------------------------------------------
374154359Sroberto * process a PARSE time sample
374254359Sroberto */
374354359Srobertostatic void
374454359Srobertoparse_process(
374554359Sroberto	struct parseunit *parse,
374654359Sroberto	parsetime_t      *parsetime
374754359Sroberto	)
374854359Sroberto{
374954359Sroberto	l_fp off, rectime, reftime;
375054359Sroberto	double fudge;
3751285612Sdelphij
3752285612Sdelphij	/* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */
3753285612Sdelphij	ZERO(off);
3754285612Sdelphij
375554359Sroberto	/*
375654359Sroberto	 * check for changes in conversion status
375754359Sroberto	 * (only one for each new status !)
375854359Sroberto	 */
375954359Sroberto	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
376054359Sroberto	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3761182007Sroberto	    (parse->timedata.parse_status != parsetime->parse_status))
376254359Sroberto	{
376354359Sroberto		char buffer[400];
3764285612Sdelphij
376554359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
376654359Sroberto			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3767182007Sroberto				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3768285612Sdelphij
376954359Sroberto		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
377054359Sroberto		{
377154359Sroberto			/*
377254359Sroberto			 * tell more about the story - list time code
377354359Sroberto			 * there is a slight change for a race condition and
377454359Sroberto			 * the time code might be overwritten by the next packet
377554359Sroberto			 */
377654359Sroberto			parsectl_t tmpctl;
3777285612Sdelphij
377854359Sroberto			if (!PARSE_GETTIMECODE(parse, &tmpctl))
377954359Sroberto			{
378054359Sroberto				ERR(ERR_INTERNAL)
378154359Sroberto					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
378254359Sroberto			}
378354359Sroberto			else
378454359Sroberto			{
3785330141Sdelphij				unsigned int count = tmpctl.parsegettc.parse_count;
3786330141Sdelphij				if (count)
3787330141Sdelphij					--count;
378854359Sroberto				ERR(ERR_BADDATA)
3789330141Sdelphij				    msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3790330141Sdelphij					    CLK_UNIT(parse->peer),
3791330141Sdelphij					    mkascii(buffer, sizeof(buffer),
3792330141Sdelphij						    tmpctl.parsegettc.parse_buffer, count));
379354359Sroberto			}
3794285612Sdelphij			/* copy status to show only changes in case of failures */
3795285612Sdelphij			parse->timedata.parse_status = parsetime->parse_status;
379654359Sroberto		}
379754359Sroberto	}
379854359Sroberto
379954359Sroberto	/*
380054359Sroberto	 * examine status and post appropriate events
380154359Sroberto	 */
380254359Sroberto	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
380354359Sroberto	{
380454359Sroberto		/*
380554359Sroberto		 * got bad data - tell the rest of the system
380654359Sroberto		 */
380754359Sroberto		switch (parsetime->parse_status & CVT_MASK)
380854359Sroberto		{
380954359Sroberto		case CVT_NONE:
381054359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
381154359Sroberto			    parse->parse_type->cl_message)
381254359Sroberto				parse->parse_type->cl_message(parse, parsetime);
3813182007Sroberto			/*
3814182007Sroberto			 * save PPS information that comes piggyback
3815182007Sroberto			 */
3816182007Sroberto			if (PARSE_PPS(parsetime->parse_state))
3817182007Sroberto			  {
3818182007Sroberto			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3819182007Sroberto			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3820182007Sroberto			  }
382154359Sroberto			break; 		/* well, still waiting - timeout is handled at higher levels */
3822285612Sdelphij
382354359Sroberto		case CVT_FAIL:
382454359Sroberto			if (parsetime->parse_status & CVT_BADFMT)
382554359Sroberto			{
382654359Sroberto				parse_event(parse, CEVNT_BADREPLY);
382754359Sroberto			}
382854359Sroberto			else
382954359Sroberto				if (parsetime->parse_status & CVT_BADDATE)
383054359Sroberto				{
383154359Sroberto					parse_event(parse, CEVNT_BADDATE);
383254359Sroberto				}
383354359Sroberto				else
383454359Sroberto					if (parsetime->parse_status & CVT_BADTIME)
383554359Sroberto					{
383654359Sroberto						parse_event(parse, CEVNT_BADTIME);
383754359Sroberto					}
383854359Sroberto					else
383954359Sroberto					{
384054359Sroberto						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
384154359Sroberto					}
384254359Sroberto		}
384354359Sroberto		return;			/* skip the rest - useless */
384454359Sroberto	}
384554359Sroberto
384654359Sroberto	/*
384754359Sroberto	 * check for format changes
384854359Sroberto	 * (in case somebody has swapped clocks 8-)
384954359Sroberto	 */
385054359Sroberto	if (parse->lastformat != parsetime->parse_format)
385154359Sroberto	{
385254359Sroberto		parsectl_t tmpctl;
3853285612Sdelphij
385454359Sroberto		tmpctl.parseformat.parse_format = parsetime->parse_format;
385554359Sroberto
385654359Sroberto		if (!PARSE_GETFMT(parse, &tmpctl))
385754359Sroberto		{
385854359Sroberto			ERR(ERR_INTERNAL)
385954359Sroberto				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
386054359Sroberto		}
386154359Sroberto		else
386254359Sroberto		{
386354359Sroberto			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
386454359Sroberto				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
386554359Sroberto					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
386654359Sroberto		}
386754359Sroberto		parse->lastformat = parsetime->parse_format;
386854359Sroberto	}
386954359Sroberto
387054359Sroberto	/*
387154359Sroberto	 * now, any changes ?
387254359Sroberto	 */
3873182007Sroberto	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3874182007Sroberto	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
387554359Sroberto	{
387654359Sroberto		char tmp1[200];
387754359Sroberto		char tmp2[200];
387854359Sroberto		/*
3879182007Sroberto		 * something happend - except for PPS events
388054359Sroberto		 */
3881285612Sdelphij
3882182007Sroberto		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3883182007Sroberto		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3884285612Sdelphij
388554359Sroberto		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
388654359Sroberto			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
388754359Sroberto				CLK_UNIT(parse->peer), tmp2, tmp1);
388854359Sroberto	}
388954359Sroberto
389054359Sroberto	/*
3891182007Sroberto	 * carry on PPS information if still usable
3892182007Sroberto	 */
3893182007Sroberto	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3894182007Sroberto        {
3895182007Sroberto	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3896182007Sroberto		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3897182007Sroberto	}
3898182007Sroberto
3899182007Sroberto	/*
390054359Sroberto	 * remember for future
390154359Sroberto	 */
3902182007Sroberto	parse->timedata = *parsetime;
390354359Sroberto
390454359Sroberto	/*
390554359Sroberto	 * check to see, whether the clock did a complete powerup or lost PZF signal
390654359Sroberto	 * and post correct events for current condition
390754359Sroberto	 */
390854359Sroberto	if (PARSE_POWERUP(parsetime->parse_state))
390954359Sroberto	{
391054359Sroberto		/*
391154359Sroberto		 * this is bad, as we have completely lost synchronisation
391254359Sroberto		 * well this is a problem with the receiver here
391354359Sroberto		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
391454359Sroberto		 * is true as it is the powerup state and the time is taken
391554359Sroberto		 * from a crude real time clock chip
3916285612Sdelphij		 * for the PZF/GPS series this is only partly true, as
391754359Sroberto		 * PARSE_POWERUP only means that the pseudo random
391854359Sroberto		 * phase shift sequence cannot be found. this is only
391954359Sroberto		 * bad, if we have never seen the clock in the SYNC
392054359Sroberto		 * state, where the PHASE and EPOCH are correct.
392154359Sroberto		 * for reporting events the above business does not
392254359Sroberto		 * really matter, but we can use the time code
392354359Sroberto		 * even in the POWERUP state after having seen
392454359Sroberto		 * the clock in the synchronized state (PZF class
392554359Sroberto		 * receivers) unless we have had a telegram disruption
392654359Sroberto		 * after having seen the clock in the SYNC state. we
392754359Sroberto		 * thus require having seen the clock in SYNC state
392854359Sroberto		 * *after* having missed telegrams (noresponse) from
392954359Sroberto		 * the clock. one problem remains: we might use erroneously
393054359Sroberto		 * POWERUP data if the disruption is shorter than 1 polling
393154359Sroberto		 * interval. fortunately powerdowns last usually longer than 64
393254359Sroberto		 * seconds and the receiver is at least 2 minutes in the
393354359Sroberto		 * POWERUP or NOSYNC state before switching to SYNC
3934285612Sdelphij		 * for GPS receivers this can mean antenna problems and other causes.
3935285612Sdelphij		 * the additional grace period can be enables by a clock
3936285612Sdelphij		 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
393754359Sroberto		 */
393854359Sroberto		parse_event(parse, CEVNT_FAULT);
393954359Sroberto		NLOG(NLOG_CLOCKSTATUS)
394054359Sroberto			ERR(ERR_BADSTATUS)
3941285612Sdelphij			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
394254359Sroberto				CLK_UNIT(parse->peer));
394354359Sroberto	}
394454359Sroberto	else
394554359Sroberto	{
394654359Sroberto		/*
394754359Sroberto		 * we have two states left
394854359Sroberto		 *
394954359Sroberto		 * SYNC:
395054359Sroberto		 *  this state means that the EPOCH (timecode) and PHASE
395154359Sroberto		 *  information has be read correctly (at least two
395254359Sroberto		 *  successive PARSE timecodes were received correctly)
395354359Sroberto		 *  this is the best possible state - full trust
395454359Sroberto		 *
395554359Sroberto		 * NOSYNC:
395654359Sroberto		 *  The clock should be on phase with respect to the second
395754359Sroberto		 *  signal, but the timecode has not been received correctly within
395854359Sroberto		 *  at least the last two minutes. this is a sort of half baked state
395954359Sroberto		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
396054359Sroberto		 *  without timecode confirmation)
396154359Sroberto		 *  PZF 535 has also no time confirmation, but the phase should be
396254359Sroberto		 *  very precise as the PZF signal can be decoded
396354359Sroberto		 */
396454359Sroberto
396554359Sroberto		if (PARSE_SYNC(parsetime->parse_state))
396654359Sroberto		{
396754359Sroberto			/*
396854359Sroberto			 * currently completely synchronized - best possible state
396954359Sroberto			 */
397054359Sroberto			parse->lastsync = current_time;
397154359Sroberto			clear_err(parse, ERR_BADSTATUS);
397254359Sroberto		}
397354359Sroberto		else
397454359Sroberto		{
397554359Sroberto			/*
397654359Sroberto			 * we have had some problems receiving the time code
397754359Sroberto			 */
397854359Sroberto			parse_event(parse, CEVNT_PROP);
397954359Sroberto			NLOG(NLOG_CLOCKSTATUS)
398054359Sroberto				ERR(ERR_BADSTATUS)
398154359Sroberto				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
398254359Sroberto					CLK_UNIT(parse->peer));
398354359Sroberto		}
398454359Sroberto	}
398554359Sroberto
398654359Sroberto	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3987285612Sdelphij
398854359Sroberto	if (PARSE_TIMECODE(parsetime->parse_state))
398954359Sroberto	{
399054359Sroberto		rectime = parsetime->parse_stime.fp;
399154359Sroberto		off = reftime = parsetime->parse_time.fp;
3992285612Sdelphij
399354359Sroberto		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
399454359Sroberto
399554359Sroberto#ifdef DEBUG
399654359Sroberto		if (debug > 3)
399754359Sroberto			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
399854359Sroberto			       CLK_UNIT(parse->peer),
399954359Sroberto			       prettydate(&reftime),
400054359Sroberto			       prettydate(&rectime),
400154359Sroberto			       lfptoa(&off,6));
400254359Sroberto#endif
400354359Sroberto	}
400454359Sroberto
400554359Sroberto	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
400654359Sroberto	{
400754359Sroberto		l_fp offset;
4008182007Sroberto		double ppsphaseadjust = parse->ppsphaseadjust;
400954359Sroberto
4010182007Sroberto#ifdef HAVE_PPSAPI
401154359Sroberto		/*
4012182007Sroberto		 * set fudge = 0.0 if already included in PPS time stamps
4013182007Sroberto		 */
4014285612Sdelphij		if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
4015182007Sroberto		        {
4016182007Sroberto			        ppsphaseadjust = 0.0;
4017182007Sroberto			}
4018182007Sroberto#endif
4019182007Sroberto
4020182007Sroberto		/*
402154359Sroberto		 * we have a PPS signal - much better than the RS232 stuff (we hope)
402254359Sroberto		 */
402354359Sroberto		offset = parsetime->parse_ptime.fp;
402454359Sroberto
402554359Sroberto#ifdef DEBUG
402654359Sroberto		if (debug > 3)
402754359Sroberto			printf("PARSE receiver #%d: PPStime %s\n",
402854359Sroberto				CLK_UNIT(parse->peer),
402954359Sroberto				prettydate(&offset));
403054359Sroberto#endif
403154359Sroberto		if (PARSE_TIMECODE(parsetime->parse_state))
403254359Sroberto		{
4033285612Sdelphij			if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) &&
4034285612Sdelphij			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf))
403554359Sroberto			{
4036182007Sroberto				fudge = ppsphaseadjust; /* pick PPS fudge factor */
4037285612Sdelphij
403854359Sroberto				/*
403954359Sroberto				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
404054359Sroberto				 */
404154359Sroberto
404254359Sroberto				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
404354359Sroberto				{
404454359Sroberto					reftime = off = offset;
4045285612Sdelphij					if (reftime.l_uf & 0x80000000)
404654359Sroberto						reftime.l_ui++;
404754359Sroberto					reftime.l_uf = 0;
404856746Sroberto
4049285612Sdelphij
405054359Sroberto					/*
405154359Sroberto					 * implied on second offset
405254359Sroberto					 */
405354359Sroberto					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4054285612Sdelphij					off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
405554359Sroberto				}
405654359Sroberto				else
405754359Sroberto				{
405854359Sroberto					/*
405954359Sroberto					 * time code describes pulse
406054359Sroberto					 */
406154359Sroberto					reftime = off = parsetime->parse_time.fp;
406254359Sroberto
406354359Sroberto					L_SUB(&off, &offset); /* true offset */
406454359Sroberto				}
406554359Sroberto			}
406654359Sroberto			/*
406754359Sroberto			 * take RS232 offset when PPS when out of bounds
406854359Sroberto			 */
406954359Sroberto		}
407054359Sroberto		else
407154359Sroberto		{
4072182007Sroberto			fudge = ppsphaseadjust; /* pick PPS fudge factor */
407354359Sroberto			/*
407454359Sroberto			 * Well, no time code to guide us - assume on second pulse
407554359Sroberto			 * and pray, that we are within [-0.5..0.5[
407654359Sroberto			 */
407754359Sroberto			off = offset;
407854359Sroberto			reftime = offset;
4079285612Sdelphij			if (reftime.l_uf & 0x80000000)
408054359Sroberto				reftime.l_ui++;
408154359Sroberto			reftime.l_uf = 0;
408254359Sroberto			/*
408354359Sroberto			 * implied on second offset
408454359Sroberto			 */
408554359Sroberto			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4086285612Sdelphij			off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
408754359Sroberto		}
408854359Sroberto	}
408954359Sroberto	else
409054359Sroberto	{
409154359Sroberto		if (!PARSE_TIMECODE(parsetime->parse_state))
409254359Sroberto		{
409354359Sroberto			/*
409454359Sroberto			 * Well, no PPS, no TIMECODE, no more work ...
409554359Sroberto			 */
409654359Sroberto			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
409754359Sroberto			    parse->parse_type->cl_message)
409854359Sroberto				parse->parse_type->cl_message(parse, parsetime);
409954359Sroberto			return;
410054359Sroberto		}
410154359Sroberto	}
410254359Sroberto
410354359Sroberto#ifdef DEBUG
410454359Sroberto	if (debug > 3)
410554359Sroberto		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
410654359Sroberto			CLK_UNIT(parse->peer),
410754359Sroberto			prettydate(&reftime),
410854359Sroberto			prettydate(&rectime),
410954359Sroberto			lfptoa(&off,6));
411054359Sroberto#endif
411154359Sroberto
411254359Sroberto
411354359Sroberto	rectime = reftime;
411454359Sroberto	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
4115285612Sdelphij
411654359Sroberto#ifdef DEBUG
411754359Sroberto	if (debug > 3)
411854359Sroberto		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
411954359Sroberto			CLK_UNIT(parse->peer),
412054359Sroberto			prettydate(&reftime),
412154359Sroberto			prettydate(&rectime));
412254359Sroberto#endif
412354359Sroberto
412454359Sroberto	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
412554359Sroberto	    parse->parse_type->cl_message)
412654359Sroberto		parse->parse_type->cl_message(parse, parsetime);
412754359Sroberto
412854359Sroberto	if (PARSE_SYNC(parsetime->parse_state))
412954359Sroberto	{
413054359Sroberto		/*
413154359Sroberto		 * log OK status
413254359Sroberto		 */
413354359Sroberto		parse_event(parse, CEVNT_NOMINAL);
413454359Sroberto	}
413554359Sroberto
413654359Sroberto	clear_err(parse, ERR_BADIO);
413754359Sroberto	clear_err(parse, ERR_BADDATA);
413854359Sroberto	clear_err(parse, ERR_NODATA);
413954359Sroberto	clear_err(parse, ERR_INTERNAL);
4140285612Sdelphij
414154359Sroberto	/*
414254359Sroberto	 * and now stick it into the clock machine
414354359Sroberto	 * samples are only valid iff lastsync is not too old and
414454359Sroberto	 * we have seen the clock in sync at least once
414554359Sroberto	 * after the last time we didn't see an expected data telegram
4146182007Sroberto	 * at startup being not in sync is also bad just like
4147285612Sdelphij	 * POWERUP state unless PARSE_F_POWERUPTRUST is set
414854359Sroberto	 * see the clock states section above for more reasoning
414954359Sroberto	 */
4150285612Sdelphij	if (((current_time - parse->lastsync) > parse->maxunsync)           ||
4151285612Sdelphij	    (parse->lastsync < parse->lastmissed)                           ||
4152182007Sroberto	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
4153285612Sdelphij	    (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
4154285612Sdelphij	     PARSE_POWERUP(parsetime->parse_state)))
415554359Sroberto	{
415654359Sroberto		parse->generic->leap = LEAP_NOTINSYNC;
4157182007Sroberto		parse->lastsync = 0;	/* wait for full sync again */
415854359Sroberto	}
415954359Sroberto	else
416054359Sroberto	{
416154359Sroberto		if (PARSE_LEAPADD(parsetime->parse_state))
416254359Sroberto		{
416354359Sroberto			/*
416454359Sroberto			 * we pick this state also for time code that pass leap warnings
416554359Sroberto			 * without direction information (as earth is currently slowing
416654359Sroberto			 * down).
416754359Sroberto			 */
416854359Sroberto			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
416954359Sroberto		}
417054359Sroberto		else
417154359Sroberto		    if (PARSE_LEAPDEL(parsetime->parse_state))
417254359Sroberto		    {
417354359Sroberto			    parse->generic->leap = LEAP_DELSECOND;
417454359Sroberto		    }
417554359Sroberto		    else
417654359Sroberto		    {
417754359Sroberto			    parse->generic->leap = LEAP_NOWARNING;
417854359Sroberto		    }
417954359Sroberto	}
4180182007Sroberto
4181182007Sroberto	if (parse->generic->leap != LEAP_NOTINSYNC)
4182182007Sroberto	{
4183182007Sroberto	        /*
4184182007Sroberto		 * only good/trusted samples are interesting
4185182007Sroberto		 */
4186182007Sroberto#ifdef DEBUG
4187285612Sdelphij	        if (debug > 2)
4188285612Sdelphij			{
4189285612Sdelphij				       printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
4190182007Sroberto				       CLK_UNIT(parse->peer),
4191182007Sroberto				       prettydate(&reftime),
4192182007Sroberto				       prettydate(&rectime),
4193182007Sroberto				       fudge);
4194182007Sroberto			}
4195182007Sroberto#endif
4196182007Sroberto		parse->generic->lastref = reftime;
4197285612Sdelphij
4198182007Sroberto		refclock_process_offset(parse->generic, reftime, rectime, fudge);
4199182007Sroberto
4200285612Sdelphij#ifdef HAVE_PPSAPI
4201182007Sroberto		/*
4202182007Sroberto		 * pass PPS information on to PPS clock
4203182007Sroberto		 */
4204182007Sroberto		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4205285612Sdelphij			{
4206285612Sdelphij				parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS);
4207182007Sroberto				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4208182007Sroberto			}
4209285612Sdelphij#endif
4210182007Sroberto	} else {
4211285612Sdelphij		parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4212285612Sdelphij		parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS);
4213182007Sroberto	}
4214182007Sroberto
421554359Sroberto	/*
4216285612Sdelphij	 * ready, unless the machine wants a sample or
4217182007Sroberto	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
421854359Sroberto	 */
4219182007Sroberto	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
422054359Sroberto	    return;
422154359Sroberto
422254359Sroberto	parse->pollneeddata = 0;
422354359Sroberto
4224182007Sroberto	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4225182007Sroberto
422654359Sroberto	refclock_receive(parse->peer);
422754359Sroberto}
4228285612Sdelphij
422954359Sroberto/**===========================================================================
423054359Sroberto ** special code for special clocks
423154359Sroberto **/
423254359Sroberto
423354359Srobertostatic void
423454359Srobertomk_utcinfo(
4235316069Sdelphij	   char *t,  /* pointer to the output string buffer */
4236316069Sdelphij	   uint16_t wnt,
4237316069Sdelphij	   uint16_t wnlsf,
423854359Sroberto	   int dn,
423954359Sroberto	   int dtls,
4240182007Sroberto	   int dtlsf,
4241316069Sdelphij	   int size  /* size of the output string buffer */
424254359Sroberto	   )
424354359Sroberto{
4244285612Sdelphij	/*
4245285612Sdelphij	 * The week number transmitted by the GPS satellites for the leap date
4246285612Sdelphij	 * is truncated to 8 bits only. If the nearest leap second date is off
4247285612Sdelphij	 * the current date by more than +/- 128 weeks then conversion to a
4248285612Sdelphij	 * calendar date is ambiguous. On the other hand, if a leap second is
4249285612Sdelphij	 * currently being announced (i.e. dtlsf != dtls) then the week number
4250285612Sdelphij	 * wnlsf is close enough, and we can unambiguously determine the date
4251285612Sdelphij	 * for which the leap second is scheduled.
4252285612Sdelphij	 */
4253285612Sdelphij	if ( dtlsf != dtls )
4254285612Sdelphij	{
4255285612Sdelphij		time_t t_ls;
4256285612Sdelphij		struct tm *tm;
4257316069Sdelphij		int nc;
4258285612Sdelphij
4259285612Sdelphij		if (wnlsf < GPSWRAP)
4260285612Sdelphij			wnlsf += GPSWEEKS;
4261316069Sdelphij		/* 'wnt' not used here: would need the same treatment as 'wnlsf */
4262285612Sdelphij
4263285612Sdelphij		t_ls = (time_t) wnlsf * SECSPERWEEK
4264285612Sdelphij			+ (time_t) dn * SECSPERDAY
4265285612Sdelphij			+ GPS_SEC_BIAS - 1;
4266285612Sdelphij
4267285612Sdelphij		tm = gmtime( &t_ls );
4268316069Sdelphij		if (tm == NULL)  /* gmtime() failed */
4269285612Sdelphij		{
4270285612Sdelphij			snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" );
4271285612Sdelphij			return;
4272285612Sdelphij		}
4273285612Sdelphij
4274316069Sdelphij		nc = snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s",
4275285612Sdelphij				dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" );
4276316069Sdelphij		if (nc < 0)
4277316069Sdelphij			nc = strlen(t);
4278316069Sdelphij		else if (nc > size)
4279316069Sdelphij			nc = size;
4280316069Sdelphij
4281316069Sdelphij		snprintf( t + nc, size - nc, " at UTC midnight at the end of %s, %04i-%02i-%02i",
4282285612Sdelphij				daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday );
4283285612Sdelphij	}
4284285612Sdelphij	else
4285316069Sdelphij	{
4286285612Sdelphij		snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls );
4287316069Sdelphij	}
4288285612Sdelphij
428954359Sroberto}
429054359Sroberto
429154359Sroberto#ifdef CLOCK_MEINBERG
429254359Sroberto/**===========================================================================
4293285612Sdelphij ** Meinberg GPS receiver support
429454359Sroberto **/
429554359Sroberto
429654359Sroberto/*------------------------------------------------------------
4297285612Sdelphij * gps16x_message - process messages from Meinberg GPS receiver
429854359Sroberto */
429954359Srobertostatic void
430054359Srobertogps16x_message(
430154359Sroberto	       struct parseunit *parse,
430254359Sroberto	       parsetime_t      *parsetime
430354359Sroberto	       )
430454359Sroberto{
4305182007Sroberto	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
430654359Sroberto	{
430754359Sroberto		GPS_MSG_HDR header;
430854359Sroberto		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4309285612Sdelphij
431054359Sroberto#ifdef DEBUG
431154359Sroberto		if (debug > 2)
431254359Sroberto		{
431354359Sroberto			char msgbuffer[600];
4314285612Sdelphij
431554359Sroberto			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
431654359Sroberto			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
431754359Sroberto				CLK_UNIT(parse->peer),
431854359Sroberto				parsetime->parse_msglen,
431954359Sroberto				msgbuffer);
432054359Sroberto		}
432154359Sroberto#endif
432254359Sroberto		get_mbg_header(&bufp, &header);
4323285612Sdelphij		if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4324285612Sdelphij		    (header.len == 0 ||
4325285612Sdelphij		     (header.len < sizeof(parsetime->parse_msg) &&
4326285612Sdelphij		      header.data_csum == mbg_csum(bufp, header.len))))
432754359Sroberto		{
432854359Sroberto			/*
432954359Sroberto			 * clean message
433054359Sroberto			 */
4331285612Sdelphij			switch (header.cmd)
433254359Sroberto			{
433354359Sroberto			case GPS_SW_REV:
433454359Sroberto				{
433554359Sroberto					char buffer[64];
433654359Sroberto					SW_REV gps_sw_rev;
4337285612Sdelphij
433854359Sroberto					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4339182007Sroberto					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
434054359Sroberto						(gps_sw_rev.code >> 8) & 0xFF,
434154359Sroberto						gps_sw_rev.code & 0xFF,
434254359Sroberto						gps_sw_rev.name[0] ? " " : "",
434354359Sroberto						gps_sw_rev.name);
4344182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
434554359Sroberto				}
434654359Sroberto			break;
434754359Sroberto
4348285612Sdelphij			case GPS_BVAR_STAT:
434954359Sroberto				{
435054359Sroberto					static struct state
435154359Sroberto					{
4352285612Sdelphij						BVAR_STAT flag; /* status flag */
4353285612Sdelphij						const char *string; /* bit name */
435454359Sroberto					} states[] =
435554359Sroberto					  {
4356285612Sdelphij						  { BVAR_CFGH_INVALID,     "Configuration/Health" },
4357285612Sdelphij						  { BVAR_ALM_NOT_COMPLETE, "Almanachs" },
4358285612Sdelphij						  { BVAR_UTC_INVALID,      "UTC Correction" },
4359285612Sdelphij						  { BVAR_IONO_INVALID,     "Ionospheric Correction" },
4360285612Sdelphij						  { BVAR_RCVR_POS_INVALID, "Receiver Position" },
4361285612Sdelphij						  { 0, "" }
436254359Sroberto					  };
4363285612Sdelphij					BVAR_STAT status;
436454359Sroberto					struct state *s = states;
436554359Sroberto					char buffer[512];
436654359Sroberto					char *p, *b;
4367285612Sdelphij
4368285612Sdelphij					status = (BVAR_STAT) get_lsb_short(&bufp);
4369285612Sdelphij					p = b = buffer;
4370285612Sdelphij					p = ap(buffer, sizeof(buffer), p,
4371285612Sdelphij					    "meinberg_gps_status=\"[0x%04x] ",
4372285612Sdelphij					    status);
4373285612Sdelphij
437454359Sroberto					if (status)
437554359Sroberto					{
4376285612Sdelphij						p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: ");
4377285612Sdelphij						b = p;
437854359Sroberto						while (s->flag)
437954359Sroberto						{
438054359Sroberto							if (status & s->flag)
438154359Sroberto							{
438254359Sroberto								if (p != b)
438354359Sroberto								{
4384285612Sdelphij									p = ap(buffer, sizeof(buffer), p, ", ");
438554359Sroberto								}
4386285612Sdelphij
4387285612Sdelphij								p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
438854359Sroberto							}
438954359Sroberto							s++;
439054359Sroberto						}
4391285612Sdelphij						p = ap(buffer, sizeof(buffer), p, "\"");
439254359Sroberto					}
439354359Sroberto					else
439454359Sroberto					{
4395285612Sdelphij						p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\"");
439654359Sroberto					}
4397285612Sdelphij
4398182007Sroberto					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
439954359Sroberto				}
440054359Sroberto			break;
440154359Sroberto
440254359Sroberto			case GPS_POS_XYZ:
440354359Sroberto				{
440454359Sroberto					XYZ xyz;
440554359Sroberto					char buffer[256];
4406285612Sdelphij
440754359Sroberto					get_mbg_xyz(&bufp, xyz);
4408182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
440954359Sroberto						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
441054359Sroberto						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
441154359Sroberto						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4412285612Sdelphij
441354359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
441454359Sroberto				}
441554359Sroberto			break;
4416285612Sdelphij
441754359Sroberto			case GPS_POS_LLA:
441854359Sroberto				{
441954359Sroberto					LLA lla;
442054359Sroberto					char buffer[256];
4421285612Sdelphij
442254359Sroberto					get_mbg_lla(&bufp, lla);
4423285612Sdelphij
4424182007Sroberto					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
442554359Sroberto						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4426285612Sdelphij						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
442754359Sroberto						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4428285612Sdelphij
442954359Sroberto					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
443054359Sroberto				}
443154359Sroberto			break;
4432285612Sdelphij
443354359Sroberto			case GPS_TZDL:
443454359Sroberto				break;
4435285612Sdelphij
443654359Sroberto			case GPS_PORT_PARM:
443754359Sroberto				break;
4438285612Sdelphij
443954359Sroberto			case GPS_SYNTH:
444054359Sroberto				break;
4441285612Sdelphij
444254359Sroberto			case GPS_ANT_INFO:
444354359Sroberto				{
444454359Sroberto					ANT_INFO antinfo;
4445182007Sroberto					char buffer[512];
4446285612Sdelphij					char *p, *q;
4447285612Sdelphij
444854359Sroberto					get_mbg_antinfo(&bufp, &antinfo);
4449285612Sdelphij					p = buffer;
4450285612Sdelphij					p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
445154359Sroberto					switch (antinfo.status)
445254359Sroberto					{
4453285612Sdelphij					case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected
4454285612Sdelphij						p = ap(buffer, sizeof(buffer),
4455285612Sdelphij						    p, "<OK>");
445654359Sroberto						break;
4457285612Sdelphij
4458285612Sdelphij					case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set
4459285612Sdelphij						q = ap(buffer, sizeof(buffer),
4460285612Sdelphij						    p, "DISCONNECTED since ");
446154359Sroberto						NLOG(NLOG_CLOCKSTATUS)
446254359Sroberto							ERR(ERR_BADSTATUS)
446354359Sroberto							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
446454359Sroberto								CLK_UNIT(parse->peer), p);
4465285612Sdelphij
4466285612Sdelphij						p = q;
4467285612Sdelphij						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
446854359Sroberto						*p = '\0';
446954359Sroberto						break;
4470285612Sdelphij
4471285612Sdelphij					case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid
4472285612Sdelphij						p = ap(buffer, sizeof(buffer),
4473285612Sdelphij						    p, "SYNC AFTER RECONNECT on ");
4474285612Sdelphij						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0);
4475285612Sdelphij						p = ap(buffer, sizeof(buffer),
4476285612Sdelphij							p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ",
447754359Sroberto							(antinfo.delta_t < 0) ? '-' : '+',
4478285612Sdelphij							(long) ABS(antinfo.delta_t) / 10000,
4479285612Sdelphij							(long) ABS(antinfo.delta_t) % 10000);
4480285612Sdelphij						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0);
448154359Sroberto						*p = '\0';
448254359Sroberto						break;
4483285612Sdelphij
448454359Sroberto					default:
4485285612Sdelphij						p = ap(buffer, sizeof(buffer),
4486285612Sdelphij						    p, "bad status 0x%04x",
4487285612Sdelphij						    antinfo.status);
448854359Sroberto						break;
448954359Sroberto					}
4490285612Sdelphij
4491285612Sdelphij					p = ap(buffer, sizeof(buffer), p, "\"");
4492285612Sdelphij
4493285612Sdelphij					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
449454359Sroberto				}
449554359Sroberto			break;
4496285612Sdelphij
449754359Sroberto			case GPS_UCAP:
449854359Sroberto				break;
4499285612Sdelphij
450054359Sroberto			case GPS_CFGH:
450154359Sroberto				{
450254359Sroberto					CFGH cfgh;
4503182007Sroberto					char buffer[512];
4504182007Sroberto					char *p;
4505285612Sdelphij
450654359Sroberto					get_mbg_cfgh(&bufp, &cfgh);
450754359Sroberto					if (cfgh.valid)
450854359Sroberto					{
4509285612Sdelphij						const char *cp;
4510285612Sdelphij						uint16_t tmp_val;
451154359Sroberto						int i;
4512285612Sdelphij
451354359Sroberto						p = buffer;
4514285612Sdelphij						p = ap(buffer, sizeof(buffer),
4515285612Sdelphij						    p, "gps_tot_51=\"");
4516182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4517285612Sdelphij						p = ap(buffer, sizeof(buffer),
4518285612Sdelphij						    p, "\"");
4519285612Sdelphij						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4520285612Sdelphij
452154359Sroberto						p = buffer;
4522285612Sdelphij						p = ap(buffer, sizeof(buffer),
4523285612Sdelphij						    p, "gps_tot_63=\"");
4524182007Sroberto						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4525285612Sdelphij						p = ap(buffer, sizeof(buffer),
4526285612Sdelphij						    p, "\"");
4527285612Sdelphij						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4528285612Sdelphij
452954359Sroberto						p = buffer;
4530285612Sdelphij						p = ap(buffer, sizeof(buffer),
4531285612Sdelphij						    p, "gps_t0a=\"");
4532182007Sroberto						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4533285612Sdelphij						p = ap(buffer, sizeof(buffer),
4534285612Sdelphij						    p, "\"");
4535285612Sdelphij						set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
4536285612Sdelphij
4537285612Sdelphij						for (i = 0; i < N_SVNO_GPS; i++)
453854359Sroberto						{
453954359Sroberto							p = buffer;
4540285612Sdelphij							p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS);
4541285612Sdelphij
4542285612Sdelphij							tmp_val = cfgh.health[i];  /* a 6 bit SV health code */
4543285612Sdelphij							p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val);
4544285612Sdelphij							/* "All Ones" has a special meaning" */
4545285612Sdelphij							if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */
4546285612Sdelphij								cp = "SV UNAVAILABLE";
4547285612Sdelphij							else {
4548285612Sdelphij								/* The MSB contains a summary of the 3 MSBs of the 8 bit health code,
4549285612Sdelphij								 * indicating if the data sent by the satellite is OK or not. */
4550285612Sdelphij								p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" );
4551285612Sdelphij
4552285612Sdelphij								/* The 5 LSBs contain the status of the different signals sent by the satellite. */
4553285612Sdelphij								switch (tmp_val & 0x1F)
4554285612Sdelphij								{
4555285612Sdelphij									case 0x00: cp = "SIGNAL OK";              break;
4556285612Sdelphij									/* codes 0x01 through 0x1B indicate that one or more
4557285612Sdelphij									 * specific signal components are weak or dead.
4558285612Sdelphij									 * We don't decode this here in detail. */
4559285612Sdelphij									case 0x1C: cp = "SV IS TEMP OUT";         break;
4560285612Sdelphij									case 0x1D: cp = "SV WILL BE TEMP OUT";    break;
4561285612Sdelphij									default:   cp = "TRANSMISSION PROBLEMS";  break;
4562285612Sdelphij								}
456354359Sroberto							}
4564285612Sdelphij							p = ap(buffer, sizeof(buffer), p, "%s)", cp );
4565285612Sdelphij
4566285612Sdelphij							tmp_val = cfgh.cfg[i];  /* a 4 bit SV configuration/type code */
4567285612Sdelphij							p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val);
4568285612Sdelphij							switch (tmp_val & 0x7)
456954359Sroberto							{
4570285612Sdelphij								case 0x00:  cp = "(reserved)";        break;
4571285612Sdelphij								case 0x01:  cp = "BLOCK II/IIA/IIR";  break;
4572285612Sdelphij								case 0x02:  cp = "BLOCK IIR-M";       break;
4573285612Sdelphij								case 0x03:  cp = "BLOCK IIF";         break;
4574285612Sdelphij								case 0x04:  cp = "BLOCK III";         break;
4575285612Sdelphij								default:   cp = "unknown SV type";   break;
457654359Sroberto							}
4577285612Sdelphij							p = ap(buffer, sizeof(buffer), p, "%s", cp );
4578285612Sdelphij							if (tmp_val & 0x08)  /* A-S is on, P-code is encrypted */
4579285612Sdelphij								p = ap( buffer, sizeof(buffer), p, ", A-S on" );
4580285612Sdelphij
4581285612Sdelphij							p = ap(buffer, sizeof(buffer), p, ")\"");
4582285612Sdelphij							set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF);
458354359Sroberto						}
458454359Sroberto					}
458554359Sroberto				}
458654359Sroberto			break;
4587285612Sdelphij
458854359Sroberto			case GPS_ALM:
458954359Sroberto				break;
4590285612Sdelphij
459154359Sroberto			case GPS_EPH:
459254359Sroberto				break;
4593285612Sdelphij
459454359Sroberto			case GPS_UTC:
459554359Sroberto				{
459654359Sroberto					UTC utc;
459754359Sroberto					char buffer[512];
459854359Sroberto					char *p;
4599285612Sdelphij
460054359Sroberto					p = buffer;
4601285612Sdelphij
460254359Sroberto					get_mbg_utc(&bufp, &utc);
4603285612Sdelphij
460454359Sroberto					if (utc.valid)
460554359Sroberto					{
4606285612Sdelphij						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
4607285612Sdelphij						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
460854359Sroberto						p += strlen(p);
4609285612Sdelphij						p = ap(buffer, sizeof(buffer), p, "\"");
461054359Sroberto					}
461154359Sroberto					else
461254359Sroberto					{
4613285612Sdelphij						p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
461454359Sroberto					}
4615285612Sdelphij					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
461654359Sroberto				}
461754359Sroberto			break;
4618285612Sdelphij
461954359Sroberto			case GPS_IONO:
462054359Sroberto				break;
4621285612Sdelphij
462254359Sroberto			case GPS_ASCII_MSG:
462354359Sroberto				{
462454359Sroberto					ASCII_MSG gps_ascii_msg;
462554359Sroberto					char buffer[128];
4626285612Sdelphij
462754359Sroberto					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4628285612Sdelphij
462954359Sroberto					if (gps_ascii_msg.valid)
463054359Sroberto						{
463154359Sroberto							char buffer1[128];
463254359Sroberto							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4633285612Sdelphij
4634182007Sroberto							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
463554359Sroberto						}
463654359Sroberto					else
4637285612Sdelphij						snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
4638285612Sdelphij
4639285612Sdelphij					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
464054359Sroberto				}
4641285612Sdelphij
464254359Sroberto			break;
4643285612Sdelphij
464454359Sroberto			default:
464554359Sroberto				break;
464654359Sroberto			}
464754359Sroberto		}
464854359Sroberto		else
464954359Sroberto		{
4650285612Sdelphij			msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), "
4651285612Sdelphij			                   "data_len = %d, data_csum = 0x%x (expected 0x%x)",
465254359Sroberto				CLK_UNIT(parse->peer),
4653285612Sdelphij				header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4654285612Sdelphij				header.len,
4655285612Sdelphij				header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0)));
465654359Sroberto		}
465754359Sroberto	}
4658285612Sdelphij
465954359Sroberto	return;
466054359Sroberto}
466154359Sroberto
466254359Sroberto/*------------------------------------------------------------
466354359Sroberto * gps16x_poll - query the reciver peridically
466454359Sroberto */
466554359Srobertostatic void
466654359Srobertogps16x_poll(
466754359Sroberto	    struct peer *peer
466854359Sroberto	    )
466954359Sroberto{
4670285612Sdelphij	struct parseunit *parse = peer->procptr->unitptr;
4671285612Sdelphij
4672285612Sdelphij	static GPS_MSG_HDR sequence[] =
467354359Sroberto	{
467454359Sroberto		{ GPS_SW_REV,          0, 0, 0 },
4675285612Sdelphij		{ GPS_BVAR_STAT,       0, 0, 0 },
467654359Sroberto		{ GPS_UTC,             0, 0, 0 },
467754359Sroberto		{ GPS_ASCII_MSG,       0, 0, 0 },
467854359Sroberto		{ GPS_ANT_INFO,        0, 0, 0 },
467954359Sroberto		{ GPS_CFGH,            0, 0, 0 },
468054359Sroberto		{ GPS_POS_XYZ,         0, 0, 0 },
468154359Sroberto		{ GPS_POS_LLA,         0, 0, 0 },
468254359Sroberto		{ (unsigned short)~0,  0, 0, 0 }
468354359Sroberto	};
4684285612Sdelphij
468554359Sroberto	int rtc;
468654359Sroberto	unsigned char cmd_buffer[64];
468754359Sroberto	unsigned char *outp = cmd_buffer;
468854359Sroberto	GPS_MSG_HDR *header;
4689285612Sdelphij
469054359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
469154359Sroberto	{
4692285612Sdelphij		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
469354359Sroberto	}
469454359Sroberto
4695285612Sdelphij	if (sequence[parse->localstate].cmd == (unsigned short)~0)
469654359Sroberto		parse->localstate = 0;
4697285612Sdelphij
469854359Sroberto	header = sequence + parse->localstate++;
4699285612Sdelphij
470054359Sroberto	*outp++ = SOH;		/* start command */
4701285612Sdelphij
470254359Sroberto	put_mbg_header(&outp, header);
470354359Sroberto	outp = cmd_buffer + 1;
4704285612Sdelphij
4705285612Sdelphij	header->hdr_csum = (short)mbg_csum(outp, 6);
470654359Sroberto	put_mbg_header(&outp, header);
4707285612Sdelphij
470854359Sroberto#ifdef DEBUG
470954359Sroberto	if (debug > 2)
471054359Sroberto	{
471154359Sroberto		char buffer[128];
4712285612Sdelphij
471354359Sroberto		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
471454359Sroberto		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
471554359Sroberto		       CLK_UNIT(parse->peer),
471654359Sroberto		       parse->localstate - 1,
471754359Sroberto		       (int)(outp - cmd_buffer),
4718285612Sdelphij		       buffer);
471954359Sroberto	}
472054359Sroberto#endif
4721285612Sdelphij
4722285612Sdelphij	rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4723285612Sdelphij
472454359Sroberto	if (rtc < 0)
472554359Sroberto	{
472654359Sroberto		ERR(ERR_BADIO)
472754359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
472854359Sroberto	}
472954359Sroberto	else
473054359Sroberto	if (rtc != outp - cmd_buffer)
473154359Sroberto	{
473254359Sroberto		ERR(ERR_BADIO)
473354359Sroberto			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));
473454359Sroberto	}
473554359Sroberto
473654359Sroberto	clear_err(parse, ERR_BADIO);
473754359Sroberto	return;
473854359Sroberto}
473954359Sroberto
474054359Sroberto/*--------------------------------------------------
474154359Sroberto * init routine - setup timer
474254359Sroberto */
474354359Srobertostatic int
474454359Srobertogps16x_poll_init(
474554359Sroberto	struct parseunit *parse
474654359Sroberto	)
474754359Sroberto{
474854359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
474954359Sroberto	{
4750285612Sdelphij		parse->peer->procptr->action = gps16x_poll;
475154359Sroberto		gps16x_poll(parse->peer);
475254359Sroberto	}
475354359Sroberto
475454359Sroberto	return 0;
475554359Sroberto}
475654359Sroberto
475754359Sroberto#else
475854359Srobertostatic void
475954359Srobertogps16x_message(
476054359Sroberto	       struct parseunit *parse,
476154359Sroberto	       parsetime_t      *parsetime
476254359Sroberto	       )
476354359Sroberto{}
476454359Srobertostatic int
476554359Srobertogps16x_poll_init(
476654359Sroberto	struct parseunit *parse
476754359Sroberto	)
476854359Sroberto{
476954359Sroberto	return 1;
477054359Sroberto}
477154359Sroberto#endif /* CLOCK_MEINBERG */
4772285612Sdelphij
477354359Sroberto/**===========================================================================
477454359Sroberto ** clock polling support
477554359Sroberto **/
477654359Sroberto
477754359Sroberto/*--------------------------------------------------
477854359Sroberto * direct poll routine
477954359Sroberto */
478054359Srobertostatic void
478154359Srobertopoll_dpoll(
478254359Sroberto	struct parseunit *parse
478354359Sroberto	)
478454359Sroberto{
4785285612Sdelphij	long rtc;
478654359Sroberto	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4787285612Sdelphij	long ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
478854359Sroberto
4789285612Sdelphij	rtc = write(parse->generic->io.fd, ps, ct);
479054359Sroberto	if (rtc < 0)
479154359Sroberto	{
479254359Sroberto		ERR(ERR_BADIO)
479354359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
479454359Sroberto	}
479554359Sroberto	else
479654359Sroberto	    if (rtc != ct)
479754359Sroberto	    {
479854359Sroberto		    ERR(ERR_BADIO)
4799285612Sdelphij			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
480054359Sroberto	    }
480154359Sroberto	clear_err(parse, ERR_BADIO);
480254359Sroberto}
480354359Sroberto
480454359Sroberto/*--------------------------------------------------
480554359Sroberto * periodic poll routine
480654359Sroberto */
480754359Srobertostatic void
480854359Srobertopoll_poll(
480954359Sroberto	struct peer *peer
481054359Sroberto	)
481154359Sroberto{
4812285612Sdelphij	struct parseunit *parse = peer->procptr->unitptr;
4813285612Sdelphij
481454359Sroberto	if (parse->parse_type->cl_poll)
481554359Sroberto		parse->parse_type->cl_poll(parse);
481654359Sroberto
481754359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
481854359Sroberto	{
4819285612Sdelphij		parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
482054359Sroberto	}
482154359Sroberto}
482254359Sroberto
482354359Sroberto/*--------------------------------------------------
482454359Sroberto * init routine - setup timer
482554359Sroberto */
482654359Srobertostatic int
482754359Srobertopoll_init(
482854359Sroberto	struct parseunit *parse
482954359Sroberto	)
483054359Sroberto{
483154359Sroberto	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
483254359Sroberto	{
4833285612Sdelphij		parse->peer->procptr->action = poll_poll;
483454359Sroberto		poll_poll(parse->peer);
483554359Sroberto	}
483654359Sroberto
483754359Sroberto	return 0;
483854359Sroberto}
4839285612Sdelphij
484054359Sroberto/**===========================================================================
484154359Sroberto ** Trimble support
484254359Sroberto **/
484354359Sroberto
484454359Sroberto/*-------------------------------------------------------------
484554359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init.
484654359Sroberto */
484754359Srobertostatic int
484854359Srobertotrimbletaip_init(
484954359Sroberto	struct parseunit *parse
485054359Sroberto	)
485154359Sroberto{
485254359Sroberto#ifdef HAVE_TERMIOS
485354359Sroberto	struct termios tio;
485454359Sroberto#endif
485554359Sroberto#ifdef HAVE_SYSV_TTYS
485654359Sroberto	struct termio tio;
485754359Sroberto#endif
485854359Sroberto	/*
485954359Sroberto	 * configure terminal line for trimble receiver
486054359Sroberto	 */
486154359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
486254359Sroberto	{
486354359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
486454359Sroberto		return 0;
486554359Sroberto	}
486654359Sroberto	else
486754359Sroberto	{
486854359Sroberto		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4869285612Sdelphij
487054359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
487154359Sroberto		{
487254359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
487354359Sroberto			return 0;
487454359Sroberto		}
487554359Sroberto	}
487654359Sroberto	return poll_init(parse);
487754359Sroberto}
487854359Sroberto
487954359Sroberto/*--------------------------------------------------
488054359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble
488154359Sroberto */
488254359Srobertostatic const char *taipinit[] = {
488354359Sroberto	">FPV00000000<",
488454359Sroberto	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
488554359Sroberto	">FTM00020001<",
488654359Sroberto	(char *)0
488754359Sroberto};
4888285612Sdelphij
488954359Srobertostatic void
489054359Srobertotrimbletaip_event(
489154359Sroberto	struct parseunit *parse,
489254359Sroberto	int event
489354359Sroberto	)
489454359Sroberto{
489554359Sroberto	switch (event)
489654359Sroberto	{
489754359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
489854359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
489954359Sroberto		    {
490054359Sroberto			    const char **iv;
490154359Sroberto
490254359Sroberto			    iv = taipinit;
490354359Sroberto			    while (*iv)
490454359Sroberto			    {
4905285612Sdelphij				    int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv));
490654359Sroberto				    if (rtc < 0)
490754359Sroberto				    {
490854359Sroberto					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
490954359Sroberto					    return;
491054359Sroberto				    }
491154359Sroberto				    else
491254359Sroberto				    {
4913285612Sdelphij					    if (rtc != (int)strlen(*iv))
491454359Sroberto					    {
491554359Sroberto						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
491654359Sroberto							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
491754359Sroberto						    return;
491854359Sroberto					    }
491954359Sroberto				    }
492054359Sroberto				    iv++;
492154359Sroberto			    }
492254359Sroberto
492354359Sroberto			    NLOG(NLOG_CLOCKINFO)
492454359Sroberto				    ERR(ERR_BADIO)
492554359Sroberto				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
492654359Sroberto					    CLK_UNIT(parse->peer));
492754359Sroberto		    }
492854359Sroberto		    break;
492954359Sroberto
493054359Sroberto	    default:			/* ignore */
493154359Sroberto		break;
493254359Sroberto	}
493354359Sroberto}
493454359Sroberto
493554359Sroberto/*
493654359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module.
493754359Sroberto * It should support other Trimble receivers which use the Trimble Standard
493854359Sroberto * Interface Protocol (see below).
493954359Sroberto *
494054359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second
494154359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is
494254359Sroberto * coincident with the change of the GPS second. This is the same as
494354359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks
494454359Sroberto * specifically use a feature in the data message as a timing reference, but
494554359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter
494654359Sroberto * on the timing of the messages, so this driver only supports the use
494754359Sroberto * of the PPS pulse for accurate timing. Where it is determined that
494854359Sroberto * the offset is way off, when first starting up ntpd for example,
494954359Sroberto * the timing of the data stream is used until the offset becomes low enough
495056746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used.
495154359Sroberto *
495254359Sroberto * It can use either option for receiving PPS information - the 'ppsclock'
495354359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier
495454359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only
495554359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in
495654359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter
495754359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another
495854359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input,
495954359Sroberto * by whichever method, is handled in ntp_loopfilter.c
496054359Sroberto *
496154359Sroberto * The receiver uses a serial message protocol called Trimble Standard
496254359Sroberto * Interface Protocol (it can support others but this driver only supports
496354359Sroberto * TSIP). Messages in this protocol have the following form:
496454359Sroberto *
496554359Sroberto * <DLE><id> ... <data> ... <DLE><ETX>
496654359Sroberto *
496754359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
496854359Sroberto * on transmission and compressed back to one on reception. Otherwise
496954359Sroberto * the values of data bytes can be anything. The serial interface is RS-422
497054359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
497154359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single,
497254359Sroberto * and double datatypes. Integers are two bytes, sent most significant first.
497354359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent
497454359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point
497554359Sroberto * numbers (8 byte) sent sign & exponent first.
497654359Sroberto * The receiver supports a large set of messages, only a small subset of
497754359Sroberto * which are used here. From driver to receiver the following are used:
497854359Sroberto *
497954359Sroberto *  ID    Description
498054359Sroberto *
498154359Sroberto *  21    Request current time
498254359Sroberto *  22    Mode Select
498354359Sroberto *  2C    Set/Request operating parameters
498454359Sroberto *  2F    Request UTC info
498554359Sroberto *  35    Set/Request I/O options
498654359Sroberto
498754359Sroberto * From receiver to driver the following are recognised:
498854359Sroberto *
498954359Sroberto *  ID    Description
499054359Sroberto *
499154359Sroberto *  41    GPS Time
499254359Sroberto *  44    Satellite selection, PDOP, mode
499354359Sroberto *  46    Receiver health
499454359Sroberto *  4B    Machine code/status
499554359Sroberto *  4C    Report operating parameters (debug only)
499654359Sroberto *  4F    UTC correction data (used to get leap second warnings)
499754359Sroberto *  55    I/O options (debug only)
499854359Sroberto *
499954359Sroberto * All others are accepted but ignored.
500054359Sroberto *
500154359Sroberto */
500254359Sroberto
500354359Sroberto#define PI		3.1415926535898	/* lots of sig figs */
500454359Sroberto#define D2R		PI/180.0
500554359Sroberto
500654359Sroberto/*-------------------------------------------------------------------
500754359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
500854359Sroberto * interface to the receiver.
500954359Sroberto *
501054359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and
501154359Sroberto * float implementation dependend - these must be converted to portable
501254359Sroberto * versions !
501354359Sroberto *
501454359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems
501554359Sroberto * with IEEE754 floats as native floats
501654359Sroberto */
501754359Sroberto
501854359Srobertotypedef struct trimble
501954359Sroberto{
502054359Sroberto	u_long last_msg;	/* last message received */
5021182007Sroberto	u_long last_reset;	/* last time a reset was issued */
502254359Sroberto	u_char qtracking;	/* query tracking status */
502354359Sroberto	u_long ctrack;		/* current tracking set */
502454359Sroberto	u_long ltrack;		/* last tracking set */
502554359Sroberto} trimble_t;
502654359Sroberto
502754359Srobertounion uval {
502854359Sroberto	u_char  bd[8];
502954359Sroberto	int     iv;
503054359Sroberto	float   fv;
503154359Sroberto	double  dv;
503254359Sroberto};
5033285612Sdelphij
503454359Srobertostruct txbuf
503554359Sroberto{
503654359Sroberto	short idx;			/* index to first unused byte */
503754359Sroberto	u_char *txt;			/* pointer to actual data buffer */
503854359Sroberto};
503954359Sroberto
5040285612Sdelphijvoid	sendcmd		(struct txbuf *buf, int c);
5041285612Sdelphijvoid	sendbyte	(struct txbuf *buf, int b);
5042285612Sdelphijvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5043285612Sdelphijvoid	sendint		(struct txbuf *buf, int a);
5044285612Sdelphijvoid	sendflt		(struct txbuf *buf, double a);
5045285612Sdelphij
504654359Srobertovoid
504754359Srobertosendcmd(
504854359Sroberto	struct txbuf *buf,
504954359Sroberto	int c
505054359Sroberto	)
505154359Sroberto{
505254359Sroberto	buf->txt[0] = DLE;
505354359Sroberto	buf->txt[1] = (u_char)c;
505454359Sroberto	buf->idx = 2;
505554359Sroberto}
505654359Sroberto
5057285612Sdelphijvoid	sendcmd		(struct txbuf *buf, int c);
5058285612Sdelphijvoid	sendbyte	(struct txbuf *buf, int b);
5059285612Sdelphijvoid	sendetx		(struct txbuf *buf, struct parseunit *parse);
5060285612Sdelphijvoid	sendint		(struct txbuf *buf, int a);
5061285612Sdelphijvoid	sendflt		(struct txbuf *buf, double a);
5062285612Sdelphij
506354359Srobertovoid
506454359Srobertosendbyte(
506554359Sroberto	struct txbuf *buf,
506654359Sroberto	int b
506754359Sroberto	)
506854359Sroberto{
506954359Sroberto	if (b == DLE)
507054359Sroberto	    buf->txt[buf->idx++] = DLE;
507154359Sroberto	buf->txt[buf->idx++] = (u_char)b;
507254359Sroberto}
507354359Sroberto
507454359Srobertovoid
507554359Srobertosendetx(
507654359Sroberto	struct txbuf *buf,
507754359Sroberto	struct parseunit *parse
507854359Sroberto	)
507954359Sroberto{
508054359Sroberto	buf->txt[buf->idx++] = DLE;
508154359Sroberto	buf->txt[buf->idx++] = ETX;
508254359Sroberto
508354359Sroberto	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
508454359Sroberto	{
508554359Sroberto		ERR(ERR_BADIO)
508654359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
508754359Sroberto	}
508854359Sroberto	else
508954359Sroberto	{
509054359Sroberto#ifdef DEBUG
509154359Sroberto	  if (debug > 2)
509254359Sroberto	  {
509354359Sroberto		  char buffer[256];
5094285612Sdelphij
509554359Sroberto		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
509654359Sroberto		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
509754359Sroberto			 CLK_UNIT(parse->peer),
5098285612Sdelphij			 buf->idx, buffer);
509954359Sroberto	  }
510054359Sroberto#endif
510154359Sroberto		clear_err(parse, ERR_BADIO);
510254359Sroberto	}
510354359Sroberto}
510454359Sroberto
5105285612Sdelphijvoid
510654359Srobertosendint(
510754359Sroberto	struct txbuf *buf,
510854359Sroberto	int a
510954359Sroberto	)
511054359Sroberto{
511154359Sroberto	/* send 16bit int, msbyte first */
511254359Sroberto	sendbyte(buf, (u_char)((a>>8) & 0xff));
511354359Sroberto	sendbyte(buf, (u_char)(a & 0xff));
511454359Sroberto}
511554359Sroberto
511654359Srobertovoid
511754359Srobertosendflt(
511854359Sroberto	struct txbuf *buf,
511954359Sroberto	double a
512054359Sroberto	)
512154359Sroberto{
512254359Sroberto	int i;
512354359Sroberto	union uval uval;
512454359Sroberto
5125285612Sdelphij	uval.fv = (float) a;
512654359Sroberto#ifdef WORDS_BIGENDIAN
512754359Sroberto	for (i=0; i<=3; i++)
512854359Sroberto#else
512954359Sroberto	    for (i=3; i>=0; i--)
513054359Sroberto#endif
513154359Sroberto		sendbyte(buf, uval.bd[i]);
513254359Sroberto}
513354359Sroberto
513454359Sroberto#define TRIM_POS_OPT	0x13	/* output position with high precision */
513554359Sroberto#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
513654359Sroberto
513754359Sroberto/*--------------------------------------------------
513854359Sroberto * trimble TSIP setup routine
513954359Sroberto */
514054359Srobertostatic int
514154359Srobertotrimbletsip_setup(
514254359Sroberto		  struct parseunit *parse,
514354359Sroberto		  const char *reason
514456746Sroberto		  )
514554359Sroberto{
514654359Sroberto	u_char buffer[256];
514754359Sroberto	struct txbuf buf;
5148182007Sroberto	trimble_t *t = parse->localdata;
514954359Sroberto
5150182007Sroberto	if (t && t->last_reset &&
5151182007Sroberto	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
5152182007Sroberto		return 1;	/* not yet */
5153182007Sroberto	}
5154182007Sroberto
5155182007Sroberto	if (t)
5156182007Sroberto		t->last_reset = current_time;
5157285612Sdelphij
515854359Sroberto	buf.txt = buffer;
5159285612Sdelphij
516054359Sroberto	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
516156746Sroberto	sendetx(&buf, parse);
5162285612Sdelphij
516354359Sroberto	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
516456746Sroberto	sendbyte(&buf, 4);	/* static */
516556746Sroberto	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
516656746Sroberto	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
516756746Sroberto	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
516856746Sroberto	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
516956746Sroberto	sendetx(&buf, parse);
5170285612Sdelphij
517154359Sroberto	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
5172182007Sroberto	sendbyte(&buf, 1);	/* time transfer mode */
517356746Sroberto	sendetx(&buf, parse);
5174285612Sdelphij
517554359Sroberto	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
517656746Sroberto	sendetx(&buf, parse);
5177285612Sdelphij
517854359Sroberto	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
517956746Sroberto	sendbyte(&buf, 0x2);	/* binary mode */
518056746Sroberto	sendetx(&buf, parse);
5181285612Sdelphij
518254359Sroberto	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
518354359Sroberto	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
518454359Sroberto	sendbyte(&buf, 0x00);	/* no velocity output */
518554359Sroberto	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
518654359Sroberto	sendbyte(&buf, 0x00);	/* no raw measurements */
518756746Sroberto	sendetx(&buf, parse);
5188285612Sdelphij
518954359Sroberto	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
519054359Sroberto	sendetx(&buf, parse);
519154359Sroberto
519254359Sroberto	NLOG(NLOG_CLOCKINFO)
519354359Sroberto		ERR(ERR_BADIO)
519454359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
519554359Sroberto
519654359Sroberto	return 0;
519754359Sroberto}
519854359Sroberto
519954359Sroberto/*--------------------------------------------------
520054359Sroberto * TRIMBLE TSIP check routine
520154359Sroberto */
520254359Srobertostatic void
520354359Srobertotrimble_check(
520454359Sroberto	      struct peer *peer
520554359Sroberto	      )
520654359Sroberto{
5207285612Sdelphij	struct parseunit *parse = peer->procptr->unitptr;
520854359Sroberto	trimble_t *t = parse->localdata;
520954359Sroberto	u_char buffer[256];
521054359Sroberto	struct txbuf buf;
521154359Sroberto	buf.txt = buffer;
5212285612Sdelphij
521354359Sroberto	if (t)
521454359Sroberto	{
521554359Sroberto		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
521654359Sroberto			(void)trimbletsip_setup(parse, "message timeout");
521754359Sroberto	}
5218182007Sroberto
521954359Sroberto	poll_poll(parse->peer);	/* emit query string and re-arm timer */
5220285612Sdelphij
5221182007Sroberto	if (t && t->qtracking)
522254359Sroberto	{
522354359Sroberto		u_long oldsats = t->ltrack & ~t->ctrack;
5224285612Sdelphij
522554359Sroberto		t->qtracking = 0;
522654359Sroberto		t->ltrack = t->ctrack;
5227285612Sdelphij
522854359Sroberto		if (oldsats)
522954359Sroberto		{
523054359Sroberto			int i;
5231285612Sdelphij
5232182007Sroberto			for (i = 0; oldsats; i++) {
523354359Sroberto				if (oldsats & (1 << i))
523454359Sroberto					{
523554359Sroberto						sendcmd(&buf, CMD_CSTATTRACK);
523654359Sroberto						sendbyte(&buf, i+1);	/* old sat */
523754359Sroberto						sendetx(&buf, parse);
523854359Sroberto					}
5239182007Sroberto				oldsats &= ~(1 << i);
5240182007Sroberto			}
524154359Sroberto		}
5242285612Sdelphij
524354359Sroberto		sendcmd(&buf, CMD_CSTATTRACK);
524454359Sroberto		sendbyte(&buf, 0x00);	/* current tracking set */
524554359Sroberto		sendetx(&buf, parse);
524654359Sroberto	}
524754359Sroberto}
524854359Sroberto
524954359Sroberto/*--------------------------------------------------
525054359Sroberto * TRIMBLE TSIP end routine
525154359Sroberto */
525254359Srobertostatic void
525354359Srobertotrimbletsip_end(
525454359Sroberto	      struct parseunit *parse
525554359Sroberto	      )
525654359Sroberto{	trimble_t *t = parse->localdata;
5257285612Sdelphij
525854359Sroberto	if (t)
525954359Sroberto	{
526054359Sroberto		free(t);
5261285612Sdelphij		parse->localdata = NULL;
526254359Sroberto	}
5263285612Sdelphij	parse->peer->procptr->nextaction = 0;
5264285612Sdelphij	parse->peer->procptr->action = NULL;
526554359Sroberto}
526654359Sroberto
526754359Sroberto/*--------------------------------------------------
526854359Sroberto * TRIMBLE TSIP init routine
526954359Sroberto */
527054359Srobertostatic int
527154359Srobertotrimbletsip_init(
527254359Sroberto	struct parseunit *parse
527354359Sroberto	)
527454359Sroberto{
527554359Sroberto#if defined(VEOL) || defined(VEOL2)
527654359Sroberto#ifdef HAVE_TERMIOS
527754359Sroberto	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
527854359Sroberto#endif
527954359Sroberto#ifdef HAVE_SYSV_TTYS
528054359Sroberto	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
528154359Sroberto#endif
528254359Sroberto	/*
528354359Sroberto	 * allocate local data area
528454359Sroberto	 */
528554359Sroberto	if (!parse->localdata)
528654359Sroberto	{
528754359Sroberto		trimble_t *t;
5288285612Sdelphij
528954359Sroberto		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5290285612Sdelphij
529154359Sroberto		if (t)
529254359Sroberto		{
529354359Sroberto			memset((char *)t, 0, sizeof(trimble_t));
529454359Sroberto			t->last_msg = current_time;
529554359Sroberto		}
529654359Sroberto	}
529754359Sroberto
5298285612Sdelphij	parse->peer->procptr->action     = trimble_check;
5299285612Sdelphij	parse->peer->procptr->nextaction = current_time;
530054359Sroberto
530154359Sroberto	/*
530254359Sroberto	 * configure terminal line for ICANON mode with VEOL characters
530354359Sroberto	 */
530454359Sroberto	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
530554359Sroberto	{
530654359Sroberto		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
530754359Sroberto		return 0;
530854359Sroberto	}
530954359Sroberto	else
531054359Sroberto	{
531154359Sroberto		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
531254359Sroberto		{
531354359Sroberto#ifdef VEOL
531454359Sroberto			tio.c_cc[VEOL]  = ETX;
531554359Sroberto#endif
531654359Sroberto#ifdef VEOL2
531754359Sroberto			tio.c_cc[VEOL2]  = DLE;
531854359Sroberto#endif
531956746Sroberto		}
532054359Sroberto
532154359Sroberto		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
532254359Sroberto		{
532354359Sroberto			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
532454359Sroberto			return 0;
532554359Sroberto		}
532654359Sroberto	}
532754359Sroberto#endif
532854359Sroberto	return trimbletsip_setup(parse, "initial startup");
532954359Sroberto}
533054359Sroberto
533154359Sroberto/*------------------------------------------------------------
533254359Sroberto * trimbletsip_event - handle Trimble events
533354359Sroberto * simple evente handler - attempt to re-initialize receiver
533454359Sroberto */
533554359Srobertostatic void
533654359Srobertotrimbletsip_event(
533754359Sroberto	struct parseunit *parse,
533854359Sroberto	int event
533954359Sroberto	)
534054359Sroberto{
534154359Sroberto	switch (event)
534254359Sroberto	{
534354359Sroberto	    case CEVNT_BADREPLY:	/* reset on garbled input */
534454359Sroberto	    case CEVNT_TIMEOUT:		/* reset on no input */
534554359Sroberto		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
534654359Sroberto		    break;
534754359Sroberto
534854359Sroberto	    default:			/* ignore */
534954359Sroberto		break;
535054359Sroberto	}
535154359Sroberto}
535254359Sroberto
535354359Sroberto/*
535454359Sroberto * getflt, getint convert fields in the incoming data into the
535554359Sroberto * appropriate type of item
535654359Sroberto *
535754359Sroberto * CAVEAT: these routines are currently definitely byte order dependent
535854359Sroberto * and assume Representation(float) == IEEE754
535954359Sroberto * These functions MUST be converted to portable versions (especially
536054359Sroberto * converting the float representation into ntp_fp formats in order
536154359Sroberto * to avoid floating point operations at all!
536254359Sroberto */
536354359Sroberto
536454359Srobertostatic float
536554359Srobertogetflt(
536654359Sroberto	u_char *bp
536754359Sroberto	)
536854359Sroberto{
536954359Sroberto	union uval uval;
5370285612Sdelphij
537154359Sroberto#ifdef WORDS_BIGENDIAN
537254359Sroberto	uval.bd[0] = *bp++;
537354359Sroberto	uval.bd[1] = *bp++;
537454359Sroberto	uval.bd[2] = *bp++;
537554359Sroberto	uval.bd[3] = *bp;
537654359Sroberto#else  /* ! WORDS_BIGENDIAN */
537754359Sroberto	uval.bd[3] = *bp++;
537854359Sroberto	uval.bd[2] = *bp++;
537954359Sroberto	uval.bd[1] = *bp++;
538054359Sroberto	uval.bd[0] = *bp;
538154359Sroberto#endif /* ! WORDS_BIGENDIAN */
538254359Sroberto	return uval.fv;
538354359Sroberto}
538454359Sroberto
538554359Srobertostatic double
538654359Srobertogetdbl(
538754359Sroberto	u_char *bp
538854359Sroberto	)
538954359Sroberto{
539054359Sroberto	union uval uval;
5391285612Sdelphij
539254359Sroberto#ifdef WORDS_BIGENDIAN
539354359Sroberto	uval.bd[0] = *bp++;
539454359Sroberto	uval.bd[1] = *bp++;
539554359Sroberto	uval.bd[2] = *bp++;
539654359Sroberto	uval.bd[3] = *bp++;
539754359Sroberto	uval.bd[4] = *bp++;
539854359Sroberto	uval.bd[5] = *bp++;
539954359Sroberto	uval.bd[6] = *bp++;
540054359Sroberto	uval.bd[7] = *bp;
540154359Sroberto#else  /* ! WORDS_BIGENDIAN */
540254359Sroberto	uval.bd[7] = *bp++;
540354359Sroberto	uval.bd[6] = *bp++;
540454359Sroberto	uval.bd[5] = *bp++;
540554359Sroberto	uval.bd[4] = *bp++;
540654359Sroberto	uval.bd[3] = *bp++;
540754359Sroberto	uval.bd[2] = *bp++;
540854359Sroberto	uval.bd[1] = *bp++;
540954359Sroberto	uval.bd[0] = *bp;
541054359Sroberto#endif /* ! WORDS_BIGENDIAN */
541154359Sroberto	return uval.dv;
541254359Sroberto}
541354359Sroberto
541454359Srobertostatic int
541554359Srobertogetshort(
541654359Sroberto	 unsigned char *p
541754359Sroberto	 )
541854359Sroberto{
5419285612Sdelphij	return (int) get_msb_short(&p);
542054359Sroberto}
542154359Sroberto
542254359Sroberto/*--------------------------------------------------
542354359Sroberto * trimbletsip_message - process trimble messages
542454359Sroberto */
542554359Sroberto#define RTOD (180.0 / 3.1415926535898)
542654359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
542754359Sroberto
542854359Srobertostatic void
542954359Srobertotrimbletsip_message(
543054359Sroberto		    struct parseunit *parse,
543154359Sroberto		    parsetime_t      *parsetime
543254359Sroberto		    )
543354359Sroberto{
543454359Sroberto	unsigned char *buffer = parsetime->parse_msg;
543554359Sroberto	unsigned int   size   = parsetime->parse_msglen;
5436285612Sdelphij
543754359Sroberto	if ((size < 4) ||
543854359Sroberto	    (buffer[0]      != DLE) ||
543954359Sroberto	    (buffer[size-1] != ETX) ||
544054359Sroberto	    (buffer[size-2] != DLE))
544154359Sroberto	{
544254359Sroberto#ifdef DEBUG
544354359Sroberto		if (debug > 2) {
5444285612Sdelphij			size_t i;
544554359Sroberto
544654359Sroberto			printf("TRIMBLE BAD packet, size %d:\n	", size);
544754359Sroberto			for (i = 0; i < size; i++) {
544854359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
544954359Sroberto				if (i%16 == 15) printf("\n\t");
545054359Sroberto			}
545154359Sroberto			printf("\n");
545254359Sroberto		}
545354359Sroberto#endif
545454359Sroberto		return;
545554359Sroberto	}
545654359Sroberto	else
545754359Sroberto	{
5458285612Sdelphij		u_short var_flag;
545954359Sroberto		trimble_t *tr = parse->localdata;
546054359Sroberto		unsigned int cmd = buffer[1];
546154359Sroberto		char pbuffer[200];
546254359Sroberto		char *t = pbuffer;
546354359Sroberto		cmd_info_t *s;
5464285612Sdelphij
546554359Sroberto#ifdef DEBUG
546654359Sroberto		if (debug > 3) {
5467285612Sdelphij			size_t i;
546854359Sroberto
546954359Sroberto			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
547054359Sroberto			for (i = 0; i < size; i++) {
547154359Sroberto				printf ("%2.2x, ", buffer[i]&0xff);
547254359Sroberto				if (i%16 == 15) printf("\n\t");
547354359Sroberto			}
547454359Sroberto			printf("\n");
547554359Sroberto		}
547654359Sroberto#endif
547754359Sroberto
547854359Sroberto		if (tr)
547954359Sroberto			tr->last_msg = current_time;
5480285612Sdelphij
548154359Sroberto		s = trimble_convert(cmd, trimble_rcmds);
5482285612Sdelphij
548354359Sroberto		if (s)
548454359Sroberto		{
5485285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
548654359Sroberto		}
548754359Sroberto		else
548854359Sroberto		{
5489182007Sroberto			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
549054359Sroberto			return;
549154359Sroberto		}
549254359Sroberto
5493285612Sdelphij		var_flag = (u_short) s->varmode;
549454359Sroberto
549554359Sroberto		switch(cmd)
549654359Sroberto		{
549754359Sroberto		case CMD_RCURTIME:
5498285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
5499182007Sroberto				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5500182007Sroberto				 getflt((unsigned char *)&mb(6)));
550154359Sroberto			break;
5502285612Sdelphij
550354359Sroberto		case CMD_RBEST4:
5504285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
550554359Sroberto			switch (mb(0) & 0xF)
550654359Sroberto			{
550754359Sroberto			default:
5508285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t,
5509285612Sdelphij				    "0x%x", mb(0) & 0x7);
551054359Sroberto				break;
551154359Sroberto
551254359Sroberto			case 1:
5513285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "0D");
551454359Sroberto				break;
5515285612Sdelphij
551654359Sroberto			case 3:
5517285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
551854359Sroberto				break;
5519285612Sdelphij
552054359Sroberto			case 4:
5521285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
552254359Sroberto				break;
552354359Sroberto			}
552454359Sroberto			if (mb(0) & 0x10)
5525285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
552654359Sroberto			else
5527285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5528285612Sdelphij
5529285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
553054359Sroberto				mb(1), mb(2), mb(3), mb(4),
553154359Sroberto				getflt((unsigned char *)&mb(5)),
553254359Sroberto				getflt((unsigned char *)&mb(9)),
553354359Sroberto				getflt((unsigned char *)&mb(13)),
553454359Sroberto				getflt((unsigned char *)&mb(17)));
553554359Sroberto
553654359Sroberto			break;
5537285612Sdelphij
553854359Sroberto		case CMD_RVERSION:
5539285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
554054359Sroberto				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
554154359Sroberto			break;
5542285612Sdelphij
554354359Sroberto		case CMD_RRECVHEALTH:
554454359Sroberto		{
554554359Sroberto			static const char *msgs[] =
554654359Sroberto			{
554754359Sroberto				"Battery backup failed",
554854359Sroberto				"Signal processor error",
554954359Sroberto				"Alignment error, channel or chip 1",
555054359Sroberto				"Alignment error, channel or chip 2",
555154359Sroberto				"Antenna feed line fault",
555254359Sroberto				"Excessive ref freq. error",
555354359Sroberto				"<BIT 6>",
555454359Sroberto				"<BIT 7>"
555554359Sroberto			};
5556285612Sdelphij
555754359Sroberto			int i, bits;
5558285612Sdelphij
555954359Sroberto			switch (mb(0) & 0xFF)
556054359Sroberto			{
556154359Sroberto			default:
5562285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
556354359Sroberto				break;
556454359Sroberto			case 0x00:
5565285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes");
556654359Sroberto				break;
556754359Sroberto			case 0x01:
5568285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet");
556954359Sroberto				break;
557054359Sroberto			case 0x03:
5571285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high");
557254359Sroberto				break;
557354359Sroberto			case 0x08:
5574285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites");
557554359Sroberto				break;
557654359Sroberto			case 0x09:
5577285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite");
557854359Sroberto				break;
557954359Sroberto			case 0x0A:
5580285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites");
558154359Sroberto				break;
558254359Sroberto			case 0x0B:
5583285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites");
558454359Sroberto				break;
558554359Sroberto			case 0x0C:
5586285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable");
558754359Sroberto				break;
558854359Sroberto			}
558954359Sroberto
5590285612Sdelphij			bits = mb(1) & 0xFF;
559154359Sroberto
559254359Sroberto			for (i = 0; i < 8; i++)
559354359Sroberto				if (bits & (0x1<<i))
559454359Sroberto				{
5595285612Sdelphij					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
559654359Sroberto				}
559754359Sroberto		}
559854359Sroberto		break;
5599285612Sdelphij
560054359Sroberto		case CMD_RMESSAGE:
5601182007Sroberto			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
560254359Sroberto			break;
5603285612Sdelphij
560454359Sroberto		case CMD_RMACHSTAT:
560554359Sroberto		{
560654359Sroberto			static const char *msgs[] =
560754359Sroberto			{
560854359Sroberto				"Synthesizer Fault",
560954359Sroberto				"Battery Powered Time Clock Fault",
561054359Sroberto				"A-to-D Converter Fault",
561154359Sroberto				"The almanac stored in the receiver is not complete and current",
561254359Sroberto				"<BIT 4>",
561354359Sroberto				"<BIT 5",
561454359Sroberto				"<BIT 6>",
561554359Sroberto				"<BIT 7>"
561654359Sroberto			};
5617285612Sdelphij
561854359Sroberto			int i, bits;
561954359Sroberto
5620285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
562154359Sroberto			bits = mb(1) & 0xFF;
5622285612Sdelphij
562354359Sroberto			for (i = 0; i < 8; i++)
562454359Sroberto				if (bits & (0x1<<i))
562554359Sroberto				{
5626285612Sdelphij					t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
562754359Sroberto				}
562854359Sroberto
5629285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
563054359Sroberto		}
563154359Sroberto		break;
5632285612Sdelphij
563354359Sroberto		case CMD_ROPERPARAM:
5634285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
563554359Sroberto				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
563654359Sroberto				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
563754359Sroberto			break;
5638285612Sdelphij
563954359Sroberto		case CMD_RUTCPARAM:
564054359Sroberto		{
564154359Sroberto			float t0t = getflt((unsigned char *)&mb(14));
5642285612Sdelphij			short wnt = (short) getshort((unsigned char *)&mb(18));
5643285612Sdelphij			short dtls = (short) getshort((unsigned char *)&mb(12));
5644285612Sdelphij			short wnlsf = (short) getshort((unsigned char *)&mb(20));
5645285612Sdelphij			short dn = (short) getshort((unsigned char *)&mb(22));
5646285612Sdelphij			short dtlsf = (short) getshort((unsigned char *)&mb(24));
564754359Sroberto
564854359Sroberto			if ((int)t0t != 0)
5649285612Sdelphij			{
5650285612Sdelphij				mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5651285612Sdelphij			}
565254359Sroberto			else
5653285612Sdelphij			{
5654285612Sdelphij			        t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
5655285612Sdelphij			}
565654359Sroberto		}
565754359Sroberto		break;
565854359Sroberto
565954359Sroberto		case CMD_RSAT1BIAS:
5660285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
566154359Sroberto				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
566254359Sroberto			break;
566354359Sroberto
566454359Sroberto		case CMD_RIOOPTIONS:
566554359Sroberto		{
5666285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
566754359Sroberto				mb(0), mb(1), mb(2), mb(3));
566854359Sroberto			if (mb(0) != TRIM_POS_OPT ||
566954359Sroberto			    mb(2) != TRIM_TIME_OPT)
567054359Sroberto			{
567154359Sroberto				(void)trimbletsip_setup(parse, "bad io options");
567254359Sroberto			}
567354359Sroberto		}
567454359Sroberto		break;
5675285612Sdelphij
567654359Sroberto		case CMD_RSPOSXYZ:
567754359Sroberto		{
567854359Sroberto			double x = getflt((unsigned char *)&mb(0));
567954359Sroberto			double y = getflt((unsigned char *)&mb(4));
568054359Sroberto			double z = getflt((unsigned char *)&mb(8));
568154359Sroberto			double f = getflt((unsigned char *)&mb(12));
5682285612Sdelphij
568354359Sroberto			if (f > 0.0)
5684285612Sdelphij			  t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
568554359Sroberto				  x, y, z,
568654359Sroberto				  f);
568754359Sroberto			else
5688285612Sdelphij				return;
568954359Sroberto		}
569054359Sroberto		break;
569154359Sroberto
569254359Sroberto		case CMD_RSLLAPOS:
569354359Sroberto		{
569454359Sroberto			double lat = getflt((unsigned char *)&mb(0));
569554359Sroberto			double lng = getflt((unsigned char *)&mb(4));
569654359Sroberto			double f   = getflt((unsigned char *)&mb(12));
5697285612Sdelphij
569854359Sroberto			if (f > 0.0)
5699285612Sdelphij			  t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
570054359Sroberto				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
570154359Sroberto				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
570254359Sroberto				  getflt((unsigned char *)&mb(8)));
570354359Sroberto			else
5704285612Sdelphij				return;
570554359Sroberto		}
570654359Sroberto		break;
570754359Sroberto
570854359Sroberto		case CMD_RDOUBLEXYZ:
570954359Sroberto		{
571054359Sroberto			double x = getdbl((unsigned char *)&mb(0));
571154359Sroberto			double y = getdbl((unsigned char *)&mb(8));
571254359Sroberto			double z = getdbl((unsigned char *)&mb(16));
5713285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
571454359Sroberto				x, y, z);
571554359Sroberto		}
571654359Sroberto		break;
5717285612Sdelphij
571854359Sroberto		case CMD_RDOUBLELLA:
571954359Sroberto		{
572054359Sroberto			double lat = getdbl((unsigned char *)&mb(0));
572154359Sroberto			double lng = getdbl((unsigned char *)&mb(8));
5722285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
572354359Sroberto				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
572454359Sroberto				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
572554359Sroberto				getdbl((unsigned char *)&mb(16)));
572654359Sroberto		}
572754359Sroberto		break;
572854359Sroberto
572954359Sroberto		case CMD_RALLINVIEW:
573054359Sroberto		{
573154359Sroberto			int i, sats;
5732285612Sdelphij
5733285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
573454359Sroberto			switch (mb(0) & 0x7)
573554359Sroberto			{
573654359Sroberto			default:
5737285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
573854359Sroberto				break;
573954359Sroberto
574054359Sroberto			case 3:
5741285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "2D");
574254359Sroberto				break;
5743285612Sdelphij
574454359Sroberto			case 4:
5745285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "3D");
574654359Sroberto				break;
574754359Sroberto			}
574854359Sroberto			if (mb(0) & 0x8)
5749285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
575054359Sroberto			else
5751285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5752285612Sdelphij
575354359Sroberto			sats = (mb(0)>>4) & 0xF;
5754285612Sdelphij
5755285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
575654359Sroberto				getflt((unsigned char *)&mb(1)),
575754359Sroberto				getflt((unsigned char *)&mb(5)),
575854359Sroberto				getflt((unsigned char *)&mb(9)),
575954359Sroberto				getflt((unsigned char *)&mb(13)),
576054359Sroberto				sats, (sats == 1) ? "" : "s");
576154359Sroberto
576254359Sroberto			for (i=0; i < sats; i++)
576354359Sroberto			{
5764285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
576554359Sroberto				if (tr)
576654359Sroberto					tr->ctrack |= (1 << (mb(17+i)-1));
576754359Sroberto			}
576854359Sroberto
576954359Sroberto			if (tr)
5770285612Sdelphij			{	/* mark for tracking status query */
577154359Sroberto				tr->qtracking = 1;
577254359Sroberto			}
577354359Sroberto		}
577454359Sroberto		break;
5775285612Sdelphij
577654359Sroberto		case CMD_RSTATTRACK:
577754359Sroberto		{
5778285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
577954359Sroberto			if (getflt((unsigned char *)&mb(4)) < 0.0)
578054359Sroberto			{
5781285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
5782285612Sdelphij				var_flag &= (u_short)(~DEF);
578354359Sroberto			}
578454359Sroberto			else
5785285612Sdelphij			{
5786285612Sdelphij				t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
578754359Sroberto					(mb(1) & 0xFF)>>3,
578854359Sroberto					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
578954359Sroberto					mb(3),
579054359Sroberto					getflt((unsigned char *)&mb(4)),
579154359Sroberto					getflt((unsigned char *)&mb(12)) * RTOD,
579254359Sroberto					getflt((unsigned char *)&mb(16)) * RTOD);
579354359Sroberto				if (mb(20))
579454359Sroberto				{
5795285612Sdelphij					var_flag &= (u_short)(~DEF);
5796285612Sdelphij					t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
579754359Sroberto				}
579854359Sroberto				if (mb(22))
579954359Sroberto				{
580054359Sroberto					if (mb(22) == 1)
5801285612Sdelphij						t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
580254359Sroberto					else
580354359Sroberto						if (mb(22) == 2)
5804285612Sdelphij							t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
580554359Sroberto				}
580654359Sroberto				if (mb(23))
5807285612Sdelphij					t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
580854359Sroberto			}
580954359Sroberto		}
581054359Sroberto		break;
5811285612Sdelphij
581254359Sroberto		default:
5813285612Sdelphij			t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
581454359Sroberto			break;
581554359Sroberto		}
5816182007Sroberto
5817285612Sdelphij		t = ap(pbuffer, sizeof(pbuffer), t, "\"");
581854359Sroberto		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
581954359Sroberto	}
582054359Sroberto}
582154359Sroberto
5822285612Sdelphij
582354359Sroberto/**============================================================
582454359Sroberto ** RAWDCF support
582554359Sroberto **/
582654359Sroberto
582754359Sroberto/*--------------------------------------------------
582856746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers
582956746Sroberto * SET DTR line
583054359Sroberto */
583154359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
583254359Srobertostatic int
583356746Srobertorawdcf_init_1(
583454359Sroberto	struct parseunit *parse
583554359Sroberto	)
583654359Sroberto{
583782498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
583854359Sroberto	/*
583954359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
584054359Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
584154359Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
584254359Sroberto	 */
584382498Sroberto	int sl232;
584482498Sroberto
584582498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
584682498Sroberto	{
584782498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
584882498Sroberto		return 0;
584982498Sroberto	}
585082498Sroberto
585154359Sroberto#ifdef TIOCM_DTR
585282498Sroberto	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
585354359Sroberto#else
585482498Sroberto	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
585554359Sroberto#endif
585654359Sroberto
585754359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
585854359Sroberto	{
585956746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
586054359Sroberto	}
586154359Sroberto	return 0;
586254359Sroberto}
586354359Sroberto#else
586454359Srobertostatic int
5865132451Srobertorawdcfdtr_init_1(
586654359Sroberto	struct parseunit *parse
586754359Sroberto	)
586854359Sroberto{
586956746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
587054359Sroberto	return 0;
587154359Sroberto}
587254359Sroberto#endif  /* DTR initialisation type */
587354359Sroberto
587454359Sroberto/*--------------------------------------------------
587556746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers
587656746Sroberto * CLR DTR line, SET RTS line
587754359Sroberto */
587856746Sroberto#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
587954359Srobertostatic int
588056746Srobertorawdcf_init_2(
588154359Sroberto	struct parseunit *parse
588254359Sroberto	)
588354359Sroberto{
588482498Sroberto	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
588554359Sroberto	/*
588654359Sroberto	 * You can use the RS232 to supply the power for a DCF77 receiver.
588756746Sroberto	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
588856746Sroberto	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
588954359Sroberto	 */
589082498Sroberto	int sl232;
589182498Sroberto
589282498Sroberto	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
589382498Sroberto	{
589482498Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
589582498Sroberto		return 0;
589682498Sroberto	}
589782498Sroberto
589854359Sroberto#ifdef TIOCM_RTS
589982498Sroberto	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
590054359Sroberto#else
590182498Sroberto	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
590254359Sroberto#endif
590354359Sroberto
590454359Sroberto	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
590554359Sroberto	{
590656746Sroberto		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
590754359Sroberto	}
590854359Sroberto	return 0;
590954359Sroberto}
591054359Sroberto#else
591154359Srobertostatic int
591256746Srobertorawdcf_init_2(
591354359Sroberto	struct parseunit *parse
591454359Sroberto	)
591554359Sroberto{
591656746Sroberto	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
591754359Sroberto	return 0;
591854359Sroberto}
591956746Sroberto#endif  /* DTR initialisation type */
592054359Sroberto
592154359Sroberto#else	/* defined(REFCLOCK) && defined(PARSE) */
5922285612SdelphijNONEMPTY_TRANSLATION_UNIT
592354359Sroberto#endif	/* defined(REFCLOCK) && defined(PARSE) */
592454359Sroberto
592554359Sroberto/*
592654359Sroberto * History:
592754359Sroberto *
592854359Sroberto * refclock_parse.c,v
5929285612Sdelphij * Revision 4.81  2009/05/01 10:15:29  kardel
5930285612Sdelphij * use new refclock_ppsapi interface
5931285612Sdelphij *
5932182007Sroberto * Revision 4.80  2007/08/11 12:06:29  kardel
5933182007Sroberto * update comments wrt/ to PPS
5934182007Sroberto *
5935182007Sroberto * Revision 4.79  2007/08/11 11:52:23  kardel
5936182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor
5937182007Sroberto *
5938182007Sroberto * Revision 4.78  2006/12/22 20:08:27  kardel
5939182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5940182007Sroberto *
5941182007Sroberto * Revision 4.77  2006/08/05 07:44:49  kardel
5942182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5943182007Sroberto *
5944182007Sroberto * Revision 4.76  2006/06/22 18:40:47  kardel
5945182007Sroberto * clean up signedness (gcc 4)
5946182007Sroberto *
5947182007Sroberto * Revision 4.75  2006/06/22 16:58:10  kardel
5948182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5949182007Sroberto * the PPS offset. Fix sign of offset passed to kernel.
5950182007Sroberto *
5951182007Sroberto * Revision 4.74  2006/06/18 21:18:37  kardel
5952182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref
5953182007Sroberto *
5954182007Sroberto * Revision 4.73  2006/05/26 14:23:46  kardel
5955182007Sroberto * cleanup of copyright info
5956182007Sroberto *
5957182007Sroberto * Revision 4.72  2006/05/26 14:19:43  kardel
5958182007Sroberto * cleanup of ioctl cruft
5959182007Sroberto *
5960182007Sroberto * Revision 4.71  2006/05/26 14:15:57  kardel
5961182007Sroberto * delay adding refclock to async refclock io after all initializations
5962182007Sroberto *
5963182007Sroberto * Revision 4.70  2006/05/25 18:20:50  kardel
5964182007Sroberto * bug #619
5965182007Sroberto * terminate parse io engine after de-registering
5966182007Sroberto * from refclock io engine
5967182007Sroberto *
5968182007Sroberto * Revision 4.69  2006/05/25 17:28:02  kardel
5969182007Sroberto * complete refclock io structure initialization *before* inserting it into the
5970182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619)
5971182007Sroberto *
5972182007Sroberto * Revision 4.68  2006/05/01 17:02:51  kardel
5973182007Sroberto * copy receiver method also for newlwy created receive buffers
5974182007Sroberto *
5975182007Sroberto * Revision 4.67  2006/05/01 14:37:29  kardel
5976182007Sroberto * If an input buffer parses into more than one message do insert the
5977182007Sroberto * parsed message in a new input buffer instead of processing it
5978182007Sroberto * directly. This avoids deed complicated processing in signal
5979182007Sroberto * handling.
5980182007Sroberto *
5981182007Sroberto * Revision 4.66  2006/03/18 00:45:30  kardel
5982182007Sroberto * coverity fixes found in NetBSD coverity scan
5983182007Sroberto *
5984182007Sroberto * Revision 4.65  2006/01/26 06:08:33  kardel
5985182007Sroberto * output errno on PPS setup failure
5986182007Sroberto *
5987182007Sroberto * Revision 4.64  2005/11/09 20:44:47  kardel
5988182007Sroberto * utilize full PPS timestamp resolution from PPS API
5989182007Sroberto *
5990182007Sroberto * Revision 4.63  2005/10/07 22:10:25  kardel
5991182007Sroberto * bounded buffer implementation
5992182007Sroberto *
5993182007Sroberto * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5994182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5995182007Sroberto * replace almost all str* and *printf functions be their buffer bounded
5996182007Sroberto * counterparts
5997182007Sroberto *
5998182007Sroberto * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
5999182007Sroberto * limit re-set rate of trimble clocks
6000182007Sroberto *
6001182007Sroberto * Revision 4.62  2005/08/06 17:40:00  kardel
6002182007Sroberto * cleanup size handling wrt/ to buffer boundaries
6003182007Sroberto *
6004182007Sroberto * Revision 4.61  2005/07/27 21:16:19  kardel
6005182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
6006182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of
6007182007Sroberto * the DCF77 clocks.
6008182007Sroberto *
6009182007Sroberto * Revision 4.60  2005/07/17 21:14:44  kardel
6010182007Sroberto * change contents of version string to include the RCS/CVS Id
6011182007Sroberto *
6012182007Sroberto * Revision 4.59  2005/07/06 06:56:38  kardel
6013182007Sroberto * syntax error
6014182007Sroberto *
6015182007Sroberto * Revision 4.58  2005/07/04 13:10:40  kardel
6016182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup
6017182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
6018182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and
6019182007Sroberto *     varying structure element sizes
6020182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers
6021182007Sroberto *
6022182007Sroberto * Revision 4.57  2005/06/25 09:25:19  kardel
6023182007Sroberto * sort out log output sequence
6024182007Sroberto *
6025182007Sroberto * Revision 4.56  2005/06/14 21:47:27  kardel
6026182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel)
6027182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
6028182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state
6029182007Sroberto *
6030182007Sroberto * Revision 4.55  2005/06/02 21:28:31  kardel
6031182007Sroberto * clarify trust logic
6032182007Sroberto *
6033182007Sroberto * Revision 4.54  2005/06/02 17:06:49  kardel
6034182007Sroberto * change status reporting to use fixed refclock_report()
6035182007Sroberto *
6036182007Sroberto * Revision 4.53  2005/06/02 16:33:31  kardel
6037182007Sroberto * fix acceptance of clocks unsync clocks right at start
6038182007Sroberto *
6039182007Sroberto * Revision 4.52  2005/05/26 21:55:06  kardel
6040182007Sroberto * cleanup status reporting
6041182007Sroberto *
6042182007Sroberto * Revision 4.51  2005/05/26 19:19:14  kardel
6043182007Sroberto * implement fast refclock startup
6044182007Sroberto *
6045182007Sroberto * Revision 4.50  2005/04/16 20:51:35  kardel
6046285612Sdelphij * set hardpps_enable = 1 when binding a kernel PPS source
6047182007Sroberto *
6048182007Sroberto * Revision 4.49  2005/04/16 17:29:26  kardel
6049182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks
6050182007Sroberto *
6051182007Sroberto * Revision 4.48  2005/04/16 16:22:27  kardel
6052182007Sroberto * bk sync 20050415 ntp-dev
6053182007Sroberto *
6054182007Sroberto * Revision 4.47  2004/11/29 10:42:48  kardel
6055182007Sroberto * bk sync ntp-dev 20041129
6056182007Sroberto *
6057182007Sroberto * Revision 4.46  2004/11/29 10:26:29  kardel
6058182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
6059182007Sroberto *
6060182007Sroberto * Revision 4.45  2004/11/14 20:53:20  kardel
6061182007Sroberto * clear PPS flags after using them
6062182007Sroberto *
6063182007Sroberto * Revision 4.44  2004/11/14 15:29:41  kardel
6064182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style
6065182007Sroberto *
6066182007Sroberto * Revision 4.43  2001/05/26 22:53:16  kardel
6067182007Sroberto * 20010526 reconcilation
6068182007Sroberto *
6069182007Sroberto * Revision 4.42  2000/05/14 15:31:51  kardel
6070182007Sroberto * PPSAPI && RAWDCF modemline support
6071182007Sroberto *
6072182007Sroberto * Revision 4.41  2000/04/09 19:50:45  kardel
6073182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1
6074182007Sroberto *
6075182007Sroberto * Revision 4.40  2000/04/09 15:27:55  kardel
6076182007Sroberto * modem line fiddle in rawdcf_init_2
6077182007Sroberto *
6078182007Sroberto * Revision 4.39  2000/03/18 09:16:55  kardel
6079182007Sroberto * PPSAPI integration
6080182007Sroberto *
6081182007Sroberto * Revision 4.38  2000/03/05 20:25:06  kardel
6082182007Sroberto * support PPSAPI
6083182007Sroberto *
6084182007Sroberto * Revision 4.37  2000/03/05 20:11:14  kardel
6085182007Sroberto * 4.0.99g reconcilation
6086182007Sroberto *
608756746Sroberto * Revision 4.36  1999/11/28 17:18:20  kardel
608856746Sroberto * disabled burst mode
608956746Sroberto *
609056746Sroberto * Revision 4.35  1999/11/28 09:14:14  kardel
609156746Sroberto * RECON_4_0_98F
609256746Sroberto *
609356746Sroberto * Revision 4.34  1999/05/14 06:08:05  kardel
609456746Sroberto * store current_time in a suitable container (u_long)
609556746Sroberto *
609656746Sroberto * Revision 4.33  1999/05/13 21:48:38  kardel
609756746Sroberto * double the no response timeout interval
609856746Sroberto *
609956746Sroberto * Revision 4.32  1999/05/13 20:09:13  kardel
610056746Sroberto * complain only about missing polls after a full poll interval
610156746Sroberto *
610256746Sroberto * Revision 4.31  1999/05/13 19:59:32  kardel
610356746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF
610456746Sroberto *
610556746Sroberto * Revision 4.30  1999/02/28 20:36:43  kardel
610656746Sroberto * fixed printf fmt
610756746Sroberto *
610854359Sroberto * Revision 4.29  1999/02/28 19:58:23  kardel
610954359Sroberto * updated copyright information
611054359Sroberto *
611154359Sroberto * Revision 4.28  1999/02/28 19:01:50  kardel
611254359Sroberto * improved debug out on sent Meinberg messages
611354359Sroberto *
611454359Sroberto * Revision 4.27  1999/02/28 18:05:55  kardel
611554359Sroberto * no linux/ppsclock.h stuff
611654359Sroberto *
611754359Sroberto * Revision 4.26  1999/02/28 15:27:27  kardel
611854359Sroberto * wharton clock integration
611954359Sroberto *
612054359Sroberto * Revision 4.25  1999/02/28 14:04:46  kardel
612154359Sroberto * added missing double quotes to UTC information string
612254359Sroberto *
612354359Sroberto * Revision 4.24  1999/02/28 12:06:50  kardel
612454359Sroberto * (parse_control): using gmprettydate instead of prettydate()
612554359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information
612654359Sroberto * (gps16x_message): changed to use mk_utcinfo()
612754359Sroberto * (trimbletsip_message): changed to use mk_utcinfo()
612854359Sroberto * ignoring position information in unsynchronized mode
612954359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
613054359Sroberto *
613154359Sroberto * Revision 4.23  1999/02/23 19:47:53  kardel
613254359Sroberto * fixed #endifs
613354359Sroberto * (stream_receive): fixed formats
613454359Sroberto *
613554359Sroberto * Revision 4.22  1999/02/22 06:21:02  kardel
613654359Sroberto * use new autoconfig symbols
613754359Sroberto *
613854359Sroberto * Revision 4.21  1999/02/21 12:18:13  kardel
613954359Sroberto * 4.91f reconcilation
614054359Sroberto *
614154359Sroberto * Revision 4.20  1999/02/21 10:53:36  kardel
614254359Sroberto * initial Linux PPSkit version
614354359Sroberto *
614454359Sroberto * Revision 4.19  1999/02/07 09:10:45  kardel
614554359Sroberto * clarify STREAMS mitigation rules in comment
614654359Sroberto *
614754359Sroberto * Revision 4.18  1998/12/20 23:45:34  kardel
614854359Sroberto * fix types and warnings
614954359Sroberto *
615054359Sroberto * Revision 4.17  1998/11/15 21:24:51  kardel
615154359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG
615254359Sroberto * is not defined
615354359Sroberto *
615454359Sroberto * Revision 4.16  1998/11/15 20:28:17  kardel
615554359Sroberto * Release 4.0.73e13 reconcilation
615654359Sroberto *
615754359Sroberto * Revision 4.15  1998/08/22 21:56:08  kardel
615854359Sroberto * fixed IO handling for non-STREAM IO
615954359Sroberto *
616054359Sroberto * Revision 4.14  1998/08/16 19:00:48  kardel
616154359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
616254359Sroberto * made uval a local variable (killed one of the last globals)
616354359Sroberto * (sendetx): added logging of messages when in debug mode
616454359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization
616554359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation
616654359Sroberto * (trimbletsip_message): extended message interpretation
616754359Sroberto * (getdbl): fixed data conversion
616854359Sroberto *
616954359Sroberto * Revision 4.13  1998/08/09 22:29:13  kardel
617054359Sroberto * Trimble TSIP support
617154359Sroberto *
617254359Sroberto * Revision 4.12  1998/07/11 10:05:34  kardel
617354359Sroberto * Release 4.0.73d reconcilation
617454359Sroberto *
617554359Sroberto * Revision 4.11  1998/06/14 21:09:42  kardel
617654359Sroberto * Sun acc cleanup
617754359Sroberto *
617854359Sroberto * Revision 4.10  1998/06/13 12:36:45  kardel
617954359Sroberto * signed/unsigned, name clashes
618054359Sroberto *
618154359Sroberto * Revision 4.9  1998/06/12 15:30:00  kardel
618254359Sroberto * prototype fixes
618354359Sroberto *
618454359Sroberto * Revision 4.8  1998/06/12 11:19:42  kardel
618554359Sroberto * added direct input processing routine for refclocks in
618654359Sroberto * order to avaiod that single character io gobbles up all
618754359Sroberto * receive buffers and drops input data. (Problem started
618854359Sroberto * with fast machines so a character a buffer was possible
618954359Sroberto * one of the few cases where faster machines break existing
619054359Sroberto * allocation algorithms)
619154359Sroberto *
619254359Sroberto * Revision 4.7  1998/06/06 18:35:20  kardel
619354359Sroberto * (parse_start): added BURST mode initialisation
619454359Sroberto *
619554359Sroberto * Revision 4.6  1998/05/27 06:12:46  kardel
619654359Sroberto * RAWDCF_BASEDELAY default added
619754359Sroberto * old comment removed
619854359Sroberto * casts for ioctl()
619954359Sroberto *
620054359Sroberto * Revision 4.5  1998/05/25 22:05:09  kardel
620154359Sroberto * RAWDCF_SETDTR option removed
620254359Sroberto * clock type 14 attempts to set DTR for
620354359Sroberto * power supply of RAWDCF receivers
620454359Sroberto *
620554359Sroberto * Revision 4.4  1998/05/24 16:20:47  kardel
620654359Sroberto * updated comments referencing Meinberg clocks
620754359Sroberto * added RAWDCF clock with DTR set option as type 14
620854359Sroberto *
620954359Sroberto * Revision 4.3  1998/05/24 10:48:33  kardel
621054359Sroberto * calibrated CONRAD RAWDCF default fudge factor
621154359Sroberto *
621254359Sroberto * Revision 4.2  1998/05/24 09:59:35  kardel
621354359Sroberto * corrected version information (ntpq support)
621454359Sroberto *
621554359Sroberto * Revision 4.1  1998/05/24 09:52:31  kardel
621654359Sroberto * use fixed format only (new IO model)
621754359Sroberto * output debug to stdout instead of msyslog()
621854359Sroberto * don't include >"< in ASCII output in order not to confuse
621954359Sroberto * ntpq parsing
622054359Sroberto *
622154359Sroberto * Revision 4.0  1998/04/10 19:52:11  kardel
622254359Sroberto * Start 4.0 release version numbering
622354359Sroberto *
622454359Sroberto * Revision 1.2  1998/04/10 19:28:04  kardel
622554359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
622654359Sroberto * derived from 3.105.1.2 from V3 tree
622754359Sroberto *
622854359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
622954359Sroberto *
623054359Sroberto */
6231