1/*
2 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
3 *
4 * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
5 *
6 * generic reference clock driver for several DCF/GPS/MSF/... receivers
7 *
8 * PPS notes:
9 *   On systems that support PPSAPI (RFC2783) PPSAPI is the
10 *   preferred interface.
11 *
12 *   Optionally make use of a STREAMS module for input processing where
13 *   available and configured. This STREAMS module reduces the time
14 *   stamp latency for serial and PPS events.
15 *   Currently the STREAMS module is only available for Suns running
16 *   SunOS 4.x and SunOS5.x.
17 *
18 * Copyright (c) 1995-2007 by Frank Kardel <kardel <AT> ntp.org>
19 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, Germany
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 *    notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 *    notice, this list of conditions and the following disclaimer in the
28 *    documentation and/or other materials provided with the distribution.
29 * 3. Neither the name of the author nor the names of its contributors
30 *    may be used to endorse or promote products derived from this software
31 *    without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 *
45 */
46
47#ifdef HAVE_CONFIG_H
48# include "config.h"
49#endif
50
51#if defined(REFCLOCK) && defined(CLOCK_PARSE)
52
53/*
54 * This driver currently provides the support for
55 *   - Meinberg receiver DCF77 PZF 535 (TCXO version)       (DCF)
56 *   - Meinberg receiver DCF77 PZF 535 (OCXO version)       (DCF)
57 *   - Meinberg receiver DCF77 PZF 509                      (DCF)
58 *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
59 *   - IGEL CLOCK                                           (DCF)
60 *   - ELV DCF7000                                          (DCF)
61 *   - Schmid clock                                         (DCF)
62 *   - Conrad DCF77 receiver module                         (DCF)
63 *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
64 *   - WHARTON 400A Series clock			    (DCF)
65 *
66 *   - Meinberg GPS166/GPS167                               (GPS)
67 *   - Trimble (TSIP and TAIP protocol)                     (GPS)
68 *
69 *   - RCC8000 MSF Receiver                                 (MSF)
70 *   - VARITEXT clock					    (MSF)
71 */
72
73/*
74 * Meinberg receivers are usually connected via a
75 * 9600 baud serial line
76 *
77 * The Meinberg GPS receivers also have a special NTP time stamp
78 * format. The firmware release is Uni-Erlangen.
79 *
80 * Meinberg generic receiver setup:
81 *	output time code every second
82 *	Baud rate 9600 7E2S
83 *
84 * Meinberg GPS16x setup:
85 *      output time code every second
86 *      Baudrate 19200 8N1
87 *
88 * This software supports the standard data formats used
89 * in Meinberg receivers.
90 *
91 * Special software versions are only sensible for the
92 * GPS 16x family of receivers.
93 *
94 * Meinberg can be reached via: http://www.meinberg.de/
95 */
96
97#include "ntpd.h"
98#include "ntp_refclock.h"
99#include "ntp_unixtime.h"	/* includes <sys/time.h> */
100#include "ntp_control.h"
101#include "ntp_string.h"
102
103#include <stdio.h>
104#include <ctype.h>
105#ifndef TM_IN_SYS_TIME
106# include <time.h>
107#endif
108
109#ifdef HAVE_UNISTD_H
110# include <unistd.h>
111#endif
112
113#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
114# include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
115#endif
116
117#ifdef STREAM
118# include <sys/stream.h>
119# include <sys/stropts.h>
120#endif
121
122#ifdef HAVE_TERMIOS
123# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
124# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
125# undef HAVE_SYSV_TTYS
126#endif
127
128#ifdef HAVE_SYSV_TTYS
129# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
130# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
131#endif
132
133#ifdef HAVE_BSD_TTYS
134/* #error CURRENTLY NO BSD TTY SUPPORT */
135# include "Bletch: BSD TTY not currently supported"
136#endif
137
138#ifdef HAVE_SYS_IOCTL_H
139# include <sys/ioctl.h>
140#endif
141
142#ifdef HAVE_PPSAPI
143# include "ppsapi_timepps.h"
144#endif
145
146#ifdef PPS
147# ifdef HAVE_SYS_PPSCLOCK_H
148#  include <sys/ppsclock.h>
149# endif
150# ifdef HAVE_TIO_SERIAL_STUFF
151#  include <linux/serial.h>
152# endif
153#endif
154
155#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
156#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
157
158/*
159 * document type of PPS interfacing - copy of ifdef mechanism in local_input()
160 */
161#undef PPS_METHOD
162
163#ifdef HAVE_PPSAPI
164#define PPS_METHOD "PPS API"
165#else
166#ifdef TIOCDCDTIMESTAMP
167#define PPS_METHOD "TIOCDCDTIMESTAMP"
168#else /* TIOCDCDTIMESTAMP */
169#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
170#ifdef HAVE_CIOGETEV
171#define PPS_METHOD "CIOGETEV"
172#endif
173#ifdef HAVE_TIOCGPPSEV
174#define PPS_METHOD "TIOCGPPSEV"
175#endif
176#endif
177#endif /* TIOCDCDTIMESTAMP */
178#endif /* HAVE_PPSAPI */
179
180#include "ntp_io.h"
181#include "ntp_stdlib.h"
182
183#include "parse.h"
184#include "mbg_gps166.h"
185#include "trimble.h"
186#include "binio.h"
187#include "ascii.h"
188#include "ieee754io.h"
189#include "recvbuff.h"
190
191static char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp";
192
193/**===========================================================================
194 ** external interface to ntp mechanism
195 **/
196
197static	int	parse_start	P((int, struct peer *));
198static	void	parse_shutdown	P((int, struct peer *));
199static	void	parse_poll	P((int, struct peer *));
200static	void	parse_control	P((int, struct refclockstat *, struct refclockstat *, struct peer *));
201
202struct	refclock refclock_parse = {
203	parse_start,
204	parse_shutdown,
205	parse_poll,
206	parse_control,
207	noentry,
208	noentry,
209	NOFLAGS
210};
211
212/*
213 * Definitions
214 */
215#define	MAXUNITS	4	/* maximum number of "PARSE" units permitted */
216#define PARSEDEVICE	"/dev/refclock-%d" /* device to open %d is unit number */
217#define PARSEPPSDEVICE	"/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
218
219#undef ABS
220#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
221
222#define PARSE_HARDPPS_DISABLE 0
223#define PARSE_HARDPPS_ENABLE  1
224
225/**===========================================================================
226 ** function vector for dynamically binding io handling mechanism
227 **/
228
229struct parseunit;		/* to keep inquiring minds happy */
230
231typedef struct bind
232{
233  const char *bd_description;	                                /* name of type of binding */
234  int	(*bd_init)     P((struct parseunit *));			/* initialize */
235  void	(*bd_end)      P((struct parseunit *));			/* end */
236  int   (*bd_setcs)    P((struct parseunit *, parsectl_t *));	/* set character size */
237  int	(*bd_disable)  P((struct parseunit *));			/* disable */
238  int	(*bd_enable)   P((struct parseunit *));			/* enable */
239  int	(*bd_getfmt)   P((struct parseunit *, parsectl_t *));	/* get format */
240  int	(*bd_setfmt)   P((struct parseunit *, parsectl_t *));	/* setfmt */
241  int	(*bd_timecode) P((struct parseunit *, parsectl_t *));	/* get time code */
242  void	(*bd_receive)  P((struct recvbuf *));			/* receive operation */
243  int	(*bd_io_input) P((struct recvbuf *));			/* input operation */
244} bind_t;
245
246#define PARSE_END(_X_)			(*(_X_)->binding->bd_end)(_X_)
247#define PARSE_SETCS(_X_, _CS_)		(*(_X_)->binding->bd_setcs)(_X_, _CS_)
248#define PARSE_ENABLE(_X_)		(*(_X_)->binding->bd_enable)(_X_)
249#define PARSE_DISABLE(_X_)		(*(_X_)->binding->bd_disable)(_X_)
250#define PARSE_GETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
251#define PARSE_SETFMT(_X_, _DCT_)	(*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
252#define PARSE_GETTIMECODE(_X_, _DCT_)	(*(_X_)->binding->bd_timecode)(_X_, _DCT_)
253
254/*
255 * io modes
256 */
257#define PARSE_F_PPSPPS		0x0001 /* use loopfilter PPS code (CIOGETEV) */
258#define PARSE_F_PPSONSECOND	0x0002 /* PPS pulses are on second */
259
260
261/**===========================================================================
262 ** error message regression handling
263 **
264 ** there are quite a few errors that can occur in rapid succession such as
265 ** noisy input data or no data at all. in order to reduce the amount of
266 ** syslog messages in such case, we are using a backoff algorithm. We limit
267 ** the number of error messages of a certain class to 1 per time unit. if a
268 ** configurable number of messages is displayed that way, we move on to the
269 ** next time unit / count for that class. a count of messages that have been
270 ** suppressed is held and displayed whenever a corresponding message is
271 ** displayed. the time units for a message class will also be displayed.
272 ** whenever an error condition clears we reset the error message state,
273 ** thus we would still generate much output on pathological conditions
274 ** where the system oscillates between OK and NOT OK states. coping
275 ** with that condition is currently considered too complicated.
276 **/
277
278#define ERR_ALL	        (unsigned)~0	/* "all" errors */
279#define ERR_BADDATA	(unsigned)0	/* unusable input data/conversion errors */
280#define ERR_NODATA	(unsigned)1	/* no input data */
281#define ERR_BADIO	(unsigned)2	/* read/write/select errors */
282#define ERR_BADSTATUS	(unsigned)3	/* unsync states */
283#define ERR_BADEVENT	(unsigned)4	/* non nominal events */
284#define ERR_INTERNAL	(unsigned)5	/* internal error */
285#define ERR_CNT		(unsigned)(ERR_INTERNAL+1)
286
287#define ERR(_X_)	if (list_err(parse, (_X_)))
288
289struct errorregression
290{
291	u_long err_count;	/* number of repititions per class */
292	u_long err_delay;	/* minimum delay between messages */
293};
294
295static struct errorregression
296err_baddata[] =			/* error messages for bad input data */
297{
298	{ 1,       0 },		/* output first message immediately */
299	{ 5,      60 },		/* output next five messages in 60 second intervals */
300	{ 3,    3600 },		/* output next 3 messages in hour intervals */
301	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
302};
303
304static struct errorregression
305err_nodata[] =			/* error messages for missing input data */
306{
307	{ 1,       0 },		/* output first message immediately */
308	{ 5,      60 },		/* output next five messages in 60 second intervals */
309	{ 3,    3600 },		/* output next 3 messages in hour intervals */
310	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
311};
312
313static struct errorregression
314err_badstatus[] =		/* unsynchronized state messages */
315{
316	{ 1,       0 },		/* output first message immediately */
317	{ 5,      60 },		/* output next five messages in 60 second intervals */
318	{ 3,    3600 },		/* output next 3 messages in hour intervals */
319	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
320};
321
322static struct errorregression
323err_badio[] =			/* io failures (bad reads, selects, ...) */
324{
325	{ 1,       0 },		/* output first message immediately */
326	{ 5,      60 },		/* output next five messages in 60 second intervals */
327	{ 5,    3600 },		/* output next 3 messages in hour intervals */
328	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
329};
330
331static struct errorregression
332err_badevent[] =		/* non nominal events */
333{
334	{ 20,      0 },		/* output first message immediately */
335	{ 6,      60 },		/* output next five messages in 60 second intervals */
336	{ 5,    3600 },		/* output next 3 messages in hour intervals */
337	{ 0, 12*3600 }		/* repeat messages only every 12 hours */
338};
339
340static struct errorregression
341err_internal[] =		/* really bad things - basically coding/OS errors */
342{
343	{ 0,       0 },		/* output all messages immediately */
344};
345
346static struct errorregression *
347err_tbl[] =
348{
349	err_baddata,
350	err_nodata,
351	err_badio,
352	err_badstatus,
353	err_badevent,
354	err_internal
355};
356
357struct errorinfo
358{
359	u_long err_started;	/* begin time (ntp) of error condition */
360	u_long err_last;	/* last time (ntp) error occurred */
361	u_long err_cnt;	/* number of error repititions */
362	u_long err_suppressed;	/* number of suppressed messages */
363	struct errorregression *err_stage; /* current error stage */
364};
365
366/**===========================================================================
367 ** refclock instance data
368 **/
369
370struct parseunit
371{
372	/*
373	 * NTP management
374	 */
375	struct peer         *peer;		/* backlink to peer structure - refclock inactive if 0  */
376	struct refclockproc *generic;		/* backlink to refclockproc structure */
377
378	/*
379	 * PARSE io
380	 */
381	bind_t	     *binding;	        /* io handling binding */
382
383	/*
384	 * parse state
385	 */
386	parse_t	      parseio;	        /* io handling structure (user level parsing) */
387
388	/*
389	 * type specific parameters
390	 */
391	struct parse_clockinfo   *parse_type;	        /* link to clock description */
392
393	/*
394	 * clock state handling/reporting
395	 */
396	u_char	      flags;	        /* flags (leap_control) */
397	u_long	      lastchange;       /* time (ntp) when last state change accured */
398	u_long	      statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
399	u_long        pollneeddata; 	/* current_time(!=0) for receive sample expected in PPS mode */
400	u_short	      lastformat;       /* last format used */
401	u_long        lastsync;		/* time (ntp) when clock was last seen fully synchronized */
402        u_long        maxunsync;        /* max time in seconds a receiver is trusted after loosing synchronisation */
403        double        ppsphaseadjust;   /* phase adjustment of PPS time stamp */
404        u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
405	u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
406	int	      ppsfd;	        /* fd to ise for PPS io */
407#ifdef HAVE_PPSAPI
408        pps_handle_t  ppshandle;        /* store PPSAPI handle */
409        pps_params_t  ppsparams;        /* current PPS parameters */
410        int           hardppsstate;     /* current hard pps state */
411#endif
412	parsetime_t   timedata;		/* last (parse module) data */
413	void         *localdata;        /* optional local, receiver-specific data */
414        unsigned long localstate;       /* private local state */
415	struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
416	struct ctl_var *kv;	        /* additional pseudo variables */
417	u_long        laststatistic;    /* time when staticstics where output */
418};
419
420
421/**===========================================================================
422 ** Clockinfo section all parameter for specific clock types
423 ** includes NTP parameters, TTY parameters and IO handling parameters
424 **/
425
426static	void	poll_dpoll	P((struct parseunit *));
427static	void	poll_poll	P((struct peer *));
428static	int	poll_init	P((struct parseunit *));
429
430typedef struct poll_info
431{
432	u_long      rate;		/* poll rate - once every "rate" seconds - 0 off */
433	const char *string;		/* string to send for polling */
434	u_long      count;		/* number of characters in string */
435} poll_info_t;
436
437#define NO_CL_FLAGS	0
438#define NO_POLL		0
439#define NO_INIT		0
440#define NO_END		0
441#define NO_EVENT	0
442#define NO_LCLDATA	0
443#define NO_MESSAGE	0
444#define NO_PPSDELAY     0
445
446#define DCF_ID		"DCF"	/* generic DCF */
447#define DCF_A_ID	"DCFa"	/* AM demodulation */
448#define DCF_P_ID	"DCFp"	/* psuedo random phase shift */
449#define GPS_ID		"GPS"	/* GPS receiver */
450
451#define	NOCLOCK_ROOTDELAY	0.0
452#define	NOCLOCK_BASEDELAY	0.0
453#define	NOCLOCK_DESCRIPTION	0
454#define NOCLOCK_MAXUNSYNC       0
455#define NOCLOCK_CFLAG           0
456#define NOCLOCK_IFLAG           0
457#define NOCLOCK_OFLAG           0
458#define NOCLOCK_LFLAG           0
459#define NOCLOCK_ID		"TILT"
460#define NOCLOCK_POLL		NO_POLL
461#define NOCLOCK_INIT		NO_INIT
462#define NOCLOCK_END		NO_END
463#define NOCLOCK_DATA		NO_LCLDATA
464#define NOCLOCK_FORMAT		""
465#define NOCLOCK_TYPE		CTL_SST_TS_UNSPEC
466#define NOCLOCK_SAMPLES		0
467#define NOCLOCK_KEEP		0
468
469#define DCF_TYPE		CTL_SST_TS_LF
470#define GPS_TYPE		CTL_SST_TS_UHF
471
472/*
473 * receiver specific constants
474 */
475#define MBG_SPEED		(B9600)
476#define MBG_CFLAG		(CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
477#define MBG_IFLAG		(IGNBRK|IGNPAR|ISTRIP)
478#define MBG_OFLAG		0
479#define MBG_LFLAG		0
480#define MBG_FLAGS               PARSE_F_PPSONSECOND
481
482/*
483 * Meinberg DCF77 receivers
484 */
485#define	DCFUA31_ROOTDELAY	0.0  /* 0 */
486#define	DCFUA31_BASEDELAY	0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
487#define	DCFUA31_DESCRIPTION	"Meinberg DCF77 C51 or compatible"
488#define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
489#define DCFUA31_SPEED		MBG_SPEED
490#define DCFUA31_CFLAG           MBG_CFLAG
491#define DCFUA31_IFLAG           MBG_IFLAG
492#define DCFUA31_OFLAG           MBG_OFLAG
493#define DCFUA31_LFLAG           MBG_LFLAG
494#define DCFUA31_SAMPLES		5
495#define DCFUA31_KEEP		3
496#define DCFUA31_FORMAT		"Meinberg Standard"
497
498/*
499 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
500 */
501#define	DCFPZF535_ROOTDELAY	0.0
502#define	DCFPZF535_BASEDELAY	0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
503#define	DCFPZF535_DESCRIPTION	"Meinberg DCF PZF 535/509 / TCXO"
504#define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
505						    * @ 5e-8df/f we have accumulated
506						    * at most 2.16 ms (thus we move to
507						    * NTP synchronisation */
508#define DCFPZF535_SPEED		MBG_SPEED
509#define DCFPZF535_CFLAG         MBG_CFLAG
510#define DCFPZF535_IFLAG         MBG_IFLAG
511#define DCFPZF535_OFLAG         MBG_OFLAG
512#define DCFPZF535_LFLAG         MBG_LFLAG
513#define DCFPZF535_SAMPLES	       5
514#define DCFPZF535_KEEP		       3
515#define DCFPZF535_FORMAT	"Meinberg Standard"
516
517/*
518 * Meinberg DCF PZF535/OCXO receiver
519 */
520#define	DCFPZF535OCXO_ROOTDELAY	0.0
521#define	DCFPZF535OCXO_BASEDELAY	0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
522#define	DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
523#define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
524						    * @ 5e-9df/f we have accumulated
525						    * at most an error of 1.73 ms
526						    * (thus we move to NTP synchronisation) */
527#define DCFPZF535OCXO_SPEED	    MBG_SPEED
528#define DCFPZF535OCXO_CFLAG         MBG_CFLAG
529#define DCFPZF535OCXO_IFLAG         MBG_IFLAG
530#define DCFPZF535OCXO_OFLAG         MBG_OFLAG
531#define DCFPZF535OCXO_LFLAG         MBG_LFLAG
532#define DCFPZF535OCXO_SAMPLES		   5
533#define DCFPZF535OCXO_KEEP	           3
534#define DCFPZF535OCXO_FORMAT	    "Meinberg Standard"
535
536/*
537 * Meinberg GPS16X receiver
538 */
539static	void	gps16x_message	 P((struct parseunit *, parsetime_t *));
540static  int     gps16x_poll_init P((struct parseunit *));
541
542#define	GPS16X_ROOTDELAY	0.0         /* nothing here */
543#define	GPS16X_BASEDELAY	0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
544#define	GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
545#define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
546						* @ 5e-9df/f we have accumulated
547						* at most an error of 1.73 ms
548						* (thus we move to NTP synchronisation) */
549#define GPS16X_SPEED		B19200
550#define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
551#define GPS16X_IFLAG            (IGNBRK|IGNPAR)
552#define GPS16X_OFLAG            MBG_OFLAG
553#define GPS16X_LFLAG            MBG_LFLAG
554#define GPS16X_POLLRATE	6
555#define GPS16X_POLLCMD	""
556#define GPS16X_CMDSIZE	0
557
558static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
559
560#define GPS16X_INIT		gps16x_poll_init
561#define GPS16X_POLL	        0
562#define GPS16X_END		0
563#define GPS16X_DATA		((void *)(&gps16x_pollinfo))
564#define GPS16X_MESSAGE		gps16x_message
565#define GPS16X_ID		GPS_ID
566#define GPS16X_FORMAT		"Meinberg GPS Extended"
567#define GPS16X_SAMPLES		5
568#define GPS16X_KEEP		3
569
570/*
571 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
572 *
573 * This is really not the hottest clock - but before you have nothing ...
574 */
575#define DCF7000_ROOTDELAY	0.0 /* 0 */
576#define DCF7000_BASEDELAY	0.405 /* slow blow */
577#define DCF7000_DESCRIPTION	"ELV DCF7000"
578#define DCF7000_MAXUNSYNC	(60*5) /* sorry - but it just was not build as a clock */
579#define DCF7000_SPEED		(B9600)
580#define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
581#define DCF7000_IFLAG		(IGNBRK)
582#define DCF7000_OFLAG		0
583#define DCF7000_LFLAG		0
584#define DCF7000_SAMPLES		5
585#define DCF7000_KEEP		3
586#define DCF7000_FORMAT		"ELV DCF7000"
587
588/*
589 * Schmid DCF Receiver Kit
590 *
591 * When the WSDCF clock is operating optimally we want the primary clock
592 * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
593 * structure is set to 290 ms and we compute delays which are at least
594 * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
595 */
596#define WS_POLLRATE	1	/* every second - watch interdependency with poll routine */
597#define WS_POLLCMD	"\163"
598#define WS_CMDSIZE	1
599
600static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
601
602#define WSDCF_INIT		poll_init
603#define WSDCF_POLL		poll_dpoll
604#define WSDCF_END		0
605#define WSDCF_DATA		((void *)(&wsdcf_pollinfo))
606#define	WSDCF_ROOTDELAY		0.0	/* 0 */
607#define	WSDCF_BASEDELAY	 	0.010	/*  ~  10ms */
608#define WSDCF_DESCRIPTION	"WS/DCF Receiver"
609#define WSDCF_FORMAT		"Schmid"
610#define WSDCF_MAXUNSYNC		(60*60)	/* assume this beast hold at 1 h better than 2 ms XXX-must verify */
611#define WSDCF_SPEED		(B1200)
612#define WSDCF_CFLAG		(CS8|CREAD|CLOCAL)
613#define WSDCF_IFLAG		0
614#define WSDCF_OFLAG		0
615#define WSDCF_LFLAG		0
616#define WSDCF_SAMPLES		5
617#define WSDCF_KEEP		3
618
619/*
620 * RAW DCF77 - input of DCF marks via RS232 - many variants
621 */
622#define RAWDCF_FLAGS		0
623#define RAWDCF_ROOTDELAY	0.0 /* 0 */
624#define RAWDCF_BASEDELAY	0.258
625#define RAWDCF_FORMAT		"RAW DCF77 Timecode"
626#define RAWDCF_MAXUNSYNC	(0) /* sorry - its a true receiver - no signal - no time */
627#define RAWDCF_SPEED		(B50)
628#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
629/* somehow doesn't grok PARENB & IGNPAR (mj) */
630# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
631#else
632# define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
633#endif
634#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
635# define RAWDCF_IFLAG		0
636#else
637# define RAWDCF_IFLAG		(IGNPAR)
638#endif
639#define RAWDCF_OFLAG		0
640#define RAWDCF_LFLAG		0
641#define RAWDCF_SAMPLES		20
642#define RAWDCF_KEEP		12
643#define RAWDCF_INIT		0
644
645/*
646 * RAW DCF variants
647 */
648/*
649 * Conrad receiver
650 *
651 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
652 * (~40DM - roughly $30 ) followed by a level converter for RS232
653 */
654#define CONRAD_BASEDELAY	0.292 /* Conrad receiver @ 50 Baud on a Sun */
655#define CONRAD_DESCRIPTION	"RAW DCF77 CODE (Conrad DCF77 receiver module)"
656
657/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
658#define GUDE_EMC_USB_V20_SPEED            (B4800)
659#define GUDE_EMC_USB_V20_BASEDELAY        0.425 /* USB serial<->USB converter FTDI232R */
660#define GUDE_EMC_USB_V20_DESCRIPTION      "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
661
662/*
663 * TimeBrick receiver
664 */
665#define TIMEBRICK_BASEDELAY	0.210 /* TimeBrick @ 50 Baud on a Sun */
666#define TIMEBRICK_DESCRIPTION	"RAW DCF77 CODE (TimeBrick)"
667
668/*
669 * IGEL:clock receiver
670 */
671#define IGELCLOCK_BASEDELAY	0.258 /* IGEL:clock receiver */
672#define IGELCLOCK_DESCRIPTION	"RAW DCF77 CODE (IGEL:clock)"
673#define IGELCLOCK_SPEED		(B1200)
674#define IGELCLOCK_CFLAG		(CS8|CREAD|HUPCL|CLOCAL)
675
676/*
677 * RAWDCF receivers that need to be powered from DTR
678 * (like Expert mouse clock)
679 */
680static	int	rawdcf_init_1	P((struct parseunit *));
681#define RAWDCFDTRSET_DESCRIPTION	"RAW DCF77 CODE (DTR SET/RTS CLR)"
682#define RAWDCFDTRSET_INIT 		rawdcf_init_1
683
684/*
685 * RAWDCF receivers that need to be powered from
686 * DTR CLR and RTS SET
687 */
688static	int	rawdcf_init_2	P((struct parseunit *));
689#define RAWDCFDTRCLRRTSSET_DESCRIPTION	"RAW DCF77 CODE (DTR CLR/RTS SET)"
690#define RAWDCFDTRCLRRTSSET_INIT	rawdcf_init_2
691
692/*
693 * Trimble GPS receivers (TAIP and TSIP protocols)
694 */
695#ifndef TRIM_POLLRATE
696#define TRIM_POLLRATE	0	/* only true direct polling */
697#endif
698
699#define TRIM_TAIPPOLLCMD	">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
700#define TRIM_TAIPCMDSIZE	(sizeof(TRIM_TAIPPOLLCMD)-1)
701
702static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
703static	int	trimbletaip_init	P((struct parseunit *));
704static	void	trimbletaip_event	P((struct parseunit *, int));
705
706/* query time & UTC correction data */
707static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
708
709static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
710static	int	trimbletsip_init	P((struct parseunit *));
711static	void	trimbletsip_end   	P((struct parseunit *));
712static	void	trimbletsip_message	P((struct parseunit *, parsetime_t *));
713static	void	trimbletsip_event	P((struct parseunit *, int));
714
715#define TRIMBLETSIP_IDLE_TIME	    (300) /* 5 minutes silence at most */
716#define TRIMBLE_RESET_HOLDOFF       TRIMBLETSIP_IDLE_TIME
717
718#define TRIMBLETAIP_SPEED	    (B4800)
719#define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
720#define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
721#define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
722#define TRIMBLETAIP_LFLAG           (0)
723
724#define TRIMBLETSIP_SPEED	    (B9600)
725#define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
726#define TRIMBLETSIP_IFLAG           (IGNBRK)
727#define TRIMBLETSIP_OFLAG           (0)
728#define TRIMBLETSIP_LFLAG           (ICANON)
729
730#define TRIMBLETSIP_SAMPLES	    5
731#define TRIMBLETSIP_KEEP	    3
732#define TRIMBLETAIP_SAMPLES	    5
733#define TRIMBLETAIP_KEEP	    3
734
735#define TRIMBLETAIP_FLAGS	    (PARSE_F_PPSONSECOND)
736#define TRIMBLETSIP_FLAGS	    (TRIMBLETAIP_FLAGS)
737
738#define TRIMBLETAIP_POLL	    poll_dpoll
739#define TRIMBLETSIP_POLL	    poll_dpoll
740
741#define TRIMBLETAIP_INIT	    trimbletaip_init
742#define TRIMBLETSIP_INIT	    trimbletsip_init
743
744#define TRIMBLETAIP_EVENT	    trimbletaip_event
745
746#define TRIMBLETSIP_EVENT	    trimbletsip_event
747#define TRIMBLETSIP_MESSAGE	    trimbletsip_message
748
749#define TRIMBLETAIP_END		    0
750#define TRIMBLETSIP_END		    trimbletsip_end
751
752#define TRIMBLETAIP_DATA	    ((void *)(&trimbletaip_pollinfo))
753#define TRIMBLETSIP_DATA	    ((void *)(&trimbletsip_pollinfo))
754
755#define TRIMBLETAIP_ID		    GPS_ID
756#define TRIMBLETSIP_ID		    GPS_ID
757
758#define TRIMBLETAIP_FORMAT	    "Trimble TAIP"
759#define TRIMBLETSIP_FORMAT	    "Trimble TSIP"
760
761#define TRIMBLETAIP_ROOTDELAY        0x0
762#define TRIMBLETSIP_ROOTDELAY        0x0
763
764#define TRIMBLETAIP_BASEDELAY        0.0
765#define TRIMBLETSIP_BASEDELAY        0.020	/* GPS time message latency */
766
767#define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
768#define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
769
770#define TRIMBLETAIP_MAXUNSYNC        0
771#define TRIMBLETSIP_MAXUNSYNC        0
772
773#define TRIMBLETAIP_EOL		    '<'
774
775/*
776 * RadioCode Clocks RCC 800 receiver
777 */
778#define RCC_POLLRATE   0       /* only true direct polling */
779#define RCC_POLLCMD    "\r"
780#define RCC_CMDSIZE    1
781
782static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
783#define RCC8000_FLAGS		0
784#define RCC8000_POLL            poll_dpoll
785#define RCC8000_INIT            poll_init
786#define RCC8000_END             0
787#define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
788#define RCC8000_ROOTDELAY       0.0
789#define RCC8000_BASEDELAY       0.0
790#define RCC8000_ID              "MSF"
791#define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
792#define RCC8000_FORMAT          "Radiocode RCC8000"
793#define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
794#define RCC8000_SPEED		(B2400)
795#define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
796#define RCC8000_IFLAG           (IGNBRK|IGNPAR)
797#define RCC8000_OFLAG           0
798#define RCC8000_LFLAG           0
799#define RCC8000_SAMPLES         5
800#define RCC8000_KEEP	        3
801
802/*
803 * Hopf Radio clock 6021 Format
804 *
805 */
806#define HOPF6021_ROOTDELAY	0.0
807#define HOPF6021_BASEDELAY	0.0
808#define HOPF6021_DESCRIPTION	"HOPF 6021"
809#define HOPF6021_FORMAT         "hopf Funkuhr 6021"
810#define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
811#define HOPF6021_SPEED         (B9600)
812#define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
813#define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
814#define HOPF6021_OFLAG		0
815#define HOPF6021_LFLAG		0
816#define HOPF6021_FLAGS          0
817#define HOPF6021_SAMPLES        5
818#define HOPF6021_KEEP	        3
819
820/*
821 * Diem's Computime Radio Clock Receiver
822 */
823#define COMPUTIME_FLAGS       0
824#define COMPUTIME_ROOTDELAY   0.0
825#define COMPUTIME_BASEDELAY   0.0
826#define COMPUTIME_ID          DCF_ID
827#define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
828#define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
829#define COMPUTIME_TYPE        DCF_TYPE
830#define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
831#define COMPUTIME_SPEED       (B9600)
832#define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
833#define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
834#define COMPUTIME_OFLAG       0
835#define COMPUTIME_LFLAG       0
836#define COMPUTIME_SAMPLES     5
837#define COMPUTIME_KEEP        3
838
839/*
840 * Varitext Radio Clock Receiver
841 */
842#define VARITEXT_FLAGS       0
843#define VARITEXT_ROOTDELAY   0.0
844#define VARITEXT_BASEDELAY   0.0
845#define VARITEXT_ID          "MSF"
846#define VARITEXT_DESCRIPTION "Varitext receiver"
847#define VARITEXT_FORMAT      "Varitext Radio Clock"
848#define VARITEXT_TYPE        DCF_TYPE
849#define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
850#define VARITEXT_SPEED       (B9600)
851#define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
852#define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
853#define VARITEXT_OFLAG       0
854#define VARITEXT_LFLAG       0
855#define VARITEXT_SAMPLES     32
856#define VARITEXT_KEEP        20
857
858static struct parse_clockinfo
859{
860	u_long  cl_flags;		/* operation flags (io modes) */
861  void  (*cl_poll)    P((struct parseunit *));			/* active poll routine */
862  int   (*cl_init)    P((struct parseunit *));			/* active poll init routine */
863  void  (*cl_event)   P((struct parseunit *, int));		/* special event handling (e.g. reset clock) */
864  void  (*cl_end)     P((struct parseunit *));			/* active poll end routine */
865  void  (*cl_message) P((struct parseunit *, parsetime_t *));	/* process a lower layer message */
866	void   *cl_data;		/* local data area for "poll" mechanism */
867	double    cl_rootdelay;		/* rootdelay */
868	double    cl_basedelay;		/* current offset by which the RS232
869				time code is delayed from the actual time */
870	const char *cl_id;		/* ID code */
871	const char *cl_description;		/* device name */
872	const char *cl_format;		/* fixed format */
873	u_char  cl_type;		/* clock type (ntp control) */
874	u_long  cl_maxunsync;		/* time to trust oscillator after losing synch */
875	u_long  cl_speed;		/* terminal input & output baudrate */
876	u_long  cl_cflag;             /* terminal control flags */
877	u_long  cl_iflag;             /* terminal input flags */
878	u_long  cl_oflag;             /* terminal output flags */
879	u_long  cl_lflag;             /* terminal local flags */
880	u_long  cl_samples;	      /* samples for median filter */
881	u_long  cl_keep;              /* samples for median filter to keep */
882} parse_clockinfo[] =
883{
884	{				/* mode 0 */
885		MBG_FLAGS,
886		NO_POLL,
887		NO_INIT,
888		NO_EVENT,
889		NO_END,
890		NO_MESSAGE,
891		NO_LCLDATA,
892		DCFPZF535_ROOTDELAY,
893		DCFPZF535_BASEDELAY,
894		DCF_P_ID,
895		DCFPZF535_DESCRIPTION,
896		DCFPZF535_FORMAT,
897		DCF_TYPE,
898		DCFPZF535_MAXUNSYNC,
899		DCFPZF535_SPEED,
900		DCFPZF535_CFLAG,
901		DCFPZF535_IFLAG,
902		DCFPZF535_OFLAG,
903		DCFPZF535_LFLAG,
904		DCFPZF535_SAMPLES,
905		DCFPZF535_KEEP
906	},
907	{				/* mode 1 */
908		MBG_FLAGS,
909		NO_POLL,
910		NO_INIT,
911		NO_EVENT,
912		NO_END,
913		NO_MESSAGE,
914		NO_LCLDATA,
915		DCFPZF535OCXO_ROOTDELAY,
916		DCFPZF535OCXO_BASEDELAY,
917		DCF_P_ID,
918		DCFPZF535OCXO_DESCRIPTION,
919		DCFPZF535OCXO_FORMAT,
920		DCF_TYPE,
921		DCFPZF535OCXO_MAXUNSYNC,
922		DCFPZF535OCXO_SPEED,
923		DCFPZF535OCXO_CFLAG,
924		DCFPZF535OCXO_IFLAG,
925		DCFPZF535OCXO_OFLAG,
926		DCFPZF535OCXO_LFLAG,
927		DCFPZF535OCXO_SAMPLES,
928		DCFPZF535OCXO_KEEP
929	},
930	{				/* mode 2 */
931		MBG_FLAGS,
932		NO_POLL,
933		NO_INIT,
934		NO_EVENT,
935		NO_END,
936		NO_MESSAGE,
937		NO_LCLDATA,
938		DCFUA31_ROOTDELAY,
939		DCFUA31_BASEDELAY,
940		DCF_A_ID,
941		DCFUA31_DESCRIPTION,
942		DCFUA31_FORMAT,
943		DCF_TYPE,
944		DCFUA31_MAXUNSYNC,
945		DCFUA31_SPEED,
946		DCFUA31_CFLAG,
947		DCFUA31_IFLAG,
948		DCFUA31_OFLAG,
949		DCFUA31_LFLAG,
950		DCFUA31_SAMPLES,
951		DCFUA31_KEEP
952	},
953	{				/* mode 3 */
954		MBG_FLAGS,
955		NO_POLL,
956		NO_INIT,
957		NO_EVENT,
958		NO_END,
959		NO_MESSAGE,
960		NO_LCLDATA,
961		DCF7000_ROOTDELAY,
962		DCF7000_BASEDELAY,
963		DCF_A_ID,
964		DCF7000_DESCRIPTION,
965		DCF7000_FORMAT,
966		DCF_TYPE,
967		DCF7000_MAXUNSYNC,
968		DCF7000_SPEED,
969		DCF7000_CFLAG,
970		DCF7000_IFLAG,
971		DCF7000_OFLAG,
972		DCF7000_LFLAG,
973		DCF7000_SAMPLES,
974		DCF7000_KEEP
975	},
976	{				/* mode 4 */
977		NO_CL_FLAGS,
978		WSDCF_POLL,
979		WSDCF_INIT,
980		NO_EVENT,
981		WSDCF_END,
982		NO_MESSAGE,
983		WSDCF_DATA,
984		WSDCF_ROOTDELAY,
985		WSDCF_BASEDELAY,
986		DCF_A_ID,
987		WSDCF_DESCRIPTION,
988		WSDCF_FORMAT,
989		DCF_TYPE,
990		WSDCF_MAXUNSYNC,
991		WSDCF_SPEED,
992		WSDCF_CFLAG,
993		WSDCF_IFLAG,
994		WSDCF_OFLAG,
995		WSDCF_LFLAG,
996		WSDCF_SAMPLES,
997		WSDCF_KEEP
998	},
999	{				/* mode 5 */
1000		RAWDCF_FLAGS,
1001		NO_POLL,
1002		RAWDCF_INIT,
1003		NO_EVENT,
1004		NO_END,
1005		NO_MESSAGE,
1006		NO_LCLDATA,
1007		RAWDCF_ROOTDELAY,
1008		CONRAD_BASEDELAY,
1009		DCF_A_ID,
1010		CONRAD_DESCRIPTION,
1011		RAWDCF_FORMAT,
1012		DCF_TYPE,
1013		RAWDCF_MAXUNSYNC,
1014		RAWDCF_SPEED,
1015		RAWDCF_CFLAG,
1016		RAWDCF_IFLAG,
1017		RAWDCF_OFLAG,
1018		RAWDCF_LFLAG,
1019		RAWDCF_SAMPLES,
1020		RAWDCF_KEEP
1021	},
1022	{				/* mode 6 */
1023		RAWDCF_FLAGS,
1024		NO_POLL,
1025		RAWDCF_INIT,
1026		NO_EVENT,
1027		NO_END,
1028		NO_MESSAGE,
1029		NO_LCLDATA,
1030		RAWDCF_ROOTDELAY,
1031		TIMEBRICK_BASEDELAY,
1032		DCF_A_ID,
1033		TIMEBRICK_DESCRIPTION,
1034		RAWDCF_FORMAT,
1035		DCF_TYPE,
1036		RAWDCF_MAXUNSYNC,
1037		RAWDCF_SPEED,
1038		RAWDCF_CFLAG,
1039		RAWDCF_IFLAG,
1040		RAWDCF_OFLAG,
1041		RAWDCF_LFLAG,
1042		RAWDCF_SAMPLES,
1043		RAWDCF_KEEP
1044	},
1045	{				/* mode 7 */
1046		MBG_FLAGS,
1047		GPS16X_POLL,
1048		GPS16X_INIT,
1049		NO_EVENT,
1050		GPS16X_END,
1051		GPS16X_MESSAGE,
1052		GPS16X_DATA,
1053		GPS16X_ROOTDELAY,
1054		GPS16X_BASEDELAY,
1055		GPS16X_ID,
1056		GPS16X_DESCRIPTION,
1057		GPS16X_FORMAT,
1058		GPS_TYPE,
1059		GPS16X_MAXUNSYNC,
1060		GPS16X_SPEED,
1061		GPS16X_CFLAG,
1062		GPS16X_IFLAG,
1063		GPS16X_OFLAG,
1064		GPS16X_LFLAG,
1065		GPS16X_SAMPLES,
1066		GPS16X_KEEP
1067	},
1068	{				/* mode 8 */
1069		RAWDCF_FLAGS,
1070		NO_POLL,
1071		NO_INIT,
1072		NO_EVENT,
1073		NO_END,
1074		NO_MESSAGE,
1075		NO_LCLDATA,
1076		RAWDCF_ROOTDELAY,
1077		IGELCLOCK_BASEDELAY,
1078		DCF_A_ID,
1079		IGELCLOCK_DESCRIPTION,
1080		RAWDCF_FORMAT,
1081		DCF_TYPE,
1082		RAWDCF_MAXUNSYNC,
1083		IGELCLOCK_SPEED,
1084		IGELCLOCK_CFLAG,
1085		RAWDCF_IFLAG,
1086		RAWDCF_OFLAG,
1087		RAWDCF_LFLAG,
1088		RAWDCF_SAMPLES,
1089		RAWDCF_KEEP
1090	},
1091	{				/* mode 9 */
1092		TRIMBLETAIP_FLAGS,
1093#if TRIM_POLLRATE		/* DHD940515: Allow user config */
1094		NO_POLL,
1095#else
1096		TRIMBLETAIP_POLL,
1097#endif
1098		TRIMBLETAIP_INIT,
1099		TRIMBLETAIP_EVENT,
1100		TRIMBLETAIP_END,
1101		NO_MESSAGE,
1102		TRIMBLETAIP_DATA,
1103		TRIMBLETAIP_ROOTDELAY,
1104		TRIMBLETAIP_BASEDELAY,
1105		TRIMBLETAIP_ID,
1106		TRIMBLETAIP_DESCRIPTION,
1107		TRIMBLETAIP_FORMAT,
1108		GPS_TYPE,
1109		TRIMBLETAIP_MAXUNSYNC,
1110		TRIMBLETAIP_SPEED,
1111		TRIMBLETAIP_CFLAG,
1112		TRIMBLETAIP_IFLAG,
1113		TRIMBLETAIP_OFLAG,
1114		TRIMBLETAIP_LFLAG,
1115		TRIMBLETAIP_SAMPLES,
1116		TRIMBLETAIP_KEEP
1117	},
1118	{				/* mode 10 */
1119		TRIMBLETSIP_FLAGS,
1120#if TRIM_POLLRATE		/* DHD940515: Allow user config */
1121		NO_POLL,
1122#else
1123		TRIMBLETSIP_POLL,
1124#endif
1125		TRIMBLETSIP_INIT,
1126		TRIMBLETSIP_EVENT,
1127		TRIMBLETSIP_END,
1128		TRIMBLETSIP_MESSAGE,
1129		TRIMBLETSIP_DATA,
1130		TRIMBLETSIP_ROOTDELAY,
1131		TRIMBLETSIP_BASEDELAY,
1132		TRIMBLETSIP_ID,
1133		TRIMBLETSIP_DESCRIPTION,
1134		TRIMBLETSIP_FORMAT,
1135		GPS_TYPE,
1136		TRIMBLETSIP_MAXUNSYNC,
1137		TRIMBLETSIP_SPEED,
1138		TRIMBLETSIP_CFLAG,
1139		TRIMBLETSIP_IFLAG,
1140		TRIMBLETSIP_OFLAG,
1141		TRIMBLETSIP_LFLAG,
1142		TRIMBLETSIP_SAMPLES,
1143		TRIMBLETSIP_KEEP
1144	},
1145	{                             /* mode 11 */
1146		NO_CL_FLAGS,
1147		RCC8000_POLL,
1148		RCC8000_INIT,
1149		NO_EVENT,
1150		RCC8000_END,
1151		NO_MESSAGE,
1152		RCC8000_DATA,
1153		RCC8000_ROOTDELAY,
1154		RCC8000_BASEDELAY,
1155		RCC8000_ID,
1156		RCC8000_DESCRIPTION,
1157		RCC8000_FORMAT,
1158		DCF_TYPE,
1159		RCC8000_MAXUNSYNC,
1160		RCC8000_SPEED,
1161		RCC8000_CFLAG,
1162		RCC8000_IFLAG,
1163		RCC8000_OFLAG,
1164		RCC8000_LFLAG,
1165		RCC8000_SAMPLES,
1166		RCC8000_KEEP
1167	},
1168	{                             /* mode 12 */
1169		HOPF6021_FLAGS,
1170		NO_POLL,
1171		NO_INIT,
1172		NO_EVENT,
1173		NO_END,
1174		NO_MESSAGE,
1175		NO_LCLDATA,
1176		HOPF6021_ROOTDELAY,
1177		HOPF6021_BASEDELAY,
1178		DCF_ID,
1179		HOPF6021_DESCRIPTION,
1180		HOPF6021_FORMAT,
1181		DCF_TYPE,
1182		HOPF6021_MAXUNSYNC,
1183		HOPF6021_SPEED,
1184		HOPF6021_CFLAG,
1185		HOPF6021_IFLAG,
1186		HOPF6021_OFLAG,
1187		HOPF6021_LFLAG,
1188		HOPF6021_SAMPLES,
1189		HOPF6021_KEEP
1190	},
1191	{                            /* mode 13 */
1192		COMPUTIME_FLAGS,
1193		NO_POLL,
1194		NO_INIT,
1195		NO_EVENT,
1196		NO_END,
1197		NO_MESSAGE,
1198		NO_LCLDATA,
1199		COMPUTIME_ROOTDELAY,
1200		COMPUTIME_BASEDELAY,
1201		COMPUTIME_ID,
1202		COMPUTIME_DESCRIPTION,
1203		COMPUTIME_FORMAT,
1204		COMPUTIME_TYPE,
1205		COMPUTIME_MAXUNSYNC,
1206		COMPUTIME_SPEED,
1207		COMPUTIME_CFLAG,
1208		COMPUTIME_IFLAG,
1209		COMPUTIME_OFLAG,
1210		COMPUTIME_LFLAG,
1211		COMPUTIME_SAMPLES,
1212		COMPUTIME_KEEP
1213	},
1214	{				/* mode 14 */
1215		RAWDCF_FLAGS,
1216		NO_POLL,
1217		RAWDCFDTRSET_INIT,
1218		NO_EVENT,
1219		NO_END,
1220		NO_MESSAGE,
1221		NO_LCLDATA,
1222		RAWDCF_ROOTDELAY,
1223		RAWDCF_BASEDELAY,
1224		DCF_A_ID,
1225		RAWDCFDTRSET_DESCRIPTION,
1226		RAWDCF_FORMAT,
1227		DCF_TYPE,
1228		RAWDCF_MAXUNSYNC,
1229		RAWDCF_SPEED,
1230		RAWDCF_CFLAG,
1231		RAWDCF_IFLAG,
1232		RAWDCF_OFLAG,
1233		RAWDCF_LFLAG,
1234		RAWDCF_SAMPLES,
1235		RAWDCF_KEEP
1236	},
1237	{				/* mode 15 */
1238		0,				/* operation flags (io modes) */
1239  		NO_POLL,			/* active poll routine */
1240		NO_INIT,			/* active poll init routine */
1241  		NO_EVENT,		        /* special event handling (e.g. reset clock) */
1242  		NO_END,				/* active poll end routine */
1243  		NO_MESSAGE,			/* process a lower layer message */
1244		NO_LCLDATA,			/* local data area for "poll" mechanism */
1245		0,				/* rootdelay */
1246		11.0 /* bits */ / 9600,		/* current offset by which the RS232
1247				           	time code is delayed from the actual time */
1248		DCF_ID,				/* ID code */
1249		"WHARTON 400A Series clock",	/* device name */
1250		"WHARTON 400A Series clock Output Format 1",	/* fixed format */
1251			/* Must match a format-name in a libparse/clk_xxx.c file */
1252		DCF_TYPE,			/* clock type (ntp control) */
1253		(1*60*60),		        /* time to trust oscillator after losing synch */
1254		B9600,				/* terminal input & output baudrate */
1255		(CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1256		0,				/* terminal input flags */
1257		0,				/* terminal output flags */
1258		0,				/* terminal local flags */
1259		5,				/* samples for median filter */
1260		3,				/* samples for median filter to keep */
1261	},
1262	{				/* mode 16 - RAWDCF RTS set, DTR clr */
1263		RAWDCF_FLAGS,
1264		NO_POLL,
1265		RAWDCFDTRCLRRTSSET_INIT,
1266		NO_EVENT,
1267		NO_END,
1268		NO_MESSAGE,
1269		NO_LCLDATA,
1270		RAWDCF_ROOTDELAY,
1271		RAWDCF_BASEDELAY,
1272		DCF_A_ID,
1273		RAWDCFDTRCLRRTSSET_DESCRIPTION,
1274		RAWDCF_FORMAT,
1275		DCF_TYPE,
1276		RAWDCF_MAXUNSYNC,
1277		RAWDCF_SPEED,
1278		RAWDCF_CFLAG,
1279		RAWDCF_IFLAG,
1280		RAWDCF_OFLAG,
1281		RAWDCF_LFLAG,
1282		RAWDCF_SAMPLES,
1283		RAWDCF_KEEP
1284	},
1285        {                            /* mode 17 */
1286                VARITEXT_FLAGS,
1287                NO_POLL,
1288                NO_INIT,
1289                NO_EVENT,
1290                NO_END,
1291                NO_MESSAGE,
1292                NO_LCLDATA,
1293                VARITEXT_ROOTDELAY,
1294                VARITEXT_BASEDELAY,
1295                VARITEXT_ID,
1296                VARITEXT_DESCRIPTION,
1297                VARITEXT_FORMAT,
1298                VARITEXT_TYPE,
1299                VARITEXT_MAXUNSYNC,
1300                VARITEXT_SPEED,
1301                VARITEXT_CFLAG,
1302                VARITEXT_IFLAG,
1303                VARITEXT_OFLAG,
1304                VARITEXT_LFLAG,
1305                VARITEXT_SAMPLES,
1306                VARITEXT_KEEP
1307        },
1308	{				/* mode 18 */
1309		MBG_FLAGS,
1310		NO_POLL,
1311		NO_INIT,
1312		NO_EVENT,
1313		GPS16X_END,
1314		GPS16X_MESSAGE,
1315		GPS16X_DATA,
1316		GPS16X_ROOTDELAY,
1317		GPS16X_BASEDELAY,
1318		GPS16X_ID,
1319		GPS16X_DESCRIPTION,
1320		GPS16X_FORMAT,
1321		GPS_TYPE,
1322		GPS16X_MAXUNSYNC,
1323		GPS16X_SPEED,
1324		GPS16X_CFLAG,
1325		GPS16X_IFLAG,
1326		GPS16X_OFLAG,
1327		GPS16X_LFLAG,
1328		GPS16X_SAMPLES,
1329		GPS16X_KEEP
1330	},
1331	{				/* mode 19 */
1332		RAWDCF_FLAGS,
1333		NO_POLL,
1334		RAWDCF_INIT,
1335		NO_EVENT,
1336		NO_END,
1337		NO_MESSAGE,
1338		NO_LCLDATA,
1339		RAWDCF_ROOTDELAY,
1340		GUDE_EMC_USB_V20_BASEDELAY,
1341		DCF_A_ID,
1342		GUDE_EMC_USB_V20_DESCRIPTION,
1343		RAWDCF_FORMAT,
1344		DCF_TYPE,
1345		RAWDCF_MAXUNSYNC,
1346		GUDE_EMC_USB_V20_SPEED,
1347		RAWDCF_CFLAG,
1348		RAWDCF_IFLAG,
1349		RAWDCF_OFLAG,
1350		RAWDCF_LFLAG,
1351		RAWDCF_SAMPLES,
1352		RAWDCF_KEEP
1353	},
1354};
1355
1356static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1357
1358#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1359#define CLK_TYPE(x)	((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1360#define CLK_UNIT(x)	((int)REFCLOCKUNIT(&(x)->srcadr))
1361#define CLK_PPS(x)	(((x)->ttl) & 0x80)
1362
1363/*
1364 * Other constant stuff
1365 */
1366#define	PARSEHSREFID	0x7f7f08ff	/* 127.127.8.255 refid for hi strata */
1367
1368#define PARSESTATISTICS   (60*60)	        /* output state statistics every hour */
1369
1370static int notice = 0;
1371
1372#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1373
1374static void parse_event   P((struct parseunit *, int));
1375static void parse_process P((struct parseunit *, parsetime_t *));
1376static void clear_err     P((struct parseunit *, u_long));
1377static int  list_err      P((struct parseunit *, u_long));
1378static char * l_mktime    P((u_long));
1379
1380/**===========================================================================
1381 ** implementation error message regression module
1382 **/
1383static void
1384clear_err(
1385	struct parseunit *parse,
1386	u_long            lstate
1387	)
1388{
1389	if (lstate == ERR_ALL)
1390	{
1391		int i;
1392
1393		for (i = 0; i < ERR_CNT; i++)
1394		{
1395			parse->errors[i].err_stage   = err_tbl[i];
1396			parse->errors[i].err_cnt     = 0;
1397			parse->errors[i].err_last    = 0;
1398			parse->errors[i].err_started = 0;
1399			parse->errors[i].err_suppressed = 0;
1400		}
1401	}
1402	else
1403	{
1404		parse->errors[lstate].err_stage   = err_tbl[lstate];
1405		parse->errors[lstate].err_cnt     = 0;
1406		parse->errors[lstate].err_last    = 0;
1407		parse->errors[lstate].err_started = 0;
1408		parse->errors[lstate].err_suppressed = 0;
1409	}
1410}
1411
1412static int
1413list_err(
1414	struct parseunit *parse,
1415	u_long            lstate
1416	)
1417{
1418	int do_it;
1419	struct errorinfo *err = &parse->errors[lstate];
1420
1421	if (err->err_started == 0)
1422	{
1423		err->err_started = current_time;
1424	}
1425
1426	do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1427
1428	if (do_it)
1429	    err->err_cnt++;
1430
1431	if (err->err_stage->err_count &&
1432	    (err->err_cnt >= err->err_stage->err_count))
1433	{
1434		err->err_stage++;
1435		err->err_cnt = 0;
1436	}
1437
1438	if (!err->err_cnt && do_it)
1439	    msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1440		    CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1441
1442	if (!do_it)
1443	    err->err_suppressed++;
1444	else
1445	    err->err_last = current_time;
1446
1447	if (do_it && err->err_suppressed)
1448	{
1449		msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1450			CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1451			l_mktime(current_time - err->err_started));
1452		err->err_suppressed = 0;
1453	}
1454
1455	return do_it;
1456}
1457
1458/*--------------------------------------------------
1459 * mkreadable - make a printable ascii string (without
1460 * embedded quotes so that the ntpq protocol isn't
1461 * fooled
1462 */
1463#ifndef isprint
1464#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1465#endif
1466
1467static char *
1468mkreadable(
1469	char  *buffer,
1470	long  blen,
1471	const char  *src,
1472	u_long  srclen,
1473	int hex
1474	)
1475{
1476	char *b    = buffer;
1477	char *endb = (char *)0;
1478
1479	if (blen < 4)
1480		return (char *)0;		/* don't bother with mini buffers */
1481
1482	endb = buffer + blen - 4;
1483
1484	blen--;			/* account for '\0' */
1485
1486	while (blen && srclen--)
1487	{
1488		if (!hex &&             /* no binary only */
1489		    (*src != '\\') &&   /* no plain \ */
1490		    (*src != '"') &&    /* no " */
1491		    isprint((int)*src))	/* only printables */
1492		{			/* they are easy... */
1493			*buffer++ = *src++;
1494			blen--;
1495		}
1496		else
1497		{
1498			if (blen < 4)
1499			{
1500				while (blen--)
1501				{
1502					*buffer++ = '.';
1503				}
1504				*buffer = '\0';
1505				return b;
1506			}
1507			else
1508			{
1509				if (*src == '\\')
1510				{
1511					strcpy(buffer,"\\\\");
1512					buffer += 2;
1513					blen   -= 2;
1514					src++;
1515				}
1516				else
1517				{
1518					sprintf(buffer, "\\x%02x", *src++);
1519					blen   -= 4;
1520					buffer += 4;
1521				}
1522			}
1523		}
1524		if (srclen && !blen && endb) /* overflow - set last chars to ... */
1525			strcpy(endb, "...");
1526	}
1527
1528	*buffer = '\0';
1529	return b;
1530}
1531
1532
1533/*--------------------------------------------------
1534 * mkascii - make a printable ascii string
1535 * assumes (unless defined better) 7-bit ASCII
1536 */
1537static char *
1538mkascii(
1539	char  *buffer,
1540	long  blen,
1541	const char  *src,
1542	u_long  srclen
1543	)
1544{
1545	return mkreadable(buffer, blen, src, srclen, 0);
1546}
1547
1548/**===========================================================================
1549 ** implementation of i/o handling methods
1550 ** (all STREAM, partial STREAM, user level)
1551 **/
1552
1553/*
1554 * define possible io handling methods
1555 */
1556#ifdef STREAM
1557static int  ppsclock_init   P((struct parseunit *));
1558static int  stream_init     P((struct parseunit *));
1559static void stream_end      P((struct parseunit *));
1560static int  stream_enable   P((struct parseunit *));
1561static int  stream_disable  P((struct parseunit *));
1562static int  stream_setcs    P((struct parseunit *, parsectl_t *));
1563static int  stream_getfmt   P((struct parseunit *, parsectl_t *));
1564static int  stream_setfmt   P((struct parseunit *, parsectl_t *));
1565static int  stream_timecode P((struct parseunit *, parsectl_t *));
1566static void stream_receive  P((struct recvbuf *));
1567#endif
1568
1569static int  local_init     P((struct parseunit *));
1570static void local_end      P((struct parseunit *));
1571static int  local_nop      P((struct parseunit *));
1572static int  local_setcs    P((struct parseunit *, parsectl_t *));
1573static int  local_getfmt   P((struct parseunit *, parsectl_t *));
1574static int  local_setfmt   P((struct parseunit *, parsectl_t *));
1575static int  local_timecode P((struct parseunit *, parsectl_t *));
1576static void local_receive  P((struct recvbuf *));
1577static int  local_input    P((struct recvbuf *));
1578
1579static bind_t io_bindings[] =
1580{
1581#ifdef STREAM
1582	{
1583		"parse STREAM",
1584		stream_init,
1585		stream_end,
1586		stream_setcs,
1587		stream_disable,
1588		stream_enable,
1589		stream_getfmt,
1590		stream_setfmt,
1591		stream_timecode,
1592		stream_receive,
1593		0,
1594	},
1595	{
1596		"ppsclock STREAM",
1597		ppsclock_init,
1598		local_end,
1599		local_setcs,
1600		local_nop,
1601		local_nop,
1602		local_getfmt,
1603		local_setfmt,
1604		local_timecode,
1605		local_receive,
1606		local_input,
1607	},
1608#endif
1609	{
1610		"normal",
1611		local_init,
1612		local_end,
1613		local_setcs,
1614		local_nop,
1615		local_nop,
1616		local_getfmt,
1617		local_setfmt,
1618		local_timecode,
1619		local_receive,
1620		local_input,
1621	},
1622	{
1623		(char *)0,
1624	}
1625};
1626
1627#ifdef STREAM
1628
1629#define fix_ts(_X_) \
1630                        if ((&(_X_))->tv.tv_usec >= 1000000)                \
1631                          {                                                 \
1632			    (&(_X_))->tv.tv_usec -= 1000000;                \
1633			    (&(_X_))->tv.tv_sec  += 1;                      \
1634			  }
1635
1636#define cvt_ts(_X_, _Y_) \
1637                        {                                                   \
1638			  l_fp ts;				            \
1639			  fix_ts((_X_));                                    \
1640			  if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1641			    {                                               \
1642                              ERR(ERR_BADDATA)	 		            \
1643                                msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1644			      return;                                       \
1645			    }                                               \
1646			  else                                              \
1647			    {                                               \
1648			      (&(_X_))->fp = ts;                            \
1649			    }                                               \
1650		        }
1651
1652/*--------------------------------------------------
1653 * ppsclock STREAM init
1654 */
1655static int
1656ppsclock_init(
1657	struct parseunit *parse
1658	)
1659{
1660        static char m1[] = "ppsclocd";
1661	static char m2[] = "ppsclock";
1662
1663	/*
1664	 * now push the parse streams module
1665	 * it will ensure exclusive access to the device
1666	 */
1667	if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1668	    ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
1669	{
1670		if (errno != EINVAL)
1671		{
1672			msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1673				CLK_UNIT(parse->peer));
1674		}
1675		return 0;
1676	}
1677	if (!local_init(parse))
1678	{
1679		(void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
1680		return 0;
1681	}
1682
1683	parse->flags |= PARSE_PPSCLOCK;
1684	return 1;
1685}
1686
1687/*--------------------------------------------------
1688 * parse STREAM init
1689 */
1690static int
1691stream_init(
1692	struct parseunit *parse
1693	)
1694{
1695	static char m1[] = "parse";
1696	/*
1697	 * now push the parse streams module
1698	 * to test whether it is there (neat interface 8-( )
1699	 */
1700	if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1701	{
1702		if (errno != EINVAL) /* accept non-existence */
1703		{
1704			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1705		}
1706		return 0;
1707	}
1708	else
1709	{
1710		while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1711		    /* empty loop */;
1712
1713		/*
1714		 * now push it a second time after we have removed all
1715		 * module garbage
1716		 */
1717		if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1718		{
1719			msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1720			return 0;
1721		}
1722		else
1723		{
1724			return 1;
1725		}
1726	}
1727}
1728
1729/*--------------------------------------------------
1730 * parse STREAM end
1731 */
1732static void
1733stream_end(
1734	struct parseunit *parse
1735	)
1736{
1737	while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1738	    /* empty loop */;
1739}
1740
1741/*--------------------------------------------------
1742 * STREAM setcs
1743 */
1744static int
1745stream_setcs(
1746	struct parseunit *parse,
1747	parsectl_t  *tcl
1748	)
1749{
1750	struct strioctl strioc;
1751
1752	strioc.ic_cmd     = PARSEIOC_SETCS;
1753	strioc.ic_timout  = 0;
1754	strioc.ic_dp      = (char *)tcl;
1755	strioc.ic_len     = sizeof (*tcl);
1756
1757	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1758	{
1759		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1760		return 0;
1761	}
1762	return 1;
1763}
1764
1765/*--------------------------------------------------
1766 * STREAM enable
1767 */
1768static int
1769stream_enable(
1770	struct parseunit *parse
1771	)
1772{
1773	struct strioctl strioc;
1774
1775	strioc.ic_cmd     = PARSEIOC_ENABLE;
1776	strioc.ic_timout  = 0;
1777	strioc.ic_dp      = (char *)0;
1778	strioc.ic_len     = 0;
1779
1780	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1781	{
1782		msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1783		return 0;
1784	}
1785	parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1786	return 1;
1787}
1788
1789/*--------------------------------------------------
1790 * STREAM disable
1791 */
1792static int
1793stream_disable(
1794	struct parseunit *parse
1795	)
1796{
1797	struct strioctl strioc;
1798
1799	strioc.ic_cmd     = PARSEIOC_DISABLE;
1800	strioc.ic_timout  = 0;
1801	strioc.ic_dp      = (char *)0;
1802	strioc.ic_len     = 0;
1803
1804	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1805	{
1806		msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1807		return 0;
1808	}
1809	parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1810	return 1;
1811}
1812
1813/*--------------------------------------------------
1814 * STREAM getfmt
1815 */
1816static int
1817stream_getfmt(
1818	struct parseunit *parse,
1819	parsectl_t  *tcl
1820	)
1821{
1822	struct strioctl strioc;
1823
1824	strioc.ic_cmd     = PARSEIOC_GETFMT;
1825	strioc.ic_timout  = 0;
1826	strioc.ic_dp      = (char *)tcl;
1827	strioc.ic_len     = sizeof (*tcl);
1828	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1829	{
1830		msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1831		return 0;
1832	}
1833	return 1;
1834}
1835
1836/*--------------------------------------------------
1837 * STREAM setfmt
1838 */
1839static int
1840stream_setfmt(
1841	struct parseunit *parse,
1842	parsectl_t  *tcl
1843	)
1844{
1845	struct strioctl strioc;
1846
1847	strioc.ic_cmd     = PARSEIOC_SETFMT;
1848	strioc.ic_timout  = 0;
1849	strioc.ic_dp      = (char *)tcl;
1850	strioc.ic_len     = sizeof (*tcl);
1851
1852	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1853	{
1854		msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1855		return 0;
1856	}
1857	return 1;
1858}
1859
1860
1861/*--------------------------------------------------
1862 * STREAM timecode
1863 */
1864static int
1865stream_timecode(
1866	struct parseunit *parse,
1867	parsectl_t  *tcl
1868	)
1869{
1870	struct strioctl strioc;
1871
1872	strioc.ic_cmd     = PARSEIOC_TIMECODE;
1873	strioc.ic_timout  = 0;
1874	strioc.ic_dp      = (char *)tcl;
1875	strioc.ic_len     = sizeof (*tcl);
1876
1877	if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1878	{
1879		ERR(ERR_INTERNAL)
1880			msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
1881		return 0;
1882	}
1883	clear_err(parse, ERR_INTERNAL);
1884	return 1;
1885}
1886
1887/*--------------------------------------------------
1888 * STREAM receive
1889 */
1890static void
1891stream_receive(
1892	struct recvbuf *rbufp
1893	)
1894{
1895	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1896	parsetime_t parsetime;
1897
1898	if (!parse->peer)
1899	    return;
1900
1901	if (rbufp->recv_length != sizeof(parsetime_t))
1902	{
1903		ERR(ERR_BADIO)
1904			msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1905				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
1906		parse_event(parse, CEVNT_BADREPLY);
1907		return;
1908	}
1909	clear_err(parse, ERR_BADIO);
1910
1911	memmove((caddr_t)&parsetime,
1912		(caddr_t)rbufp->recv_buffer,
1913		sizeof(parsetime_t));
1914
1915#ifdef DEBUG
1916	if (debug > 3)
1917	  {
1918	    printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1919		   CLK_UNIT(parse->peer),
1920		   (unsigned int)parsetime.parse_status,
1921		   (unsigned int)parsetime.parse_state,
1922		   (unsigned long)parsetime.parse_time.tv.tv_sec,
1923		   (unsigned long)parsetime.parse_time.tv.tv_usec,
1924		   (unsigned long)parsetime.parse_stime.tv.tv_sec,
1925		   (unsigned long)parsetime.parse_stime.tv.tv_usec,
1926		   (unsigned long)parsetime.parse_ptime.tv.tv_sec,
1927		   (unsigned long)parsetime.parse_ptime.tv.tv_usec);
1928	  }
1929#endif
1930
1931	/*
1932	 * switch time stamp world - be sure to normalize small usec field
1933	 * errors.
1934	 */
1935
1936	cvt_ts(parsetime.parse_stime, "parse_stime");
1937
1938	if (PARSE_TIMECODE(parsetime.parse_state))
1939	{
1940	    cvt_ts(parsetime.parse_time, "parse_time");
1941	}
1942
1943	if (PARSE_PPS(parsetime.parse_state))
1944	    cvt_ts(parsetime.parse_ptime, "parse_ptime");
1945
1946	parse_process(parse, &parsetime);
1947}
1948#endif
1949
1950/*--------------------------------------------------
1951 * local init
1952 */
1953static int
1954local_init(
1955	struct parseunit *parse
1956	)
1957{
1958	return parse_ioinit(&parse->parseio);
1959}
1960
1961/*--------------------------------------------------
1962 * local end
1963 */
1964static void
1965local_end(
1966	struct parseunit *parse
1967	)
1968{
1969	parse_ioend(&parse->parseio);
1970}
1971
1972
1973/*--------------------------------------------------
1974 * local nop
1975 */
1976static int
1977local_nop(
1978	struct parseunit *parse
1979	)
1980{
1981	return 1;
1982}
1983
1984/*--------------------------------------------------
1985 * local setcs
1986 */
1987static int
1988local_setcs(
1989	struct parseunit *parse,
1990	parsectl_t  *tcl
1991	)
1992{
1993	return parse_setcs(tcl, &parse->parseio);
1994}
1995
1996/*--------------------------------------------------
1997 * local getfmt
1998 */
1999static int
2000local_getfmt(
2001	struct parseunit *parse,
2002	parsectl_t  *tcl
2003	)
2004{
2005	return parse_getfmt(tcl, &parse->parseio);
2006}
2007
2008/*--------------------------------------------------
2009 * local setfmt
2010 */
2011static int
2012local_setfmt(
2013	struct parseunit *parse,
2014	parsectl_t  *tcl
2015	)
2016{
2017	return parse_setfmt(tcl, &parse->parseio);
2018}
2019
2020/*--------------------------------------------------
2021 * local timecode
2022 */
2023static int
2024local_timecode(
2025	struct parseunit *parse,
2026	parsectl_t  *tcl
2027	)
2028{
2029	return parse_timecode(tcl, &parse->parseio);
2030}
2031
2032
2033/*--------------------------------------------------
2034 * local input
2035 */
2036static int
2037local_input(
2038	struct recvbuf *rbufp
2039	)
2040{
2041	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2042	int count;
2043	unsigned char *s;
2044	timestamp_t ts;
2045
2046	if (!parse->peer)
2047		return 0;
2048
2049	/*
2050	 * eat all characters, parsing then and feeding complete samples
2051	 */
2052	count = rbufp->recv_length;
2053	s = (unsigned char *)rbufp->recv_buffer;
2054	ts.fp = rbufp->recv_time;
2055
2056	while (count--)
2057	{
2058		if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
2059		{
2060			struct recvbuf *buf;
2061
2062			/*
2063			 * got something good to eat
2064			 */
2065			if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
2066			{
2067#ifdef HAVE_PPSAPI
2068				if (parse->flags & PARSE_PPSCLOCK)
2069				{
2070					struct timespec pps_timeout;
2071					pps_info_t      pps_info;
2072
2073					pps_timeout.tv_sec  = 0;
2074					pps_timeout.tv_nsec = 0;
2075
2076					if (time_pps_fetch(parse->ppshandle, PPS_TSFMT_TSPEC, &pps_info,
2077							   &pps_timeout) == 0)
2078					{
2079						if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2080						{
2081							double dtemp;
2082
2083						        struct timespec pts;
2084							/*
2085							 * add PPS time stamp if available via ppsclock module
2086							 * and not supplied already.
2087							 */
2088							if (parse->flags & PARSE_CLEAR)
2089							  pts = pps_info.clear_timestamp;
2090							else
2091							  pts = pps_info.assert_timestamp;
2092
2093							parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
2094
2095							dtemp = pts.tv_nsec / 1e9;
2096							if (dtemp < 0.) {
2097								dtemp += 1;
2098								parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2099							}
2100							if (dtemp > 1.) {
2101								dtemp -= 1;
2102								parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2103							}
2104							parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
2105
2106						        parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2107#ifdef DEBUG
2108							if (debug > 3)
2109							{
2110								printf(
2111								       "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2112								       rbufp->fd,
2113								       (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2114								       lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2115							}
2116#endif
2117						}
2118#ifdef DEBUG
2119						else
2120						{
2121							if (debug > 3)
2122							{
2123								printf(
2124								       "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2125								       rbufp->fd,
2126								       (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2127							}
2128						}
2129#endif
2130						parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2131					}
2132#ifdef DEBUG
2133					else
2134					{
2135						if (debug > 3)
2136						{
2137							printf(
2138							       "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2139							       rbufp->fd,
2140							       errno);
2141						}
2142					}
2143#endif
2144				}
2145#else
2146#ifdef TIOCDCDTIMESTAMP
2147				struct timeval dcd_time;
2148
2149				if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
2150				{
2151					l_fp tstmp;
2152
2153					TVTOTS(&dcd_time, &tstmp);
2154					tstmp.l_ui += JAN_1970;
2155					L_SUB(&ts.fp, &tstmp);
2156					if (ts.fp.l_ui == 0)
2157					{
2158#ifdef DEBUG
2159						if (debug)
2160						{
2161							printf(
2162							       "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2163							       parse->ppsfd,
2164							       lfptoa(&tstmp, 6));
2165							printf(" sigio %s\n",
2166							       lfptoa(&ts.fp, 6));
2167						}
2168#endif
2169						parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
2170						parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2171					}
2172				}
2173#else /* TIOCDCDTIMESTAMP */
2174#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
2175				if (parse->flags & PARSE_PPSCLOCK)
2176				  {
2177				    l_fp tts;
2178				    struct ppsclockev ev;
2179
2180#ifdef HAVE_CIOGETEV
2181				    if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
2182#endif
2183#ifdef HAVE_TIOCGPPSEV
2184				    if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
2185#endif
2186					{
2187					  if (ev.serial != parse->ppsserial)
2188					    {
2189					      /*
2190					       * add PPS time stamp if available via ppsclock module
2191					       * and not supplied already.
2192					       */
2193					      if (!buftvtots((const char *)&ev.tv, &tts))
2194						{
2195						  ERR(ERR_BADDATA)
2196						    msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2197						}
2198					      else
2199						{
2200						  parse->parseio.parse_dtime.parse_ptime.fp = tts;
2201						  parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2202						}
2203					    }
2204					  parse->ppsserial = ev.serial;
2205					}
2206				  }
2207#endif
2208#endif /* TIOCDCDTIMESTAMP */
2209#endif /* !HAVE_PPSAPI */
2210			}
2211			if (count)
2212			{	/* simulate receive */
2213				buf = get_free_recv_buffer();
2214				if (buf != NULL) {
2215					memmove((caddr_t)buf->recv_buffer,
2216						(caddr_t)&parse->parseio.parse_dtime,
2217						sizeof(parsetime_t));
2218					buf->recv_length  = sizeof(parsetime_t);
2219					buf->recv_time    = rbufp->recv_time;
2220					buf->srcadr       = rbufp->srcadr;
2221					buf->dstadr       = rbufp->dstadr;
2222					buf->receiver     = rbufp->receiver;
2223					buf->fd           = rbufp->fd;
2224					buf->X_from_where = rbufp->X_from_where;
2225					add_full_recv_buffer(buf);
2226				}
2227				parse_iodone(&parse->parseio);
2228			}
2229			else
2230			{
2231				memmove((caddr_t)rbufp->recv_buffer,
2232					(caddr_t)&parse->parseio.parse_dtime,
2233					sizeof(parsetime_t));
2234				parse_iodone(&parse->parseio);
2235				rbufp->recv_length = sizeof(parsetime_t);
2236				return 1; /* got something & in place return */
2237			}
2238		}
2239	}
2240	return 0;		/* nothing to pass up */
2241}
2242
2243/*--------------------------------------------------
2244 * local receive
2245 */
2246static void
2247local_receive(
2248	struct recvbuf *rbufp
2249	)
2250{
2251	struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2252	parsetime_t parsetime;
2253
2254	if (!parse->peer)
2255	    return;
2256
2257	if (rbufp->recv_length != sizeof(parsetime_t))
2258	{
2259		ERR(ERR_BADIO)
2260			msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2261				CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2262		parse_event(parse, CEVNT_BADREPLY);
2263		return;
2264	}
2265	clear_err(parse, ERR_BADIO);
2266
2267	memmove((caddr_t)&parsetime,
2268		(caddr_t)rbufp->recv_buffer,
2269		sizeof(parsetime_t));
2270
2271#ifdef DEBUG
2272	if (debug > 3)
2273	  {
2274	    printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
2275		   CLK_UNIT(parse->peer),
2276		   (unsigned int)parsetime.parse_status,
2277		   (unsigned int)parsetime.parse_state,
2278		   (unsigned long)parsetime.parse_time.fp.l_ui,
2279		   (unsigned long)parsetime.parse_time.fp.l_uf,
2280		   (unsigned long)parsetime.parse_stime.fp.l_ui,
2281		   (unsigned long)parsetime.parse_stime.fp.l_uf,
2282		   (unsigned long)parsetime.parse_ptime.fp.l_ui,
2283		   (unsigned long)parsetime.parse_ptime.fp.l_uf);
2284	  }
2285#endif
2286
2287	parse_process(parse, &parsetime);
2288}
2289
2290/*--------------------------------------------------
2291 * init_iobinding - find and initialize lower layers
2292 */
2293static bind_t *
2294init_iobinding(
2295	struct parseunit *parse
2296	)
2297{
2298  bind_t *b = io_bindings;
2299
2300	while (b->bd_description != (char *)0)
2301	{
2302		if ((*b->bd_init)(parse))
2303		{
2304			return b;
2305		}
2306		b++;
2307	}
2308	return (bind_t *)0;
2309}
2310
2311/**===========================================================================
2312 ** support routines
2313 **/
2314
2315/*--------------------------------------------------
2316 * convert a flag field to a string
2317 */
2318static char *
2319parsestate(
2320	u_long lstate,
2321	char *buffer,
2322	int size
2323	)
2324{
2325	static struct bits
2326	{
2327		u_long      bit;
2328		const char *name;
2329	} flagstrings[] =
2330	  {
2331		  { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
2332		  { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
2333		  { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
2334		  { PARSEB_DST,        "DST" },
2335		  { PARSEB_UTC,        "UTC DISPLAY" },
2336		  { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
2337		  { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
2338		  { PARSEB_LEAPSECOND, "LEAP SECOND" },
2339		  { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
2340		  { PARSEB_TIMECODE,   "TIME CODE" },
2341		  { PARSEB_PPS,        "PPS" },
2342		  { PARSEB_POSITION,   "POSITION" },
2343		  { 0 }
2344	  };
2345
2346	static struct sbits
2347	{
2348		u_long      bit;
2349		const char *name;
2350	} sflagstrings[] =
2351	  {
2352		  { PARSEB_S_LEAP,     "LEAP INDICATION" },
2353		  { PARSEB_S_PPS,      "PPS SIGNAL" },
2354		  { PARSEB_S_ANTENNA,  "ANTENNA" },
2355		  { PARSEB_S_POSITION, "POSITION" },
2356		  { 0 }
2357	  };
2358	int i;
2359	char *s, *t;
2360
2361
2362	*buffer = '\0';
2363	s = t = buffer;
2364
2365	i = 0;
2366	while (flagstrings[i].bit)
2367	{
2368		if (flagstrings[i].bit & lstate)
2369		{
2370			if (s != t)
2371				strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2372			strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2373			t += strlen(t);
2374		}
2375		i++;
2376	}
2377
2378	if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2379	{
2380		if (s != t)
2381			strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2382
2383		t += strlen(t);
2384
2385		strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
2386
2387		s = t = t + strlen(t);
2388
2389		i = 0;
2390		while (sflagstrings[i].bit)
2391		{
2392			if (sflagstrings[i].bit & lstate)
2393			{
2394				if (t != s)
2395				{
2396					strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2397					t += 2;
2398				}
2399
2400				strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2401				t += strlen(t);
2402			}
2403			i++;
2404		}
2405		strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
2406	}
2407	return buffer;
2408}
2409
2410/*--------------------------------------------------
2411 * convert a status flag field to a string
2412 */
2413static char *
2414parsestatus(
2415	u_long lstate,
2416	char *buffer,
2417	int size
2418	)
2419{
2420	static struct bits
2421	{
2422		u_long      bit;
2423		const char *name;
2424	} flagstrings[] =
2425	  {
2426		  { CVT_OK,      "CONVERSION SUCCESSFUL" },
2427		  { CVT_NONE,    "NO CONVERSION" },
2428		  { CVT_FAIL,    "CONVERSION FAILED" },
2429		  { CVT_BADFMT,  "ILLEGAL FORMAT" },
2430		  { CVT_BADDATE, "DATE ILLEGAL" },
2431		  { CVT_BADTIME, "TIME ILLEGAL" },
2432		  { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2433		  { 0 }
2434	  };
2435	int i;
2436
2437	*buffer = '\0';
2438
2439	i = 0;
2440	while (flagstrings[i].bit)
2441	{
2442		if (flagstrings[i].bit & lstate)
2443		{
2444			if (buffer[0])
2445				strncat(buffer, "; ", size);
2446			strncat(buffer, flagstrings[i].name, size);
2447		}
2448		i++;
2449	}
2450
2451	return buffer;
2452}
2453
2454/*--------------------------------------------------
2455 * convert a clock status flag field to a string
2456 */
2457static const char *
2458clockstatus(
2459	u_long lstate
2460	)
2461{
2462	static char buffer[20];
2463	static struct status
2464	{
2465		u_long      value;
2466		const char *name;
2467	} flagstrings[] =
2468	  {
2469		  { CEVNT_NOMINAL, "NOMINAL" },
2470		  { CEVNT_TIMEOUT, "NO RESPONSE" },
2471		  { CEVNT_BADREPLY,"BAD FORMAT" },
2472		  { CEVNT_FAULT,   "FAULT" },
2473		  { CEVNT_PROP,    "PROPAGATION DELAY" },
2474		  { CEVNT_BADDATE, "ILLEGAL DATE" },
2475		  { CEVNT_BADTIME, "ILLEGAL TIME" },
2476		  { (unsigned)~0L }
2477	  };
2478	int i;
2479
2480	i = 0;
2481	while (flagstrings[i].value != ~0)
2482	{
2483		if (flagstrings[i].value == lstate)
2484		{
2485			return flagstrings[i].name;
2486		}
2487		i++;
2488	}
2489
2490	snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
2491
2492	return buffer;
2493}
2494
2495
2496/*--------------------------------------------------
2497 * l_mktime - make representation of a relative time
2498 */
2499static char *
2500l_mktime(
2501	u_long delta
2502	)
2503{
2504	u_long tmp, m, s;
2505	static char buffer[40];
2506	char *t;
2507
2508	buffer[0] = '\0';
2509
2510	if ((tmp = delta / (60*60*24)) != 0)
2511	{
2512		snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
2513		delta -= tmp * 60*60*24;
2514	}
2515
2516	s = delta % 60;
2517	delta /= 60;
2518	m = delta % 60;
2519	delta /= 60;
2520
2521	t = buffer + strlen(buffer);
2522
2523	snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
2524		 (int)delta, (int)m, (int)s);
2525
2526	return buffer;
2527}
2528
2529
2530/*--------------------------------------------------
2531 * parse_statistics - list summary of clock states
2532 */
2533static void
2534parse_statistics(
2535	struct parseunit *parse
2536	)
2537{
2538	int i;
2539
2540	NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2541		{
2542			msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2543				CLK_UNIT(parse->peer),
2544				l_mktime(current_time - parse->generic->timestarted));
2545
2546			msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2547				CLK_UNIT(parse->peer),
2548				clockstatus(parse->generic->currentstatus));
2549
2550			for (i = 0; i <= CEVNT_MAX; i++)
2551			{
2552				u_long s_time;
2553				u_long percent, d = current_time - parse->generic->timestarted;
2554
2555				percent = s_time = PARSE_STATETIME(parse, i);
2556
2557				while (((u_long)(~0) / 10000) < percent)
2558				{
2559					percent /= 10;
2560					d       /= 10;
2561				}
2562
2563				if (d)
2564				    percent = (percent * 10000) / d;
2565				else
2566				    percent = 10000;
2567
2568				if (s_time)
2569				    msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2570					    CLK_UNIT(parse->peer),
2571					    clockstatus((unsigned int)i),
2572					    l_mktime(s_time),
2573					    percent / 100, percent % 100);
2574			}
2575		}
2576}
2577
2578/*--------------------------------------------------
2579 * cparse_statistics - wrapper for statistics call
2580 */
2581static void
2582cparse_statistics(
2583        struct parseunit *parse
2584	)
2585{
2586	if (parse->laststatistic + PARSESTATISTICS < current_time)
2587		parse_statistics(parse);
2588	parse->laststatistic = current_time;
2589}
2590
2591/**===========================================================================
2592 ** ntp interface routines
2593 **/
2594
2595/*--------------------------------------------------
2596 * parse_shutdown - shut down a PARSE clock
2597 */
2598static void
2599parse_shutdown(
2600	int unit,
2601	struct peer *peer
2602	)
2603{
2604	struct parseunit *parse = (struct parseunit *)0;
2605
2606	if (peer && peer->procptr)
2607		parse = (struct parseunit *)peer->procptr->unitptr;
2608
2609	if (!parse)
2610	{
2611		/* nothing to clean up */
2612		return;
2613	}
2614
2615        if (!parse->peer)
2616	{
2617		msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2618		return;
2619	}
2620
2621#ifdef HAVE_PPSAPI
2622	if (parse->flags & PARSE_PPSCLOCK)
2623	{
2624		(void)time_pps_destroy(parse->ppshandle);
2625	}
2626#endif
2627	if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2628		(void)close(parse->ppsfd);  /* close separate PPS source */
2629
2630	/*
2631	 * print statistics a last time and
2632	 * stop statistics machine
2633	 */
2634	parse_statistics(parse);
2635
2636	if (parse->parse_type->cl_end)
2637	{
2638		parse->parse_type->cl_end(parse);
2639	}
2640
2641	/*
2642	 * cleanup before leaving this world
2643	 */
2644	if (parse->binding)
2645	    PARSE_END(parse);
2646
2647	/*
2648	 * Tell the I/O module to turn us off.  We're history.
2649	 */
2650	io_closeclock(&parse->generic->io);
2651
2652	free_varlist(parse->kv);
2653
2654	NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2655		msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2656			CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2657
2658	parse->peer = (struct peer *)0; /* unused now */
2659	peer->procptr->unitptr = (caddr_t)0;
2660	free(parse);
2661}
2662
2663#ifdef HAVE_PPSAPI
2664/*----------------------------------------
2665 * set up HARDPPS via PPSAPI
2666 */
2667static void
2668parse_hardpps(
2669	      struct parseunit *parse,
2670	      int mode
2671	      )
2672{
2673        if (parse->hardppsstate == mode)
2674	        return;
2675
2676	if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2677		int	i = 0;
2678
2679		if (mode == PARSE_HARDPPS_ENABLE)
2680		        {
2681			        if (parse->flags & PARSE_CLEAR)
2682				        i = PPS_CAPTURECLEAR;
2683				else
2684				        i = PPS_CAPTUREASSERT;
2685			}
2686
2687		if (time_pps_kcbind(parse->ppshandle, PPS_KC_HARDPPS, i,
2688		    PPS_TSFMT_TSPEC) < 0) {
2689		        msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2690				CLK_UNIT(parse->peer));
2691		} else {
2692		        NLOG(NLOG_CLOCKINFO)
2693		                msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2694					CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2695			/*
2696			 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2697			 */
2698			if (mode == PARSE_HARDPPS_ENABLE)
2699			        pps_enable = 1;
2700		}
2701	}
2702
2703	parse->hardppsstate = mode;
2704}
2705
2706/*----------------------------------------
2707 * set up PPS via PPSAPI
2708 */
2709static int
2710parse_ppsapi(
2711	     struct parseunit *parse
2712	)
2713{
2714	int cap, mode, mode1;
2715	char *cp;
2716
2717	parse->flags &= ~PARSE_PPSCLOCK;
2718
2719	if (time_pps_getcap(parse->ppshandle, &cap) < 0) {
2720		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2721			CLK_UNIT(parse->peer));
2722
2723		return 0;
2724	}
2725
2726	if (time_pps_getparams(parse->ppshandle, &parse->ppsparams) < 0) {
2727		msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getparams failed: %m",
2728			CLK_UNIT(parse->peer));
2729		return 0;
2730	}
2731
2732	/* nb. only turn things on, if someone else has turned something
2733	 *	on before we get here, leave it alone!
2734	 */
2735
2736	if (parse->flags & PARSE_CLEAR) {
2737		cp = "CLEAR";
2738		mode = PPS_CAPTURECLEAR;
2739		mode1 = PPS_OFFSETCLEAR;
2740	} else {
2741		cp = "ASSERT";
2742		mode = PPS_CAPTUREASSERT;
2743		mode1 = PPS_OFFSETASSERT;
2744	}
2745
2746	msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2747		CLK_UNIT(parse->peer), cp);
2748
2749	if (!(mode & cap)) {
2750	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED to initialize PPS to %s (PPS API capabilities=0x%x)",
2751		  CLK_UNIT(parse->peer), cp, cap);
2752
2753		return 0;
2754	}
2755
2756	if (!(mode1 & cap)) {
2757	  msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2758		  CLK_UNIT(parse->peer), cp, cap);
2759		mode1 = 0;
2760	} else {
2761	        if (mode1 == PPS_OFFSETCLEAR)
2762		        {
2763			        parse->ppsparams.clear_offset.tv_sec = -parse->ppsphaseadjust;
2764			        parse->ppsparams.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2765			}
2766
2767		if (mode1 == PPS_OFFSETASSERT)
2768	                {
2769		                parse->ppsparams.assert_offset.tv_sec = -parse->ppsphaseadjust;
2770				parse->ppsparams.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2771			}
2772	}
2773
2774	/* only set what is legal */
2775
2776	parse->ppsparams.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
2777
2778	if (time_pps_setparams(parse->ppshandle, &parse->ppsparams) < 0) {
2779	  msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2780		  CLK_UNIT(parse->peer));
2781		return 0;
2782	}
2783
2784	parse->flags |= PARSE_PPSCLOCK;
2785	return 1;
2786}
2787#else
2788#define parse_hardpps(_PARSE_, _MODE_) /* empty */
2789#endif
2790
2791/*--------------------------------------------------
2792 * parse_start - open the PARSE devices and initialize data for processing
2793 */
2794static int
2795parse_start(
2796	int sysunit,
2797	struct peer *peer
2798	)
2799{
2800	u_int unit;
2801	int fd232;
2802#ifdef HAVE_TERMIOS
2803	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
2804#endif
2805#ifdef HAVE_SYSV_TTYS
2806	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
2807#endif
2808	struct parseunit * parse;
2809	char parsedev[sizeof(PARSEDEVICE)+20];
2810	char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
2811	parsectl_t tmp_ctl;
2812	u_int type;
2813
2814	/*
2815	 * get out Copyright information once
2816	 */
2817	if (!notice)
2818        {
2819		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2820			msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2006, Frank Kardel");
2821		notice = 1;
2822	}
2823
2824	type = CLK_TYPE(peer);
2825	unit = CLK_UNIT(peer);
2826
2827	if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
2828	{
2829		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2830			unit, CLK_REALTYPE(peer), ncltypes-1);
2831		return 0;
2832	}
2833
2834	/*
2835	 * Unit okay, attempt to open the device.
2836	 */
2837	(void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
2838	(void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
2839
2840#ifndef O_NOCTTY
2841#define O_NOCTTY 0
2842#endif
2843
2844	fd232 = open(parsedev, O_RDWR | O_NOCTTY
2845#ifdef O_NONBLOCK
2846		     | O_NONBLOCK
2847#endif
2848		     , 0777);
2849
2850	if (fd232 == -1)
2851	{
2852		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2853		return 0;
2854	}
2855
2856	parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2857
2858	memset((char *)parse, 0, sizeof(struct parseunit));
2859
2860	parse->generic = peer->procptr;	 /* link up */
2861	parse->generic->unitptr = (caddr_t)parse; /* link down */
2862
2863	/*
2864	 * Set up the structures
2865	 */
2866	parse->generic->timestarted    = current_time;
2867	parse->lastchange     = current_time;
2868
2869	parse->flags          = 0;
2870	parse->pollneeddata   = 0;
2871	parse->laststatistic  = current_time;
2872	parse->lastformat     = (unsigned short)~0;	/* assume no format known */
2873	parse->timedata.parse_status = (unsigned short)~0;	/* be sure to mark initial status change */
2874	parse->lastmissed     = 0;	/* assume got everything */
2875	parse->ppsserial      = 0;
2876	parse->ppsfd	      = -1;
2877	parse->localdata      = (void *)0;
2878	parse->localstate     = 0;
2879	parse->kv             = (struct ctl_var *)0;
2880
2881	clear_err(parse, ERR_ALL);
2882
2883	parse->parse_type     = &parse_clockinfo[type];
2884
2885	parse->maxunsync      = parse->parse_type->cl_maxunsync;
2886
2887	parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
2888
2889	parse->generic->fudgetime2 = 0.0;
2890	parse->ppsphaseadjust = parse->generic->fudgetime2;
2891
2892	parse->generic->clockdesc  = parse->parse_type->cl_description;
2893
2894	peer->rootdelay       = parse->parse_type->cl_rootdelay;
2895	peer->sstclktype      = parse->parse_type->cl_type;
2896	peer->precision       = sys_precision;
2897
2898	peer->stratum         = STRATUM_REFCLOCK;
2899
2900	if (peer->stratum <= 1)
2901	    memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
2902	else
2903	    parse->generic->refid = htonl(PARSEHSREFID);
2904
2905	parse->generic->io.fd = fd232;
2906
2907	parse->peer = peer;		/* marks it also as busy */
2908
2909	/*
2910	 * configure terminal line
2911	 */
2912	if (TTY_GETATTR(fd232, &tio) == -1)
2913	{
2914		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
2915		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2916		return 0;
2917	}
2918	else
2919	{
2920#ifndef _PC_VDISABLE
2921		memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
2922#else
2923		int disablec;
2924		errno = 0;		/* pathconf can deliver -1 without changing errno ! */
2925
2926		disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
2927		if (disablec == -1 && errno)
2928		{
2929			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
2930			memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
2931		}
2932		else
2933		    if (disablec != -1)
2934			memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
2935#endif
2936
2937#if defined (VMIN) || defined(VTIME)
2938		if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
2939		{
2940#ifdef VMIN
2941			tio.c_cc[VMIN]   = 1;
2942#endif
2943#ifdef VTIME
2944			tio.c_cc[VTIME]  = 0;
2945#endif
2946		}
2947#endif
2948
2949		tio.c_cflag = parse_clockinfo[type].cl_cflag;
2950		tio.c_iflag = parse_clockinfo[type].cl_iflag;
2951		tio.c_oflag = parse_clockinfo[type].cl_oflag;
2952		tio.c_lflag = parse_clockinfo[type].cl_lflag;
2953
2954
2955#ifdef HAVE_TERMIOS
2956		if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
2957		    (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
2958		{
2959			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
2960			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2961			return 0;
2962		}
2963#else
2964		tio.c_cflag     |= parse_clockinfo[type].cl_speed;
2965#endif
2966
2967		/*
2968		 * set up pps device
2969		 * if the PARSEPPSDEVICE can be opened that will be used
2970		 * for PPS else PARSEDEVICE will be used
2971		 */
2972		parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
2973#ifdef O_NONBLOCK
2974				    | O_NONBLOCK
2975#endif
2976				    , 0777);
2977
2978		if (parse->ppsfd == -1)
2979		{
2980			parse->ppsfd = fd232;
2981		}
2982
2983/*
2984 * Linux PPS - the old way
2985 */
2986#if defined(HAVE_TIO_SERIAL_STUFF)		/* Linux hack: define PPS interface */
2987		{
2988			struct serial_struct	ss;
2989			if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
2990			    (
2991#ifdef ASYNC_LOW_LATENCY
2992			     ss.flags |= ASYNC_LOW_LATENCY,
2993#endif
2994#ifndef HAVE_PPSAPI
2995#ifdef ASYNC_PPS_CD_NEG
2996			     ss.flags |= ASYNC_PPS_CD_NEG,
2997#endif
2998#endif
2999			     ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3000				msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3001				msyslog(LOG_NOTICE,
3002					"refclock_parse: optional PPS processing not available");
3003			} else {
3004				parse->flags    |= PARSE_PPSCLOCK;
3005#ifdef ASYNC_PPS_CD_NEG
3006				NLOG(NLOG_CLOCKINFO)
3007				  msyslog(LOG_INFO,
3008					  "refclock_parse: PPS detection on");
3009#endif
3010			}
3011		}
3012#endif
3013
3014/*
3015 * SUN the Solaris way
3016 */
3017#ifdef HAVE_TIOCSPPS			/* SUN PPS support */
3018		if (CLK_PPS(parse->peer))
3019		    {
3020			int i = 1;
3021
3022			if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3023			    {
3024				parse->flags |= PARSE_PPSCLOCK;
3025			    }
3026		    }
3027#endif
3028
3029/*
3030 * PPS via PPSAPI
3031 */
3032#if defined(HAVE_PPSAPI)
3033		parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3034		if (CLK_PPS(parse->peer))
3035		{
3036		  if (time_pps_create(parse->ppsfd, &parse->ppshandle) < 0)
3037		    {
3038		      msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3039		    }
3040		  else
3041		    {
3042		      parse_ppsapi(parse);
3043		    }
3044		}
3045#endif
3046
3047		if (TTY_SETATTR(fd232, &tio) == -1)
3048		{
3049			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
3050			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3051			return 0;
3052		}
3053	}
3054
3055	/*
3056	 * pick correct input machine
3057	 */
3058	parse->generic->io.srcclock = (caddr_t)parse;
3059	parse->generic->io.datalen = 0;
3060
3061	parse->binding = init_iobinding(parse);
3062
3063	if (parse->binding == (bind_t *)0)
3064		{
3065			msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
3066			parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3067			return 0;			/* well, ok - special initialisation broke */
3068		}
3069
3070	parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3071	parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
3072
3073	/*
3074	 * as we always(?) get 8 bit chars we want to be
3075	 * sure, that the upper bits are zero for less
3076	 * than 8 bit I/O - so we pass that information on.
3077	 * note that there can be only one bit count format
3078	 * per file descriptor
3079	 */
3080
3081	switch (tio.c_cflag & CSIZE)
3082	{
3083	    case CS5:
3084		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
3085		break;
3086
3087	    case CS6:
3088		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
3089		break;
3090
3091	    case CS7:
3092		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
3093		break;
3094
3095	    case CS8:
3096		tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
3097		break;
3098	}
3099
3100	if (!PARSE_SETCS(parse, &tmp_ctl))
3101	{
3102		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
3103		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3104		return 0;			/* well, ok - special initialisation broke */
3105	}
3106
3107	strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3108	tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
3109
3110	if (!PARSE_SETFMT(parse, &tmp_ctl))
3111	{
3112		msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
3113		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3114		return 0;			/* well, ok - special initialisation broke */
3115	}
3116
3117	/*
3118	 * get rid of all IO accumulated so far
3119	 */
3120#ifdef HAVE_TERMIOS
3121	(void) tcflush(parse->generic->io.fd, TCIOFLUSH);
3122#else
3123#if defined(TCFLSH) && defined(TCIOFLUSH)
3124	{
3125		int flshcmd = TCIOFLUSH;
3126
3127		(void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
3128	}
3129#endif
3130#endif
3131
3132	/*
3133	 * try to do any special initializations
3134	 */
3135	if (parse->parse_type->cl_init)
3136		{
3137			if (parse->parse_type->cl_init(parse))
3138				{
3139					parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3140					return 0;		/* well, ok - special initialisation broke */
3141				}
3142		}
3143
3144	/*
3145	 * Insert in async io device list.
3146	 */
3147	if (!io_addclock(&parse->generic->io))
3148        {
3149		msyslog(LOG_ERR,
3150			"PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3151		parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3152		return 0;
3153	}
3154
3155	/*
3156	 * print out configuration
3157	 */
3158	NLOG(NLOG_CLOCKINFO)
3159		{
3160			/* conditional if clause for conditional syslog */
3161			msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3162				CLK_UNIT(parse->peer),
3163				parse->parse_type->cl_description, parsedev,
3164				(parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
3165
3166			msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3167				CLK_UNIT(parse->peer),
3168				parse->peer->stratum,
3169				l_mktime(parse->maxunsync), parse->peer->precision);
3170
3171			msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3172				CLK_UNIT(parse->peer),
3173				parse->parse_type->cl_rootdelay,
3174				parse->generic->fudgetime1,
3175				parse->ppsphaseadjust,
3176                                parse->binding->bd_description);
3177
3178			msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
3179				parse->parse_type->cl_format);
3180                        msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3181				CLK_PPS(parse->peer) ? "" : "NO ",
3182				CLK_PPS(parse->peer) ?
3183#ifdef PPS_METHOD
3184				" (implementation " PPS_METHOD ")"
3185#else
3186				""
3187#endif
3188				: ""
3189				);
3190		}
3191
3192	return 1;
3193}
3194
3195/*--------------------------------------------------
3196 * parse_ctl - process changes on flags/time values
3197 */
3198static void
3199parse_ctl(
3200	    struct parseunit *parse,
3201	    struct refclockstat *in
3202	    )
3203{
3204        if (in)
3205	{
3206		if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3207		{
3208		  parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3209		    (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3210#if defined(HAVE_PPSAPI)
3211		  if (CLK_PPS(parse->peer))
3212		    {
3213		      parse_ppsapi(parse);
3214		    }
3215#endif
3216		}
3217
3218		if (in->haveflags & CLK_HAVETIME1)
3219                {
3220		  parse->generic->fudgetime1 = in->fudgetime1;
3221		  msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3222			  CLK_UNIT(parse->peer),
3223			  parse->generic->fudgetime1);
3224		}
3225
3226		if (in->haveflags & CLK_HAVETIME2)
3227                {
3228		  parse->generic->fudgetime2 = in->fudgetime2;
3229		  if (parse->flags & PARSE_TRUSTTIME)
3230		    {
3231		      parse->maxunsync = (u_long)ABS(in->fudgetime2);
3232		      msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3233			      CLK_UNIT(parse->peer),
3234			      l_mktime(parse->maxunsync));
3235		    }
3236		  else
3237		    {
3238		      parse->ppsphaseadjust = in->fudgetime2;
3239		      msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3240			  CLK_UNIT(parse->peer),
3241			      parse->ppsphaseadjust);
3242#if defined(HAVE_PPSAPI)
3243		      if (CLK_PPS(parse->peer))
3244		      {
3245			      parse_ppsapi(parse);
3246		      }
3247#endif
3248		    }
3249		}
3250	}
3251}
3252
3253/*--------------------------------------------------
3254 * parse_poll - called by the transmit procedure
3255 */
3256static void
3257parse_poll(
3258	int unit,
3259	struct peer *peer
3260	)
3261{
3262	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3263
3264	if (peer != parse->peer)
3265	{
3266		msyslog(LOG_ERR,
3267			"PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3268			unit);
3269		return;
3270	}
3271
3272	/*
3273	 * Update clock stat counters
3274	 */
3275	parse->generic->polls++;
3276
3277	if (parse->pollneeddata &&
3278	    ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
3279	{
3280		/*
3281		 * start worrying when exceeding a poll inteval
3282		 * bad news - didn't get a response last time
3283		 */
3284		parse->lastmissed = current_time;
3285		parse_event(parse, CEVNT_TIMEOUT);
3286
3287		ERR(ERR_NODATA)
3288			msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
3289	}
3290
3291	/*
3292	 * we just mark that we want the next sample for the clock filter
3293	 */
3294	parse->pollneeddata = current_time;
3295
3296	if (parse->parse_type->cl_poll)
3297	{
3298		parse->parse_type->cl_poll(parse);
3299	}
3300
3301	cparse_statistics(parse);
3302
3303	return;
3304}
3305
3306#define LEN_STATES 300		/* length of state string */
3307
3308/*--------------------------------------------------
3309 * parse_control - set fudge factors, return statistics
3310 */
3311static void
3312parse_control(
3313	int unit,
3314	struct refclockstat *in,
3315	struct refclockstat *out,
3316	struct peer *peer
3317	)
3318{
3319        struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3320	parsectl_t tmpctl;
3321
3322	static char outstatus[400];	/* status output buffer */
3323
3324	if (out)
3325	{
3326		out->lencode       = 0;
3327		out->p_lastcode    = 0;
3328		out->kv_list       = (struct ctl_var *)0;
3329	}
3330
3331	if (!parse || !parse->peer)
3332	{
3333		msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3334			unit);
3335		return;
3336	}
3337
3338	unit = CLK_UNIT(parse->peer);
3339
3340	/*
3341	 * handle changes
3342	 */
3343	parse_ctl(parse, in);
3344
3345	/*
3346	 * supply data
3347	 */
3348	if (out)
3349	{
3350		u_long sum = 0;
3351		char *tt, *start;
3352		int i;
3353
3354		outstatus[0] = '\0';
3355
3356		out->type       = REFCLK_PARSE;
3357
3358		/*
3359		 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3360		 */
3361		parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3362
3363		/*
3364		 * figure out skew between PPS and RS232 - just for informational
3365		 * purposes
3366		 */
3367		if (PARSE_SYNC(parse->timedata.parse_state))
3368		{
3369			if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
3370			{
3371				l_fp off;
3372
3373				/*
3374				 * we have a PPS and RS232 signal - calculate the skew
3375				 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3376				 */
3377				off = parse->timedata.parse_stime.fp;
3378				L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
3379				tt = add_var(&out->kv_list, 80, RO);
3380				snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
3381			}
3382		}
3383
3384		if (PARSE_PPS(parse->timedata.parse_state))
3385		{
3386			tt = add_var(&out->kv_list, 80, RO|DEF);
3387			snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
3388		}
3389
3390		start = tt = add_var(&out->kv_list, 128, RO|DEF);
3391		snprintf(tt, 128, "refclock_time=\"");
3392		tt += strlen(tt);
3393
3394		if (parse->timedata.parse_time.fp.l_ui == 0)
3395		{
3396			strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
3397		}
3398		else
3399		{
3400			snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
3401		}
3402
3403		if (!PARSE_GETTIMECODE(parse, &tmpctl))
3404		{
3405			ERR(ERR_INTERNAL)
3406				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
3407		}
3408		else
3409		{
3410			start = tt = add_var(&out->kv_list, 512, RO|DEF);
3411			snprintf(tt, 512, "refclock_status=\"");
3412			tt += strlen(tt);
3413
3414			/*
3415			 * copy PPS flags from last read transaction (informational only)
3416			 */
3417			tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
3418				(PARSEB_PPS|PARSEB_S_PPS);
3419
3420			(void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
3421
3422			strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
3423
3424			if (tmpctl.parsegettc.parse_count)
3425			    mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3426				    tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
3427
3428		}
3429
3430		tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3431
3432		if (!PARSE_GETFMT(parse, &tmpctl))
3433		{
3434			ERR(ERR_INTERNAL)
3435				msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
3436		}
3437		else
3438		{
3439			tt = add_var(&out->kv_list, 80, RO|DEF);
3440			snprintf(tt, 80, "refclock_format=\"");
3441
3442			strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
3443			strncat(tt,"\"", 80);
3444		}
3445
3446		/*
3447		 * gather state statistics
3448		 */
3449
3450		start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3451		strncpy(tt, "refclock_states=\"", LEN_STATES);
3452		tt += strlen(tt);
3453
3454		for (i = 0; i <= CEVNT_MAX; i++)
3455		{
3456			u_long s_time;
3457			u_long d = current_time - parse->generic->timestarted;
3458			u_long percent;
3459
3460			percent = s_time = PARSE_STATETIME(parse, i);
3461
3462			while (((u_long)(~0) / 10000) < percent)
3463			{
3464				percent /= 10;
3465				d       /= 10;
3466			}
3467
3468			if (d)
3469			    percent = (percent * 10000) / d;
3470			else
3471			    percent = 10000;
3472
3473			if (s_time)
3474			{
3475				char item[80];
3476				int count;
3477
3478				snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
3479					sum ? "; " : "",
3480					(parse->generic->currentstatus == i) ? "*" : "",
3481					clockstatus((unsigned int)i),
3482					l_mktime(s_time),
3483					(int)(percent / 100), (int)(percent % 100));
3484				if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3485					{
3486						strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
3487						tt  += count;
3488					}
3489				sum += s_time;
3490			}
3491		}
3492
3493		snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
3494
3495		tt = add_var(&out->kv_list, 32, RO);
3496		snprintf(tt, 32,  "refclock_id=\"%s\"", parse->parse_type->cl_id);
3497
3498		tt = add_var(&out->kv_list, 80, RO);
3499		snprintf(tt, 80,  "refclock_iomode=\"%s\"", parse->binding->bd_description);
3500
3501		tt = add_var(&out->kv_list, 128, RO);
3502		snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3503
3504		{
3505			struct ctl_var *k;
3506
3507			k = parse->kv;
3508			while (k && !(k->flags & EOV))
3509			{
3510				set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3511				k++;
3512			}
3513		}
3514
3515		out->lencode       = strlen(outstatus);
3516		out->p_lastcode    = outstatus;
3517	}
3518}
3519
3520/**===========================================================================
3521 ** processing routines
3522 **/
3523
3524/*--------------------------------------------------
3525 * event handling - note that nominal events will also be posted
3526 * keep track of state dwelling times
3527 */
3528static void
3529parse_event(
3530	struct parseunit *parse,
3531	int event
3532	)
3533{
3534	if (parse->generic->currentstatus != (u_char) event)
3535	{
3536		parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3537		parse->lastchange              = current_time;
3538
3539		if (parse->parse_type->cl_event)
3540		    parse->parse_type->cl_event(parse, event);
3541
3542		if (event == CEVNT_NOMINAL)
3543		{
3544			NLOG(NLOG_CLOCKSTATUS)
3545				msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3546					CLK_UNIT(parse->peer));
3547		}
3548
3549		refclock_report(parse->peer, event);
3550	}
3551}
3552
3553/*--------------------------------------------------
3554 * process a PARSE time sample
3555 */
3556static void
3557parse_process(
3558	struct parseunit *parse,
3559	parsetime_t      *parsetime
3560	)
3561{
3562	l_fp off, rectime, reftime;
3563	double fudge;
3564
3565	/*
3566	 * check for changes in conversion status
3567	 * (only one for each new status !)
3568	 */
3569	if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3570	    ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3571	    (parse->timedata.parse_status != parsetime->parse_status))
3572	{
3573		char buffer[400];
3574
3575		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3576			msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3577				CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3578
3579		if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3580		{
3581			/*
3582			 * tell more about the story - list time code
3583			 * there is a slight change for a race condition and
3584			 * the time code might be overwritten by the next packet
3585			 */
3586			parsectl_t tmpctl;
3587
3588			if (!PARSE_GETTIMECODE(parse, &tmpctl))
3589			{
3590				ERR(ERR_INTERNAL)
3591					msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3592			}
3593			else
3594			{
3595				ERR(ERR_BADDATA)
3596					msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3597						CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
3598			}
3599		}
3600	}
3601
3602	/*
3603	 * examine status and post appropriate events
3604	 */
3605	if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3606	{
3607		/*
3608		 * got bad data - tell the rest of the system
3609		 */
3610		switch (parsetime->parse_status & CVT_MASK)
3611		{
3612		case CVT_NONE:
3613			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3614			    parse->parse_type->cl_message)
3615				parse->parse_type->cl_message(parse, parsetime);
3616			/*
3617			 * save PPS information that comes piggyback
3618			 */
3619			if (PARSE_PPS(parsetime->parse_state))
3620			  {
3621			    parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3622			    parse->timedata.parse_ptime  = parsetime->parse_ptime;
3623			  }
3624			break; 		/* well, still waiting - timeout is handled at higher levels */
3625
3626		case CVT_FAIL:
3627			if (parsetime->parse_status & CVT_BADFMT)
3628			{
3629				parse_event(parse, CEVNT_BADREPLY);
3630			}
3631			else
3632				if (parsetime->parse_status & CVT_BADDATE)
3633				{
3634					parse_event(parse, CEVNT_BADDATE);
3635				}
3636				else
3637					if (parsetime->parse_status & CVT_BADTIME)
3638					{
3639						parse_event(parse, CEVNT_BADTIME);
3640					}
3641					else
3642					{
3643						parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3644					}
3645		}
3646		return;			/* skip the rest - useless */
3647	}
3648
3649	/*
3650	 * check for format changes
3651	 * (in case somebody has swapped clocks 8-)
3652	 */
3653	if (parse->lastformat != parsetime->parse_format)
3654	{
3655		parsectl_t tmpctl;
3656
3657		tmpctl.parseformat.parse_format = parsetime->parse_format;
3658
3659		if (!PARSE_GETFMT(parse, &tmpctl))
3660		{
3661			ERR(ERR_INTERNAL)
3662				msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3663		}
3664		else
3665		{
3666			NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3667				msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3668					CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3669		}
3670		parse->lastformat = parsetime->parse_format;
3671	}
3672
3673	/*
3674	 * now, any changes ?
3675	 */
3676	if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3677	    ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
3678	{
3679		char tmp1[200];
3680		char tmp2[200];
3681		/*
3682		 * something happend - except for PPS events
3683		 */
3684
3685		(void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3686		(void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3687
3688		NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3689			msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3690				CLK_UNIT(parse->peer), tmp2, tmp1);
3691	}
3692
3693	/*
3694	 * carry on PPS information if still usable
3695	 */
3696	if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3697        {
3698	        parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3699		parsetime->parse_ptime  = parse->timedata.parse_ptime;
3700	}
3701
3702	/*
3703	 * remember for future
3704	 */
3705	parse->timedata = *parsetime;
3706
3707	/*
3708	 * check to see, whether the clock did a complete powerup or lost PZF signal
3709	 * and post correct events for current condition
3710	 */
3711	if (PARSE_POWERUP(parsetime->parse_state))
3712	{
3713		/*
3714		 * this is bad, as we have completely lost synchronisation
3715		 * well this is a problem with the receiver here
3716		 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3717		 * is true as it is the powerup state and the time is taken
3718		 * from a crude real time clock chip
3719		 * for the PZF series this is only partly true, as
3720		 * PARSE_POWERUP only means that the pseudo random
3721		 * phase shift sequence cannot be found. this is only
3722		 * bad, if we have never seen the clock in the SYNC
3723		 * state, where the PHASE and EPOCH are correct.
3724		 * for reporting events the above business does not
3725		 * really matter, but we can use the time code
3726		 * even in the POWERUP state after having seen
3727		 * the clock in the synchronized state (PZF class
3728		 * receivers) unless we have had a telegram disruption
3729		 * after having seen the clock in the SYNC state. we
3730		 * thus require having seen the clock in SYNC state
3731		 * *after* having missed telegrams (noresponse) from
3732		 * the clock. one problem remains: we might use erroneously
3733		 * POWERUP data if the disruption is shorter than 1 polling
3734		 * interval. fortunately powerdowns last usually longer than 64
3735		 * seconds and the receiver is at least 2 minutes in the
3736		 * POWERUP or NOSYNC state before switching to SYNC
3737		 */
3738		parse_event(parse, CEVNT_FAULT);
3739		NLOG(NLOG_CLOCKSTATUS)
3740			ERR(ERR_BADSTATUS)
3741			msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
3742				CLK_UNIT(parse->peer));
3743	}
3744	else
3745	{
3746		/*
3747		 * we have two states left
3748		 *
3749		 * SYNC:
3750		 *  this state means that the EPOCH (timecode) and PHASE
3751		 *  information has be read correctly (at least two
3752		 *  successive PARSE timecodes were received correctly)
3753		 *  this is the best possible state - full trust
3754		 *
3755		 * NOSYNC:
3756		 *  The clock should be on phase with respect to the second
3757		 *  signal, but the timecode has not been received correctly within
3758		 *  at least the last two minutes. this is a sort of half baked state
3759		 *  for PARSE Meinberg DCF77 clocks this is bad news (clock running
3760		 *  without timecode confirmation)
3761		 *  PZF 535 has also no time confirmation, but the phase should be
3762		 *  very precise as the PZF signal can be decoded
3763		 */
3764
3765		if (PARSE_SYNC(parsetime->parse_state))
3766		{
3767			/*
3768			 * currently completely synchronized - best possible state
3769			 */
3770			parse->lastsync = current_time;
3771			clear_err(parse, ERR_BADSTATUS);
3772		}
3773		else
3774		{
3775			/*
3776			 * we have had some problems receiving the time code
3777			 */
3778			parse_event(parse, CEVNT_PROP);
3779			NLOG(NLOG_CLOCKSTATUS)
3780				ERR(ERR_BADSTATUS)
3781				msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3782					CLK_UNIT(parse->peer));
3783		}
3784	}
3785
3786	fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3787
3788	if (PARSE_TIMECODE(parsetime->parse_state))
3789	{
3790		rectime = parsetime->parse_stime.fp;
3791		off = reftime = parsetime->parse_time.fp;
3792
3793		L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
3794
3795#ifdef DEBUG
3796		if (debug > 3)
3797			printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3798			       CLK_UNIT(parse->peer),
3799			       prettydate(&reftime),
3800			       prettydate(&rectime),
3801			       lfptoa(&off,6));
3802#endif
3803	}
3804
3805	if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3806	{
3807		l_fp offset;
3808		double ppsphaseadjust = parse->ppsphaseadjust;
3809
3810#ifdef HAVE_PPSAPI
3811		/*
3812		 * set fudge = 0.0 if already included in PPS time stamps
3813		 */
3814		if (parse->ppsparams.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3815		        {
3816			        ppsphaseadjust = 0.0;
3817			}
3818#endif
3819
3820		/*
3821		 * we have a PPS signal - much better than the RS232 stuff (we hope)
3822		 */
3823		offset = parsetime->parse_ptime.fp;
3824
3825#ifdef DEBUG
3826		if (debug > 3)
3827			printf("PARSE receiver #%d: PPStime %s\n",
3828				CLK_UNIT(parse->peer),
3829				prettydate(&offset));
3830#endif
3831		if (PARSE_TIMECODE(parsetime->parse_state))
3832		{
3833			if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
3834			    M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
3835			{
3836				fudge = ppsphaseadjust; /* pick PPS fudge factor */
3837
3838				/*
3839				 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
3840				 */
3841
3842				if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
3843				{
3844					reftime = off = offset;
3845					if (reftime.l_uf & (unsigned)0x80000000)
3846						reftime.l_ui++;
3847					reftime.l_uf = 0;
3848
3849
3850					/*
3851					 * implied on second offset
3852					 */
3853					off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3854					off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3855				}
3856				else
3857				{
3858					/*
3859					 * time code describes pulse
3860					 */
3861					reftime = off = parsetime->parse_time.fp;
3862
3863					L_SUB(&off, &offset); /* true offset */
3864				}
3865			}
3866			/*
3867			 * take RS232 offset when PPS when out of bounds
3868			 */
3869		}
3870		else
3871		{
3872			fudge = ppsphaseadjust; /* pick PPS fudge factor */
3873			/*
3874			 * Well, no time code to guide us - assume on second pulse
3875			 * and pray, that we are within [-0.5..0.5[
3876			 */
3877			off = offset;
3878			reftime = offset;
3879			if (reftime.l_uf & (unsigned)0x80000000)
3880				reftime.l_ui++;
3881			reftime.l_uf = 0;
3882			/*
3883			 * implied on second offset
3884			 */
3885			off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3886			off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3887		}
3888	}
3889	else
3890	{
3891		if (!PARSE_TIMECODE(parsetime->parse_state))
3892		{
3893			/*
3894			 * Well, no PPS, no TIMECODE, no more work ...
3895			 */
3896			if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3897			    parse->parse_type->cl_message)
3898				parse->parse_type->cl_message(parse, parsetime);
3899			return;
3900		}
3901	}
3902
3903#ifdef DEBUG
3904	if (debug > 3)
3905		printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
3906			CLK_UNIT(parse->peer),
3907			prettydate(&reftime),
3908			prettydate(&rectime),
3909			lfptoa(&off,6));
3910#endif
3911
3912
3913	rectime = reftime;
3914	L_SUB(&rectime, &off);	/* just to keep the ntp interface happy */
3915
3916#ifdef DEBUG
3917	if (debug > 3)
3918		printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
3919			CLK_UNIT(parse->peer),
3920			prettydate(&reftime),
3921			prettydate(&rectime));
3922#endif
3923
3924	if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3925	    parse->parse_type->cl_message)
3926		parse->parse_type->cl_message(parse, parsetime);
3927
3928	if (PARSE_SYNC(parsetime->parse_state))
3929	{
3930		/*
3931		 * log OK status
3932		 */
3933		parse_event(parse, CEVNT_NOMINAL);
3934	}
3935
3936	clear_err(parse, ERR_BADIO);
3937	clear_err(parse, ERR_BADDATA);
3938	clear_err(parse, ERR_NODATA);
3939	clear_err(parse, ERR_INTERNAL);
3940
3941	/*
3942	 * and now stick it into the clock machine
3943	 * samples are only valid iff lastsync is not too old and
3944	 * we have seen the clock in sync at least once
3945	 * after the last time we didn't see an expected data telegram
3946	 * at startup being not in sync is also bad just like
3947	 * POWERUP state
3948	 * see the clock states section above for more reasoning
3949	 */
3950	if (((current_time - parse->lastsync) > parse->maxunsync) ||
3951	    (parse->lastsync < parse->lastmissed) ||
3952	    ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
3953	    PARSE_POWERUP(parsetime->parse_state))
3954	{
3955		parse->generic->leap = LEAP_NOTINSYNC;
3956		parse->lastsync = 0;	/* wait for full sync again */
3957	}
3958	else
3959	{
3960		if (PARSE_LEAPADD(parsetime->parse_state))
3961		{
3962			/*
3963			 * we pick this state also for time code that pass leap warnings
3964			 * without direction information (as earth is currently slowing
3965			 * down).
3966			 */
3967			parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
3968		}
3969		else
3970		    if (PARSE_LEAPDEL(parsetime->parse_state))
3971		    {
3972			    parse->generic->leap = LEAP_DELSECOND;
3973		    }
3974		    else
3975		    {
3976			    parse->generic->leap = LEAP_NOWARNING;
3977		    }
3978	}
3979
3980	if (parse->generic->leap != LEAP_NOTINSYNC)
3981	{
3982	        /*
3983		 * only good/trusted samples are interesting
3984		 */
3985#ifdef DEBUG
3986	        if (debug > 2)
3987		        {
3988			        printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
3989				       CLK_UNIT(parse->peer),
3990				       prettydate(&reftime),
3991				       prettydate(&rectime),
3992				       fudge);
3993			}
3994#endif
3995		parse->generic->lastref = reftime;
3996
3997		refclock_process_offset(parse->generic, reftime, rectime, fudge);
3998
3999		/*
4000		 * pass PPS information on to PPS clock
4001		 */
4002		if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4003		        {
4004			        (void) pps_sample(&parse->timedata.parse_ptime.fp);
4005				parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4006			}
4007	} else {
4008	        parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4009	}
4010
4011	/*
4012	 * ready, unless the machine wants a sample or
4013	 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4014	 */
4015	if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
4016	    return;
4017
4018	parse->pollneeddata = 0;
4019
4020	parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4021
4022	refclock_receive(parse->peer);
4023}
4024
4025/**===========================================================================
4026 ** special code for special clocks
4027 **/
4028
4029static void
4030mk_utcinfo(
4031	   char *t,
4032	   int wnt,
4033	   int wnlsf,
4034	   int dn,
4035	   int dtls,
4036	   int dtlsf,
4037	   int size
4038	   )
4039{
4040  l_fp leapdate;
4041  char *start = t;
4042
4043  snprintf(t, size, "current correction %d sec", dtls);
4044  t += strlen(t);
4045
4046  if (wnlsf < 990)
4047    wnlsf += 1024;
4048
4049  if (wnt < 990)
4050    wnt += 1024;
4051
4052  gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
4053
4054  if ((dtlsf != dtls) &&
4055      ((wnlsf - wnt) < 52))
4056    {
4057	    snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
4058	      dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
4059    }
4060  else
4061    {
4062	    snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
4063	      gmprettydate(&leapdate));
4064    }
4065}
4066
4067#ifdef CLOCK_MEINBERG
4068/**===========================================================================
4069 ** Meinberg GPS166/GPS167 support
4070 **/
4071
4072/*------------------------------------------------------------
4073 * gps16x_message - process GPS16x messages
4074 */
4075static void
4076gps16x_message(
4077	       struct parseunit *parse,
4078	       parsetime_t      *parsetime
4079	       )
4080{
4081	if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
4082	{
4083		GPS_MSG_HDR header;
4084		unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4085
4086#ifdef DEBUG
4087		if (debug > 2)
4088		{
4089			char msgbuffer[600];
4090
4091			mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
4092			printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4093				CLK_UNIT(parse->peer),
4094				parsetime->parse_msglen,
4095				msgbuffer);
4096		}
4097#endif
4098		get_mbg_header(&bufp, &header);
4099		if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4100		    (header.gps_len == 0 ||
4101		     (header.gps_len < sizeof(parsetime->parse_msg) &&
4102		      header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
4103		{
4104			/*
4105			 * clean message
4106			 */
4107			switch (header.gps_cmd)
4108			{
4109			case GPS_SW_REV:
4110				{
4111					char buffer[64];
4112					SW_REV gps_sw_rev;
4113
4114					get_mbg_sw_rev(&bufp, &gps_sw_rev);
4115					snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
4116						(gps_sw_rev.code >> 8) & 0xFF,
4117						gps_sw_rev.code & 0xFF,
4118						gps_sw_rev.name[0] ? " " : "",
4119						gps_sw_rev.name);
4120					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4121				}
4122			break;
4123
4124			case GPS_STAT:
4125				{
4126					static struct state
4127					{
4128						unsigned short flag; /* status flag */
4129						unsigned const char *string; /* bit name */
4130					} states[] =
4131					  {
4132						  { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
4133						  { TM_SYN_FLAG,    (const unsigned char *)"NO SYNC SIGNAL" },
4134						  { TM_NO_SYNC,     (const unsigned char *)"NO SYNC POWERUP" },
4135						  { TM_NO_POS,      (const unsigned char *)"NO POSITION" },
4136						  { 0, (const unsigned char *)"" }
4137					  };
4138					unsigned short status;
4139					struct state *s = states;
4140					char buffer[512];
4141					char *p, *b;
4142
4143					status = get_lsb_short(&bufp);
4144					snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
4145
4146					if (status)
4147					{
4148						p = b = buffer + strlen(buffer);
4149						while (s->flag)
4150						{
4151							if (status & s->flag)
4152							{
4153								if (p != b)
4154								{
4155									*p++ = ',';
4156									*p++ = ' ';
4157								}
4158
4159								strncat(p, (const char *)s->string, sizeof(buffer));
4160							}
4161							s++;
4162						}
4163
4164						*p++ = '"';
4165						*p   = '\0';
4166					}
4167					else
4168					{
4169						strncat(buffer, "<OK>\"", sizeof(buffer));
4170					}
4171
4172					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4173				}
4174			break;
4175
4176			case GPS_POS_XYZ:
4177				{
4178					XYZ xyz;
4179					char buffer[256];
4180
4181					get_mbg_xyz(&bufp, xyz);
4182					snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4183						mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
4184						mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
4185						mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4186
4187					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4188				}
4189			break;
4190
4191			case GPS_POS_LLA:
4192				{
4193					LLA lla;
4194					char buffer[256];
4195
4196					get_mbg_lla(&bufp, lla);
4197
4198					snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4199						mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4200						mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
4201						mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4202
4203					set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4204				}
4205			break;
4206
4207			case GPS_TZDL:
4208				break;
4209
4210			case GPS_PORT_PARM:
4211				break;
4212
4213			case GPS_SYNTH:
4214				break;
4215
4216			case GPS_ANT_INFO:
4217				{
4218					ANT_INFO antinfo;
4219					char buffer[512];
4220					char *p;
4221
4222					get_mbg_antinfo(&bufp, &antinfo);
4223					snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
4224					p = buffer + strlen(buffer);
4225
4226					switch (antinfo.status)
4227					{
4228					case ANT_INVALID:
4229						strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
4230						p += strlen(p);
4231						break;
4232
4233					case ANT_DISCONN:
4234						strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
4235						NLOG(NLOG_CLOCKSTATUS)
4236							ERR(ERR_BADSTATUS)
4237							msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4238								CLK_UNIT(parse->peer), p);
4239
4240						p += strlen(p);
4241						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4242						*p = '\0';
4243						break;
4244
4245					case ANT_RECONN:
4246						strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
4247						p += strlen(p);
4248						mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4249						snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
4250							(antinfo.delta_t < 0) ? '-' : '+',
4251							ABS(antinfo.delta_t) / 10000,
4252							ABS(antinfo.delta_t) % 10000);
4253						p += strlen(p);
4254						mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4255						*p = '\0';
4256						break;
4257
4258					default:
4259						snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
4260						p += strlen(p);
4261						break;
4262					}
4263
4264					strncat(p, "\"", BUFFER_SIZE(buffer, p));
4265
4266					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4267				}
4268			break;
4269
4270			case GPS_UCAP:
4271				break;
4272
4273			case GPS_CFGH:
4274				{
4275					CFGH cfgh;
4276					char buffer[512];
4277					char *p;
4278
4279					get_mbg_cfgh(&bufp, &cfgh);
4280					if (cfgh.valid)
4281					{
4282						int i;
4283
4284						p = buffer;
4285						strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
4286						p += strlen(p);
4287						mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4288						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4289						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4290
4291						p = buffer;
4292						strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
4293						p += strlen(p);
4294						mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4295						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4296						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4297
4298						p = buffer;
4299						strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
4300						p += strlen(p);
4301						mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4302						strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4303						set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4304
4305						for (i = MIN_SVNO; i < MAX_SVNO; i++)
4306						{
4307							p = buffer;
4308							snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
4309							p += strlen(p);
4310							switch (cfgh.cfg[i] & 0x7)
4311							{
4312							case 0:
4313								strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
4314								break;
4315							case 1:
4316								strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
4317								break;
4318							default:
4319								strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
4320								break;
4321							}
4322							strncat(p, "\"", BUFFER_SIZE(buffer, p));
4323							set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4324
4325							p = buffer;
4326							snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
4327							p += strlen(p);
4328							switch ((cfgh.health[i] >> 5) & 0x7 )
4329							{
4330							case 0:
4331								strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
4332								break;
4333							case 1:
4334								strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
4335								break;
4336							case 2:
4337								strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
4338								break;
4339							case 3:
4340								strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
4341								break;
4342							case 4:
4343								strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
4344								break;
4345							case 5:
4346								strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
4347								break;
4348							case 6:
4349								strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
4350								break;
4351							case 7:
4352								strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
4353								break;
4354							}
4355
4356							p += strlen(p);
4357
4358							switch (cfgh.health[i] & 0x1F)
4359							{
4360							case 0:
4361								strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
4362								break;
4363							case 0x1C:
4364								strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
4365								break;
4366							case 0x1D:
4367								strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
4368								break;
4369							case 0x1E:
4370								break;
4371							case 0x1F:
4372								strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
4373								break;
4374							default:
4375								strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
4376								break;
4377							}
4378
4379							strncat(p, "\"", sizeof(buffer));
4380							set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4381						}
4382					}
4383				}
4384			break;
4385
4386			case GPS_ALM:
4387				break;
4388
4389			case GPS_EPH:
4390				break;
4391
4392			case GPS_UTC:
4393				{
4394					UTC utc;
4395					char buffer[512];
4396					char *p;
4397
4398					p = buffer;
4399
4400					get_mbg_utc(&bufp, &utc);
4401
4402					if (utc.valid)
4403					{
4404						strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
4405						p += strlen(p);
4406						mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4407						strncat(p, "\"", BUFFER_SIZE(buffer, p));
4408					}
4409					else
4410					{
4411						strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
4412					}
4413					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4414				}
4415			break;
4416
4417			case GPS_IONO:
4418				break;
4419
4420			case GPS_ASCII_MSG:
4421				{
4422					ASCII_MSG gps_ascii_msg;
4423					char buffer[128];
4424
4425					get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4426
4427					if (gps_ascii_msg.valid)
4428						{
4429							char buffer1[128];
4430							mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4431
4432							snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
4433						}
4434					else
4435						strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
4436
4437					set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4438				}
4439
4440			break;
4441
4442			default:
4443				break;
4444			}
4445		}
4446		else
4447		{
4448			msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
4449				CLK_UNIT(parse->peer),
4450				header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4451				header.gps_len,
4452				header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
4453		}
4454	}
4455
4456	return;
4457}
4458
4459/*------------------------------------------------------------
4460 * gps16x_poll - query the reciver peridically
4461 */
4462static void
4463gps16x_poll(
4464	    struct peer *peer
4465	    )
4466{
4467	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4468
4469	static GPS_MSG_HDR sequence[] =
4470	{
4471		{ GPS_SW_REV,          0, 0, 0 },
4472		{ GPS_STAT,            0, 0, 0 },
4473		{ GPS_UTC,             0, 0, 0 },
4474		{ GPS_ASCII_MSG,       0, 0, 0 },
4475		{ GPS_ANT_INFO,        0, 0, 0 },
4476		{ GPS_CFGH,            0, 0, 0 },
4477		{ GPS_POS_XYZ,         0, 0, 0 },
4478		{ GPS_POS_LLA,         0, 0, 0 },
4479		{ (unsigned short)~0,  0, 0, 0 }
4480	};
4481
4482	int rtc;
4483	unsigned char cmd_buffer[64];
4484	unsigned char *outp = cmd_buffer;
4485	GPS_MSG_HDR *header;
4486
4487	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4488	{
4489		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4490	}
4491
4492	if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
4493		parse->localstate = 0;
4494
4495	header = sequence + parse->localstate++;
4496
4497	*outp++ = SOH;		/* start command */
4498
4499	put_mbg_header(&outp, header);
4500	outp = cmd_buffer + 1;
4501
4502	header->gps_hdr_csum = (short)mbg_csum(outp, 6);
4503	put_mbg_header(&outp, header);
4504
4505#ifdef DEBUG
4506	if (debug > 2)
4507	{
4508		char buffer[128];
4509
4510		mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4511		printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4512		       CLK_UNIT(parse->peer),
4513		       parse->localstate - 1,
4514		       (int)(outp - cmd_buffer),
4515		       buffer);
4516	}
4517#endif
4518
4519	rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4520
4521	if (rtc < 0)
4522	{
4523		ERR(ERR_BADIO)
4524			msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4525	}
4526	else
4527	if (rtc != outp - cmd_buffer)
4528	{
4529		ERR(ERR_BADIO)
4530			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));
4531	}
4532
4533	clear_err(parse, ERR_BADIO);
4534	return;
4535}
4536
4537/*--------------------------------------------------
4538 * init routine - setup timer
4539 */
4540static int
4541gps16x_poll_init(
4542	struct parseunit *parse
4543	)
4544{
4545	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4546	{
4547		parse->peer->action = gps16x_poll;
4548		gps16x_poll(parse->peer);
4549	}
4550
4551	return 0;
4552}
4553
4554#else
4555static void
4556gps16x_message(
4557	       struct parseunit *parse,
4558	       parsetime_t      *parsetime
4559	       )
4560{}
4561static int
4562gps16x_poll_init(
4563	struct parseunit *parse
4564	)
4565{
4566	return 1;
4567}
4568#endif /* CLOCK_MEINBERG */
4569
4570/**===========================================================================
4571 ** clock polling support
4572 **/
4573
4574/*--------------------------------------------------
4575 * direct poll routine
4576 */
4577static void
4578poll_dpoll(
4579	struct parseunit *parse
4580	)
4581{
4582	int rtc;
4583	const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4584	int   ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4585
4586	rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
4587	if (rtc < 0)
4588	{
4589		ERR(ERR_BADIO)
4590			msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4591	}
4592	else
4593	    if (rtc != ct)
4594	    {
4595		    ERR(ERR_BADIO)
4596			    msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4597	    }
4598	clear_err(parse, ERR_BADIO);
4599}
4600
4601/*--------------------------------------------------
4602 * periodic poll routine
4603 */
4604static void
4605poll_poll(
4606	struct peer *peer
4607	)
4608{
4609	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4610
4611	if (parse->parse_type->cl_poll)
4612		parse->parse_type->cl_poll(parse);
4613
4614	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4615	{
4616		parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4617	}
4618}
4619
4620/*--------------------------------------------------
4621 * init routine - setup timer
4622 */
4623static int
4624poll_init(
4625	struct parseunit *parse
4626	)
4627{
4628	if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4629	{
4630		parse->peer->action = poll_poll;
4631		poll_poll(parse->peer);
4632	}
4633
4634	return 0;
4635}
4636
4637/**===========================================================================
4638 ** Trimble support
4639 **/
4640
4641/*-------------------------------------------------------------
4642 * trimble TAIP init routine - setup EOL and then do poll_init.
4643 */
4644static int
4645trimbletaip_init(
4646	struct parseunit *parse
4647	)
4648{
4649#ifdef HAVE_TERMIOS
4650	struct termios tio;
4651#endif
4652#ifdef HAVE_SYSV_TTYS
4653	struct termio tio;
4654#endif
4655	/*
4656	 * configure terminal line for trimble receiver
4657	 */
4658	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4659	{
4660		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4661		return 0;
4662	}
4663	else
4664	{
4665		tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4666
4667		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4668		{
4669			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4670			return 0;
4671		}
4672	}
4673	return poll_init(parse);
4674}
4675
4676/*--------------------------------------------------
4677 * trimble TAIP event routine - reset receiver upon data format trouble
4678 */
4679static const char *taipinit[] = {
4680	">FPV00000000<",
4681	">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4682	">FTM00020001<",
4683	(char *)0
4684};
4685
4686static void
4687trimbletaip_event(
4688	struct parseunit *parse,
4689	int event
4690	)
4691{
4692	switch (event)
4693	{
4694	    case CEVNT_BADREPLY:	/* reset on garbled input */
4695	    case CEVNT_TIMEOUT:		/* reset on no input */
4696		    {
4697			    const char **iv;
4698
4699			    iv = taipinit;
4700			    while (*iv)
4701			    {
4702				    int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
4703				    if (rtc < 0)
4704				    {
4705					    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4706					    return;
4707				    }
4708				    else
4709				    {
4710					    if (rtc != strlen(*iv))
4711					    {
4712						    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4713							    CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4714						    return;
4715					    }
4716				    }
4717				    iv++;
4718			    }
4719
4720			    NLOG(NLOG_CLOCKINFO)
4721				    ERR(ERR_BADIO)
4722				    msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4723					    CLK_UNIT(parse->peer));
4724		    }
4725		    break;
4726
4727	    default:			/* ignore */
4728		break;
4729	}
4730}
4731
4732/*
4733 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4734 * It should support other Trimble receivers which use the Trimble Standard
4735 * Interface Protocol (see below).
4736 *
4737 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4738 * output, about 1 microsecond wide. The leading edge of the pulse is
4739 * coincident with the change of the GPS second. This is the same as
4740 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4741 * specifically use a feature in the data message as a timing reference, but
4742 * the SVee Six Plus does not do this. In fact there is considerable jitter
4743 * on the timing of the messages, so this driver only supports the use
4744 * of the PPS pulse for accurate timing. Where it is determined that
4745 * the offset is way off, when first starting up ntpd for example,
4746 * the timing of the data stream is used until the offset becomes low enough
4747 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4748 *
4749 * It can use either option for receiving PPS information - the 'ppsclock'
4750 * stream pushed onto the serial data interface to timestamp the Carrier
4751 * Detect interrupts, where the 1PPS connects to the CD line. This only
4752 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4753 * Config.local. The other option is to use a pulse-stretcher/level-converter
4754 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4755 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4756 * by whichever method, is handled in ntp_loopfilter.c
4757 *
4758 * The receiver uses a serial message protocol called Trimble Standard
4759 * Interface Protocol (it can support others but this driver only supports
4760 * TSIP). Messages in this protocol have the following form:
4761 *
4762 * <DLE><id> ... <data> ... <DLE><ETX>
4763 *
4764 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4765 * on transmission and compressed back to one on reception. Otherwise
4766 * the values of data bytes can be anything. The serial interface is RS-422
4767 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4768 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4769 * and double datatypes. Integers are two bytes, sent most significant first.
4770 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4771 * sign & exponent first. Doubles are IEEE754 double precision floating point
4772 * numbers (8 byte) sent sign & exponent first.
4773 * The receiver supports a large set of messages, only a small subset of
4774 * which are used here. From driver to receiver the following are used:
4775 *
4776 *  ID    Description
4777 *
4778 *  21    Request current time
4779 *  22    Mode Select
4780 *  2C    Set/Request operating parameters
4781 *  2F    Request UTC info
4782 *  35    Set/Request I/O options
4783
4784 * From receiver to driver the following are recognised:
4785 *
4786 *  ID    Description
4787 *
4788 *  41    GPS Time
4789 *  44    Satellite selection, PDOP, mode
4790 *  46    Receiver health
4791 *  4B    Machine code/status
4792 *  4C    Report operating parameters (debug only)
4793 *  4F    UTC correction data (used to get leap second warnings)
4794 *  55    I/O options (debug only)
4795 *
4796 * All others are accepted but ignored.
4797 *
4798 */
4799
4800#define PI		3.1415926535898	/* lots of sig figs */
4801#define D2R		PI/180.0
4802
4803/*-------------------------------------------------------------------
4804 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
4805 * interface to the receiver.
4806 *
4807 * CAVEAT: the sendflt, sendint routines are byte order dependend and
4808 * float implementation dependend - these must be converted to portable
4809 * versions !
4810 *
4811 * CURRENT LIMITATION: float implementation. This runs only on systems
4812 * with IEEE754 floats as native floats
4813 */
4814
4815typedef struct trimble
4816{
4817	u_long last_msg;	/* last message received */
4818	u_long last_reset;	/* last time a reset was issued */
4819	u_char qtracking;	/* query tracking status */
4820	u_long ctrack;		/* current tracking set */
4821	u_long ltrack;		/* last tracking set */
4822} trimble_t;
4823
4824union uval {
4825	u_char  bd[8];
4826	int     iv;
4827	float   fv;
4828	double  dv;
4829};
4830
4831struct txbuf
4832{
4833	short idx;			/* index to first unused byte */
4834	u_char *txt;			/* pointer to actual data buffer */
4835};
4836
4837void	sendcmd		P((struct txbuf *buf, int c));
4838void	sendbyte	P((struct txbuf *buf, int b));
4839void	sendetx		P((struct txbuf *buf, struct parseunit *parse));
4840void	sendint		P((struct txbuf *buf, int a));
4841void	sendflt		P((struct txbuf *buf, double a));
4842
4843void
4844sendcmd(
4845	struct txbuf *buf,
4846	int c
4847	)
4848{
4849	buf->txt[0] = DLE;
4850	buf->txt[1] = (u_char)c;
4851	buf->idx = 2;
4852}
4853
4854void	sendcmd		P((struct txbuf *buf, int c));
4855void	sendbyte	P((struct txbuf *buf, int b));
4856void	sendetx		P((struct txbuf *buf, struct parseunit *parse));
4857void	sendint		P((struct txbuf *buf, int a));
4858void	sendflt		P((struct txbuf *buf, double a));
4859
4860void
4861sendbyte(
4862	struct txbuf *buf,
4863	int b
4864	)
4865{
4866	if (b == DLE)
4867	    buf->txt[buf->idx++] = DLE;
4868	buf->txt[buf->idx++] = (u_char)b;
4869}
4870
4871void
4872sendetx(
4873	struct txbuf *buf,
4874	struct parseunit *parse
4875	)
4876{
4877	buf->txt[buf->idx++] = DLE;
4878	buf->txt[buf->idx++] = ETX;
4879
4880	if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
4881	{
4882		ERR(ERR_BADIO)
4883			msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4884	}
4885	else
4886	{
4887#ifdef DEBUG
4888	  if (debug > 2)
4889	  {
4890		  char buffer[256];
4891
4892		  mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
4893		  printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4894			 CLK_UNIT(parse->peer),
4895			 buf->idx, buffer);
4896	  }
4897#endif
4898		clear_err(parse, ERR_BADIO);
4899	}
4900}
4901
4902void
4903sendint(
4904	struct txbuf *buf,
4905	int a
4906	)
4907{
4908	/* send 16bit int, msbyte first */
4909	sendbyte(buf, (u_char)((a>>8) & 0xff));
4910	sendbyte(buf, (u_char)(a & 0xff));
4911}
4912
4913void
4914sendflt(
4915	struct txbuf *buf,
4916	double a
4917	)
4918{
4919	int i;
4920	union uval uval;
4921
4922	uval.fv = a;
4923#ifdef WORDS_BIGENDIAN
4924	for (i=0; i<=3; i++)
4925#else
4926	    for (i=3; i>=0; i--)
4927#endif
4928		sendbyte(buf, uval.bd[i]);
4929}
4930
4931#define TRIM_POS_OPT	0x13	/* output position with high precision */
4932#define TRIM_TIME_OPT	0x03	/* use UTC time stamps, on second */
4933
4934/*--------------------------------------------------
4935 * trimble TSIP setup routine
4936 */
4937static int
4938trimbletsip_setup(
4939		  struct parseunit *parse,
4940		  const char *reason
4941		  )
4942{
4943	u_char buffer[256];
4944	struct txbuf buf;
4945	trimble_t *t = parse->localdata;
4946
4947	if (t && t->last_reset &&
4948	    ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
4949		return 1;	/* not yet */
4950	}
4951
4952	if (t)
4953		t->last_reset = current_time;
4954
4955	buf.txt = buffer;
4956
4957	sendcmd(&buf, CMD_CVERSION);	/* request software versions */
4958	sendetx(&buf, parse);
4959
4960	sendcmd(&buf, CMD_COPERPARAM);	/* set operating parameters */
4961	sendbyte(&buf, 4);	/* static */
4962	sendflt(&buf, 5.0*D2R);	/* elevation angle mask = 10 deg XXX */
4963	sendflt(&buf, 4.0);	/* s/n ratio mask = 6 XXX */
4964	sendflt(&buf, 12.0);	/* PDOP mask = 12 */
4965	sendflt(&buf, 8.0);	/* PDOP switch level = 8 */
4966	sendetx(&buf, parse);
4967
4968	sendcmd(&buf, CMD_CMODESEL);	/* fix mode select */
4969	sendbyte(&buf, 1);	/* time transfer mode */
4970	sendetx(&buf, parse);
4971
4972	sendcmd(&buf, CMD_CMESSAGE);	/* request system message */
4973	sendetx(&buf, parse);
4974
4975	sendcmd(&buf, CMD_CSUPER);	/* superpacket fix */
4976	sendbyte(&buf, 0x2);	/* binary mode */
4977	sendetx(&buf, parse);
4978
4979	sendcmd(&buf, CMD_CIOOPTIONS);	/* set I/O options */
4980	sendbyte(&buf, TRIM_POS_OPT);	/* position output */
4981	sendbyte(&buf, 0x00);	/* no velocity output */
4982	sendbyte(&buf, TRIM_TIME_OPT);	/* UTC, compute on seconds */
4983	sendbyte(&buf, 0x00);	/* no raw measurements */
4984	sendetx(&buf, parse);
4985
4986	sendcmd(&buf, CMD_CUTCPARAM);	/* request UTC correction data */
4987	sendetx(&buf, parse);
4988
4989	NLOG(NLOG_CLOCKINFO)
4990		ERR(ERR_BADIO)
4991		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
4992
4993	return 0;
4994}
4995
4996/*--------------------------------------------------
4997 * TRIMBLE TSIP check routine
4998 */
4999static void
5000trimble_check(
5001	      struct peer *peer
5002	      )
5003{
5004	struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
5005	trimble_t *t = parse->localdata;
5006	u_char buffer[256];
5007	struct txbuf buf;
5008	buf.txt = buffer;
5009
5010	if (t)
5011	{
5012		if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
5013			(void)trimbletsip_setup(parse, "message timeout");
5014	}
5015
5016	poll_poll(parse->peer);	/* emit query string and re-arm timer */
5017
5018	if (t && t->qtracking)
5019	{
5020		u_long oldsats = t->ltrack & ~t->ctrack;
5021
5022		t->qtracking = 0;
5023		t->ltrack = t->ctrack;
5024
5025		if (oldsats)
5026		{
5027			int i;
5028
5029			for (i = 0; oldsats; i++) {
5030				if (oldsats & (1 << i))
5031					{
5032						sendcmd(&buf, CMD_CSTATTRACK);
5033						sendbyte(&buf, i+1);	/* old sat */
5034						sendetx(&buf, parse);
5035					}
5036				oldsats &= ~(1 << i);
5037			}
5038		}
5039
5040		sendcmd(&buf, CMD_CSTATTRACK);
5041		sendbyte(&buf, 0x00);	/* current tracking set */
5042		sendetx(&buf, parse);
5043	}
5044}
5045
5046/*--------------------------------------------------
5047 * TRIMBLE TSIP end routine
5048 */
5049static void
5050trimbletsip_end(
5051	      struct parseunit *parse
5052	      )
5053{	trimble_t *t = parse->localdata;
5054
5055	if (t)
5056	{
5057		free(t);
5058		parse->localdata = (void *)0;
5059	}
5060	parse->peer->nextaction = 0;
5061	parse->peer->action = (void (*) P((struct peer *)))0;
5062}
5063
5064/*--------------------------------------------------
5065 * TRIMBLE TSIP init routine
5066 */
5067static int
5068trimbletsip_init(
5069	struct parseunit *parse
5070	)
5071{
5072#if defined(VEOL) || defined(VEOL2)
5073#ifdef HAVE_TERMIOS
5074	struct termios tio;		/* NEEDED FOR A LONG TIME ! */
5075#endif
5076#ifdef HAVE_SYSV_TTYS
5077	struct termio tio;		/* NEEDED FOR A LONG TIME ! */
5078#endif
5079	/*
5080	 * allocate local data area
5081	 */
5082	if (!parse->localdata)
5083	{
5084		trimble_t *t;
5085
5086		t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5087
5088		if (t)
5089		{
5090			memset((char *)t, 0, sizeof(trimble_t));
5091			t->last_msg = current_time;
5092		}
5093	}
5094
5095	parse->peer->action     = trimble_check;
5096	parse->peer->nextaction = current_time;
5097
5098	/*
5099	 * configure terminal line for ICANON mode with VEOL characters
5100	 */
5101	if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
5102	{
5103		msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5104		return 0;
5105	}
5106	else
5107	{
5108		if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
5109		{
5110#ifdef VEOL
5111			tio.c_cc[VEOL]  = ETX;
5112#endif
5113#ifdef VEOL2
5114			tio.c_cc[VEOL2]  = DLE;
5115#endif
5116		}
5117
5118		if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
5119		{
5120			msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5121			return 0;
5122		}
5123	}
5124#endif
5125	return trimbletsip_setup(parse, "initial startup");
5126}
5127
5128/*------------------------------------------------------------
5129 * trimbletsip_event - handle Trimble events
5130 * simple evente handler - attempt to re-initialize receiver
5131 */
5132static void
5133trimbletsip_event(
5134	struct parseunit *parse,
5135	int event
5136	)
5137{
5138	switch (event)
5139	{
5140	    case CEVNT_BADREPLY:	/* reset on garbled input */
5141	    case CEVNT_TIMEOUT:		/* reset on no input */
5142		    (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
5143		    break;
5144
5145	    default:			/* ignore */
5146		break;
5147	}
5148}
5149
5150/*
5151 * getflt, getint convert fields in the incoming data into the
5152 * appropriate type of item
5153 *
5154 * CAVEAT: these routines are currently definitely byte order dependent
5155 * and assume Representation(float) == IEEE754
5156 * These functions MUST be converted to portable versions (especially
5157 * converting the float representation into ntp_fp formats in order
5158 * to avoid floating point operations at all!
5159 */
5160
5161static float
5162getflt(
5163	u_char *bp
5164	)
5165{
5166	union uval uval;
5167
5168#ifdef WORDS_BIGENDIAN
5169	uval.bd[0] = *bp++;
5170	uval.bd[1] = *bp++;
5171	uval.bd[2] = *bp++;
5172	uval.bd[3] = *bp;
5173#else  /* ! WORDS_BIGENDIAN */
5174	uval.bd[3] = *bp++;
5175	uval.bd[2] = *bp++;
5176	uval.bd[1] = *bp++;
5177	uval.bd[0] = *bp;
5178#endif /* ! WORDS_BIGENDIAN */
5179	return uval.fv;
5180}
5181
5182static double
5183getdbl(
5184	u_char *bp
5185	)
5186{
5187	union uval uval;
5188
5189#ifdef WORDS_BIGENDIAN
5190	uval.bd[0] = *bp++;
5191	uval.bd[1] = *bp++;
5192	uval.bd[2] = *bp++;
5193	uval.bd[3] = *bp++;
5194	uval.bd[4] = *bp++;
5195	uval.bd[5] = *bp++;
5196	uval.bd[6] = *bp++;
5197	uval.bd[7] = *bp;
5198#else  /* ! WORDS_BIGENDIAN */
5199	uval.bd[7] = *bp++;
5200	uval.bd[6] = *bp++;
5201	uval.bd[5] = *bp++;
5202	uval.bd[4] = *bp++;
5203	uval.bd[3] = *bp++;
5204	uval.bd[2] = *bp++;
5205	uval.bd[1] = *bp++;
5206	uval.bd[0] = *bp;
5207#endif /* ! WORDS_BIGENDIAN */
5208	return uval.dv;
5209}
5210
5211static int
5212getshort(
5213	 unsigned char *p
5214	 )
5215{
5216	return get_msb_short(&p);
5217}
5218
5219/*--------------------------------------------------
5220 * trimbletsip_message - process trimble messages
5221 */
5222#define RTOD (180.0 / 3.1415926535898)
5223#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5224
5225static void
5226trimbletsip_message(
5227		    struct parseunit *parse,
5228		    parsetime_t      *parsetime
5229		    )
5230{
5231	unsigned char *buffer = parsetime->parse_msg;
5232	unsigned int   size   = parsetime->parse_msglen;
5233
5234	if ((size < 4) ||
5235	    (buffer[0]      != DLE) ||
5236	    (buffer[size-1] != ETX) ||
5237	    (buffer[size-2] != DLE))
5238	{
5239#ifdef DEBUG
5240		if (debug > 2) {
5241			int i;
5242
5243			printf("TRIMBLE BAD packet, size %d:\n	", size);
5244			for (i = 0; i < size; i++) {
5245				printf ("%2.2x, ", buffer[i]&0xff);
5246				if (i%16 == 15) printf("\n\t");
5247			}
5248			printf("\n");
5249		}
5250#endif
5251		return;
5252	}
5253	else
5254	{
5255		int var_flag;
5256		trimble_t *tr = parse->localdata;
5257		unsigned int cmd = buffer[1];
5258		char pbuffer[200];
5259		char *t = pbuffer;
5260		cmd_info_t *s;
5261
5262#ifdef DEBUG
5263		if (debug > 3) {
5264			int i;
5265
5266			printf("TRIMBLE packet 0x%02x, size %d:\n	", cmd, size);
5267			for (i = 0; i < size; i++) {
5268				printf ("%2.2x, ", buffer[i]&0xff);
5269				if (i%16 == 15) printf("\n\t");
5270			}
5271			printf("\n");
5272		}
5273#endif
5274
5275		if (tr)
5276			tr->last_msg = current_time;
5277
5278		s = trimble_convert(cmd, trimble_rcmds);
5279
5280		if (s)
5281		{
5282			snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
5283		}
5284		else
5285		{
5286			DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
5287			return;
5288		}
5289
5290		var_flag = s->varmode;
5291
5292		t += strlen(t);
5293
5294		switch(cmd)
5295		{
5296		case CMD_RCURTIME:
5297			snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
5298				 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5299				 getflt((unsigned char *)&mb(6)));
5300			break;
5301
5302		case CMD_RBEST4:
5303			strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5304			t += strlen(t);
5305			switch (mb(0) & 0xF)
5306			{
5307			default:
5308				snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5309				break;
5310
5311			case 1:
5312				strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
5313				break;
5314
5315			case 3:
5316				strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5317				break;
5318
5319			case 4:
5320				strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5321				break;
5322			}
5323			t += strlen(t);
5324			if (mb(0) & 0x10)
5325				strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5326			else
5327				strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5328			t += strlen(t);
5329
5330			snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5331				mb(1), mb(2), mb(3), mb(4),
5332				getflt((unsigned char *)&mb(5)),
5333				getflt((unsigned char *)&mb(9)),
5334				getflt((unsigned char *)&mb(13)),
5335				getflt((unsigned char *)&mb(17)));
5336
5337			break;
5338
5339		case CMD_RVERSION:
5340			snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
5341				mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5342			break;
5343
5344		case CMD_RRECVHEALTH:
5345		{
5346			static const char *msgs[] =
5347			{
5348				"Battery backup failed",
5349				"Signal processor error",
5350				"Alignment error, channel or chip 1",
5351				"Alignment error, channel or chip 2",
5352				"Antenna feed line fault",
5353				"Excessive ref freq. error",
5354				"<BIT 6>",
5355				"<BIT 7>"
5356			};
5357
5358			int i, bits;
5359
5360			switch (mb(0) & 0xFF)
5361			{
5362			default:
5363				snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
5364				break;
5365			case 0x00:
5366				strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
5367				break;
5368			case 0x01:
5369				strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
5370				break;
5371			case 0x03:
5372				strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
5373				break;
5374			case 0x08:
5375				strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
5376				break;
5377			case 0x09:
5378				strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
5379				break;
5380			case 0x0A:
5381				strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
5382				break;
5383			case 0x0B:
5384				strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
5385				break;
5386			case 0x0C:
5387				strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
5388				break;
5389			}
5390
5391			t += strlen(t);
5392
5393			bits = mb(1) & 0xFF;
5394
5395			for (i = 0; i < 8; i++)
5396				if (bits & (0x1<<i))
5397				{
5398					snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5399					t += strlen(t);
5400				}
5401		}
5402		break;
5403
5404		case CMD_RMESSAGE:
5405			mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
5406			break;
5407
5408		case CMD_RMACHSTAT:
5409		{
5410			static const char *msgs[] =
5411			{
5412				"Synthesizer Fault",
5413				"Battery Powered Time Clock Fault",
5414				"A-to-D Converter Fault",
5415				"The almanac stored in the receiver is not complete and current",
5416				"<BIT 4>",
5417				"<BIT 5",
5418				"<BIT 6>",
5419				"<BIT 7>"
5420			};
5421
5422			int i, bits;
5423
5424			snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
5425			t += strlen(t);
5426
5427			bits = mb(1) & 0xFF;
5428
5429			for (i = 0; i < 8; i++)
5430				if (bits & (0x1<<i))
5431				{
5432					snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5433					t += strlen(t);
5434				}
5435
5436			snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5437		}
5438		break;
5439
5440		case CMD_ROPERPARAM:
5441			snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
5442				mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5443				getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5444			break;
5445
5446		case CMD_RUTCPARAM:
5447		{
5448			float t0t = getflt((unsigned char *)&mb(14));
5449			short wnt = getshort((unsigned char *)&mb(18));
5450			short dtls = getshort((unsigned char *)&mb(12));
5451			short wnlsf = getshort((unsigned char *)&mb(20));
5452			short dn = getshort((unsigned char *)&mb(22));
5453			short dtlsf = getshort((unsigned char *)&mb(24));
5454
5455			if ((int)t0t != 0)
5456			  {
5457				  mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5458			  }
5459			else
5460			  {
5461			    strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
5462			  }
5463		}
5464		break;
5465
5466		case CMD_RSAT1BIAS:
5467			snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
5468				getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5469			break;
5470
5471		case CMD_RIOOPTIONS:
5472		{
5473			snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
5474				mb(0), mb(1), mb(2), mb(3));
5475			if (mb(0) != TRIM_POS_OPT ||
5476			    mb(2) != TRIM_TIME_OPT)
5477			{
5478				(void)trimbletsip_setup(parse, "bad io options");
5479			}
5480		}
5481		break;
5482
5483		case CMD_RSPOSXYZ:
5484		{
5485			double x = getflt((unsigned char *)&mb(0));
5486			double y = getflt((unsigned char *)&mb(4));
5487			double z = getflt((unsigned char *)&mb(8));
5488			double f = getflt((unsigned char *)&mb(12));
5489
5490			if (f > 0.0)
5491			  snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5492				  x, y, z,
5493				  f);
5494			else
5495			  return;
5496		}
5497		break;
5498
5499		case CMD_RSLLAPOS:
5500		{
5501			double lat = getflt((unsigned char *)&mb(0));
5502			double lng = getflt((unsigned char *)&mb(4));
5503			double f   = getflt((unsigned char *)&mb(12));
5504
5505			if (f > 0.0)
5506			  snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
5507				  ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5508				  ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5509				  getflt((unsigned char *)&mb(8)));
5510			else
5511			  return;
5512		}
5513		break;
5514
5515		case CMD_RDOUBLEXYZ:
5516		{
5517			double x = getdbl((unsigned char *)&mb(0));
5518			double y = getdbl((unsigned char *)&mb(8));
5519			double z = getdbl((unsigned char *)&mb(16));
5520			snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
5521				x, y, z);
5522		}
5523		break;
5524
5525		case CMD_RDOUBLELLA:
5526		{
5527			double lat = getdbl((unsigned char *)&mb(0));
5528			double lng = getdbl((unsigned char *)&mb(8));
5529			snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
5530				((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5531				((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5532				getdbl((unsigned char *)&mb(16)));
5533		}
5534		break;
5535
5536		case CMD_RALLINVIEW:
5537		{
5538			int i, sats;
5539
5540			strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5541			t += strlen(t);
5542			switch (mb(0) & 0x7)
5543			{
5544			default:
5545				snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5546				break;
5547
5548			case 3:
5549				strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5550				break;
5551
5552			case 4:
5553				strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5554				break;
5555			}
5556			t += strlen(t);
5557			if (mb(0) & 0x8)
5558				strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5559			else
5560				strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5561			t += strlen(t);
5562
5563			sats = (mb(0)>>4) & 0xF;
5564
5565			snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5566				getflt((unsigned char *)&mb(1)),
5567				getflt((unsigned char *)&mb(5)),
5568				getflt((unsigned char *)&mb(9)),
5569				getflt((unsigned char *)&mb(13)),
5570				sats, (sats == 1) ? "" : "s");
5571			t += strlen(t);
5572
5573			for (i=0; i < sats; i++)
5574			{
5575				snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
5576				t += strlen(t);
5577				if (tr)
5578					tr->ctrack |= (1 << (mb(17+i)-1));
5579			}
5580
5581			if (tr)
5582                        { /* mark for tracking status query */
5583				tr->qtracking = 1;
5584			}
5585		}
5586		break;
5587
5588		case CMD_RSTATTRACK:
5589		{
5590			snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */
5591			t += strlen(t);
5592
5593			if (getflt((unsigned char *)&mb(4)) < 0.0)
5594			{
5595				strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
5596				var_flag &= ~DEF;
5597			}
5598			else
5599			{
5600				snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5601					(mb(1) & 0xFF)>>3,
5602					mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5603					mb(3),
5604					getflt((unsigned char *)&mb(4)),
5605					getflt((unsigned char *)&mb(12)) * RTOD,
5606					getflt((unsigned char *)&mb(16)) * RTOD);
5607				t += strlen(t);
5608				if (mb(20))
5609				{
5610					var_flag &= ~DEF;
5611					strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
5612				}
5613				t += strlen(t);
5614				if (mb(22))
5615				{
5616					if (mb(22) == 1)
5617						strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
5618					else
5619						if (mb(22) == 2)
5620							strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
5621				}
5622				t += strlen(t);
5623				if (mb(23))
5624					strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
5625			}
5626		}
5627		break;
5628
5629		default:
5630			strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
5631			break;
5632		}
5633		t += strlen(t);
5634
5635		strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
5636		set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5637	}
5638}
5639
5640
5641/**============================================================
5642 ** RAWDCF support
5643 **/
5644
5645/*--------------------------------------------------
5646 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5647 * SET DTR line
5648 */
5649#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5650static int
5651rawdcf_init_1(
5652	struct parseunit *parse
5653	)
5654{
5655	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5656	/*
5657	 * You can use the RS232 to supply the power for a DCF77 receiver.
5658	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5659	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5660	 */
5661	int sl232;
5662
5663	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5664	{
5665		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5666		return 0;
5667	}
5668
5669#ifdef TIOCM_DTR
5670	sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5671#else
5672	sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;	/* turn on DTR, clear RTS for power supply */
5673#endif
5674
5675	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5676	{
5677		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5678	}
5679	return 0;
5680}
5681#else
5682static int
5683rawdcfdtr_init_1(
5684	struct parseunit *parse
5685	)
5686{
5687	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5688	return 0;
5689}
5690#endif  /* DTR initialisation type */
5691
5692/*--------------------------------------------------
5693 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5694 * CLR DTR line, SET RTS line
5695 */
5696#if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5697static int
5698rawdcf_init_2(
5699	struct parseunit *parse
5700	)
5701{
5702	/* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5703	/*
5704	 * You can use the RS232 to supply the power for a DCF77 receiver.
5705	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5706	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5707	 */
5708	int sl232;
5709
5710	if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5711	{
5712		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5713		return 0;
5714	}
5715
5716#ifdef TIOCM_RTS
5717	sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5718#else
5719	sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;	/* turn on RTS, clear DTR for power supply */
5720#endif
5721
5722	if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5723	{
5724		msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5725	}
5726	return 0;
5727}
5728#else
5729static int
5730rawdcf_init_2(
5731	struct parseunit *parse
5732	)
5733{
5734	msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5735	return 0;
5736}
5737#endif  /* DTR initialisation type */
5738
5739#else	/* defined(REFCLOCK) && defined(PARSE) */
5740int refclock_parse_bs;
5741#endif	/* defined(REFCLOCK) && defined(PARSE) */
5742
5743/*
5744 * History:
5745 *
5746 * refclock_parse.c,v
5747 * Revision 4.80  2007/08/11 12:06:29  kardel
5748 * update comments wrt/ to PPS
5749 *
5750 * Revision 4.79  2007/08/11 11:52:23  kardel
5751 * - terminate io bindings before io_closeclock() will close our file descriptor
5752 *
5753 * Revision 4.78  2006/12/22 20:08:27  kardel
5754 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5755 *
5756 * Revision 4.77  2006/08/05 07:44:49  kardel
5757 * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5758 *
5759 * Revision 4.76  2006/06/22 18:40:47  kardel
5760 * clean up signedness (gcc 4)
5761 *
5762 * Revision 4.75  2006/06/22 16:58:10  kardel
5763 * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5764 * the PPS offset. Fix sign of offset passed to kernel.
5765 *
5766 * Revision 4.74  2006/06/18 21:18:37  kardel
5767 * NetBSD Coverity CID 3796: possible NULL deref
5768 *
5769 * Revision 4.73  2006/05/26 14:23:46  kardel
5770 * cleanup of copyright info
5771 *
5772 * Revision 4.72  2006/05/26 14:19:43  kardel
5773 * cleanup of ioctl cruft
5774 *
5775 * Revision 4.71  2006/05/26 14:15:57  kardel
5776 * delay adding refclock to async refclock io after all initializations
5777 *
5778 * Revision 4.70  2006/05/25 18:20:50  kardel
5779 * bug #619
5780 * terminate parse io engine after de-registering
5781 * from refclock io engine
5782 *
5783 * Revision 4.69  2006/05/25 17:28:02  kardel
5784 * complete refclock io structure initialization *before* inserting it into the
5785 * refclock input machine (avoids null pointer deref) (bug #619)
5786 *
5787 * Revision 4.68  2006/05/01 17:02:51  kardel
5788 * copy receiver method also for newlwy created receive buffers
5789 *
5790 * Revision 4.67  2006/05/01 14:37:29  kardel
5791 * If an input buffer parses into more than one message do insert the
5792 * parsed message in a new input buffer instead of processing it
5793 * directly. This avoids deed complicated processing in signal
5794 * handling.
5795 *
5796 * Revision 4.66  2006/03/18 00:45:30  kardel
5797 * coverity fixes found in NetBSD coverity scan
5798 *
5799 * Revision 4.65  2006/01/26 06:08:33  kardel
5800 * output errno on PPS setup failure
5801 *
5802 * Revision 4.64  2005/11/09 20:44:47  kardel
5803 * utilize full PPS timestamp resolution from PPS API
5804 *
5805 * Revision 4.63  2005/10/07 22:10:25  kardel
5806 * bounded buffer implementation
5807 *
5808 * Revision 4.62.2.2  2005/09/25 10:20:16  kardel
5809 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5810 * replace almost all str* and *printf functions be their buffer bounded
5811 * counterparts
5812 *
5813 * Revision 4.62.2.1  2005/08/27 16:19:27  kardel
5814 * limit re-set rate of trimble clocks
5815 *
5816 * Revision 4.62  2005/08/06 17:40:00  kardel
5817 * cleanup size handling wrt/ to buffer boundaries
5818 *
5819 * Revision 4.61  2005/07/27 21:16:19  kardel
5820 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5821 * default setup. CSTOPB was missing for the 7E2 default data format of
5822 * the DCF77 clocks.
5823 *
5824 * Revision 4.60  2005/07/17 21:14:44  kardel
5825 * change contents of version string to include the RCS/CVS Id
5826 *
5827 * Revision 4.59  2005/07/06 06:56:38  kardel
5828 * syntax error
5829 *
5830 * Revision 4.58  2005/07/04 13:10:40  kardel
5831 * fix bug 455: tripping over NULL pointer on cleanup
5832 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5833 * fix compiler warnings for some platforms wrt/ printf formatstrings and
5834 *     varying structure element sizes
5835 * reorder assignment in binding to avoid tripping over NULL pointers
5836 *
5837 * Revision 4.57  2005/06/25 09:25:19  kardel
5838 * sort out log output sequence
5839 *
5840 * Revision 4.56  2005/06/14 21:47:27  kardel
5841 * collect samples only if samples are ok (sync or trusted flywheel)
5842 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
5843 * en- and dis-able HARDPPS in correlation to receiver sync state
5844 *
5845 * Revision 4.55  2005/06/02 21:28:31  kardel
5846 * clarify trust logic
5847 *
5848 * Revision 4.54  2005/06/02 17:06:49  kardel
5849 * change status reporting to use fixed refclock_report()
5850 *
5851 * Revision 4.53  2005/06/02 16:33:31  kardel
5852 * fix acceptance of clocks unsync clocks right at start
5853 *
5854 * Revision 4.52  2005/05/26 21:55:06  kardel
5855 * cleanup status reporting
5856 *
5857 * Revision 4.51  2005/05/26 19:19:14  kardel
5858 * implement fast refclock startup
5859 *
5860 * Revision 4.50  2005/04/16 20:51:35  kardel
5861 * set pps_enable = 1 when binding a kernel PPS source
5862 *
5863 * Revision 4.49  2005/04/16 17:29:26  kardel
5864 * add non polling clock type 18 for just listenning to Meinberg clocks
5865 *
5866 * Revision 4.48  2005/04/16 16:22:27  kardel
5867 * bk sync 20050415 ntp-dev
5868 *
5869 * Revision 4.47  2004/11/29 10:42:48  kardel
5870 * bk sync ntp-dev 20041129
5871 *
5872 * Revision 4.46  2004/11/29 10:26:29  kardel
5873 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
5874 *
5875 * Revision 4.45  2004/11/14 20:53:20  kardel
5876 * clear PPS flags after using them
5877 *
5878 * Revision 4.44  2004/11/14 15:29:41  kardel
5879 * support PPSAPI, upgrade Copyright to Berkeley style
5880 *
5881 * Revision 4.43  2001/05/26 22:53:16  kardel
5882 * 20010526 reconcilation
5883 *
5884 * Revision 4.42  2000/05/14 15:31:51  kardel
5885 * PPSAPI && RAWDCF modemline support
5886 *
5887 * Revision 4.41  2000/04/09 19:50:45  kardel
5888 * fixed rawdcfdtr_init() -> rawdcf_init_1
5889 *
5890 * Revision 4.40  2000/04/09 15:27:55  kardel
5891 * modem line fiddle in rawdcf_init_2
5892 *
5893 * Revision 4.39  2000/03/18 09:16:55  kardel
5894 * PPSAPI integration
5895 *
5896 * Revision 4.38  2000/03/05 20:25:06  kardel
5897 * support PPSAPI
5898 *
5899 * Revision 4.37  2000/03/05 20:11:14  kardel
5900 * 4.0.99g reconcilation
5901 *
5902 * Revision 4.36  1999/11/28 17:18:20  kardel
5903 * disabled burst mode
5904 *
5905 * Revision 4.35  1999/11/28 09:14:14  kardel
5906 * RECON_4_0_98F
5907 *
5908 * Revision 4.34  1999/05/14 06:08:05  kardel
5909 * store current_time in a suitable container (u_long)
5910 *
5911 * Revision 4.33  1999/05/13 21:48:38  kardel
5912 * double the no response timeout interval
5913 *
5914 * Revision 4.32  1999/05/13 20:09:13  kardel
5915 * complain only about missing polls after a full poll interval
5916 *
5917 * Revision 4.31  1999/05/13 19:59:32  kardel
5918 * add clock type 16 for RTS set DTR clr in RAWDCF
5919 *
5920 * Revision 4.30  1999/02/28 20:36:43  kardel
5921 * fixed printf fmt
5922 *
5923 * Revision 4.29  1999/02/28 19:58:23  kardel
5924 * updated copyright information
5925 *
5926 * Revision 4.28  1999/02/28 19:01:50  kardel
5927 * improved debug out on sent Meinberg messages
5928 *
5929 * Revision 4.27  1999/02/28 18:05:55  kardel
5930 * no linux/ppsclock.h stuff
5931 *
5932 * Revision 4.26  1999/02/28 15:27:27  kardel
5933 * wharton clock integration
5934 *
5935 * Revision 4.25  1999/02/28 14:04:46  kardel
5936 * added missing double quotes to UTC information string
5937 *
5938 * Revision 4.24  1999/02/28 12:06:50  kardel
5939 * (parse_control): using gmprettydate instead of prettydate()
5940 * (mk_utcinfo): new function for formatting GPS derived UTC information
5941 * (gps16x_message): changed to use mk_utcinfo()
5942 * (trimbletsip_message): changed to use mk_utcinfo()
5943 * ignoring position information in unsynchronized mode
5944 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5945 *
5946 * Revision 4.23  1999/02/23 19:47:53  kardel
5947 * fixed #endifs
5948 * (stream_receive): fixed formats
5949 *
5950 * Revision 4.22  1999/02/22 06:21:02  kardel
5951 * use new autoconfig symbols
5952 *
5953 * Revision 4.21  1999/02/21 12:18:13  kardel
5954 * 4.91f reconcilation
5955 *
5956 * Revision 4.20  1999/02/21 10:53:36  kardel
5957 * initial Linux PPSkit version
5958 *
5959 * Revision 4.19  1999/02/07 09:10:45  kardel
5960 * clarify STREAMS mitigation rules in comment
5961 *
5962 * Revision 4.18  1998/12/20 23:45:34  kardel
5963 * fix types and warnings
5964 *
5965 * Revision 4.17  1998/11/15 21:24:51  kardel
5966 * cannot access mbg_ routines when CLOCK_MEINBERG
5967 * is not defined
5968 *
5969 * Revision 4.16  1998/11/15 20:28:17  kardel
5970 * Release 4.0.73e13 reconcilation
5971 *
5972 * Revision 4.15  1998/08/22 21:56:08  kardel
5973 * fixed IO handling for non-STREAM IO
5974 *
5975 * Revision 4.14  1998/08/16 19:00:48  kardel
5976 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5977 * made uval a local variable (killed one of the last globals)
5978 * (sendetx): added logging of messages when in debug mode
5979 * (trimble_check): added periodic checks to facilitate re-initialization
5980 * (trimbletsip_init): made use of EOL character if in non-kernel operation
5981 * (trimbletsip_message): extended message interpretation
5982 * (getdbl): fixed data conversion
5983 *
5984 * Revision 4.13  1998/08/09 22:29:13  kardel
5985 * Trimble TSIP support
5986 *
5987 * Revision 4.12  1998/07/11 10:05:34  kardel
5988 * Release 4.0.73d reconcilation
5989 *
5990 * Revision 4.11  1998/06/14 21:09:42  kardel
5991 * Sun acc cleanup
5992 *
5993 * Revision 4.10  1998/06/13 12:36:45  kardel
5994 * signed/unsigned, name clashes
5995 *
5996 * Revision 4.9  1998/06/12 15:30:00  kardel
5997 * prototype fixes
5998 *
5999 * Revision 4.8  1998/06/12 11:19:42  kardel
6000 * added direct input processing routine for refclocks in
6001 * order to avaiod that single character io gobbles up all
6002 * receive buffers and drops input data. (Problem started
6003 * with fast machines so a character a buffer was possible
6004 * one of the few cases where faster machines break existing
6005 * allocation algorithms)
6006 *
6007 * Revision 4.7  1998/06/06 18:35:20  kardel
6008 * (parse_start): added BURST mode initialisation
6009 *
6010 * Revision 4.6  1998/05/27 06:12:46  kardel
6011 * RAWDCF_BASEDELAY default added
6012 * old comment removed
6013 * casts for ioctl()
6014 *
6015 * Revision 4.5  1998/05/25 22:05:09  kardel
6016 * RAWDCF_SETDTR option removed
6017 * clock type 14 attempts to set DTR for
6018 * power supply of RAWDCF receivers
6019 *
6020 * Revision 4.4  1998/05/24 16:20:47  kardel
6021 * updated comments referencing Meinberg clocks
6022 * added RAWDCF clock with DTR set option as type 14
6023 *
6024 * Revision 4.3  1998/05/24 10:48:33  kardel
6025 * calibrated CONRAD RAWDCF default fudge factor
6026 *
6027 * Revision 4.2  1998/05/24 09:59:35  kardel
6028 * corrected version information (ntpq support)
6029 *
6030 * Revision 4.1  1998/05/24 09:52:31  kardel
6031 * use fixed format only (new IO model)
6032 * output debug to stdout instead of msyslog()
6033 * don't include >"< in ASCII output in order not to confuse
6034 * ntpq parsing
6035 *
6036 * Revision 4.0  1998/04/10 19:52:11  kardel
6037 * Start 4.0 release version numbering
6038 *
6039 * Revision 1.2  1998/04/10 19:28:04  kardel
6040 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6041 * derived from 3.105.1.2 from V3 tree
6042 *
6043 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
6044 *
6045 */
6046