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