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