xref: /freebsd/contrib/ntp/ntpd/refclock_parse.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
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 
137 static 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 
143 static	void	parse_init	P((void));
144 static	int	parse_start	P((int, struct peer *));
145 static	void	parse_shutdown	P((int, struct peer *));
146 static	void	parse_poll	P((int, struct peer *));
147 static	void	parse_control	P((int, struct refclockstat *, struct refclockstat *, struct peer *));
148 
149 #define	parse_buginfo	noentry
150 
151 struct	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 
174 struct parseunit;		/* to keep inquiring minds happy */
175 
176 typedef 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 
234 struct errorregression
235 {
236 	u_long err_count;	/* number of repititions per class */
237 	u_long err_delay;	/* minimum delay between messages */
238 };
239 
240 static struct errorregression
241 err_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 
249 static struct errorregression
250 err_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 
258 static struct errorregression
259 err_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 
267 static struct errorregression
268 err_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 
276 static struct errorregression
277 err_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 
285 static struct errorregression
286 err_internal[] =		/* really bad things - basically coding/OS errors */
287 {
288 	{ 0,       0 },		/* output all messages immediately */
289 };
290 
291 static struct errorregression *
292 err_tbl[] =
293 {
294 	err_baddata,
295 	err_nodata,
296 	err_badio,
297 	err_badstatus,
298 	err_badevent,
299 	err_internal
300 };
301 
302 struct 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 
315 struct 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 
363 static	void	poll_dpoll	P((struct parseunit *));
364 static	void	poll_poll	P((struct peer *));
365 static	int	poll_init	P((struct parseunit *));
366 
367 typedef 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  */
476 static	void	gps16x_message	 P((struct parseunit *, parsetime_t *));
477 static  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 
495 static 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 
537 static 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  */
612 static	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  */
620 static	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 
634 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
635 static	int	trimbletaip_init	P((struct parseunit *));
636 static	void	trimbletaip_event	P((struct parseunit *, int));
637 
638 /* query time & UTC correction data */
639 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
640 
641 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
642 static	int	trimbletsip_init	P((struct parseunit *));
643 static	void	trimbletsip_end   	P((struct parseunit *));
644 static	void	trimbletsip_message	P((struct parseunit *, parsetime_t *));
645 static	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 
713 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
714 #define RCC8000_FLAGS		0
715 #define RCC8000_POLL            poll_dpoll
716 #define RCC8000_INIT            poll_init
717 #define RCC8000_END             0
718 #define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
719 #define RCC8000_ROOTDELAY       0.0
720 #define RCC8000_BASEDELAY       0.0
721 #define RCC8000_ID              "MSF"
722 #define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
723 #define RCC8000_FORMAT          "Radiocode RCC8000"
724 #define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
725 #define RCC8000_SPEED		(B2400)
726 #define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
727 #define RCC8000_IFLAG           (IGNBRK|IGNPAR)
728 #define RCC8000_OFLAG           0
729 #define RCC8000_LFLAG           0
730 #define RCC8000_SAMPLES         5
731 #define RCC8000_KEEP	        3
732 
733 /*
734  * Hopf Radio clock 6021 Format
735  *
736  */
737 #define HOPF6021_ROOTDELAY	0.0
738 #define HOPF6021_BASEDELAY	0.0
739 #define HOPF6021_DESCRIPTION	"HOPF 6021"
740 #define HOPF6021_FORMAT         "hopf Funkuhr 6021"
741 #define HOPF6021_MAXUNSYNC	(60*60)  /* should be ok for an hour */
742 #define HOPF6021_SPEED         (B9600)
743 #define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
744 #define HOPF6021_IFLAG		(IGNBRK|ISTRIP)
745 #define HOPF6021_OFLAG		0
746 #define HOPF6021_LFLAG		0
747 #define HOPF6021_FLAGS          0
748 #define HOPF6021_SAMPLES        5
749 #define HOPF6021_KEEP	        3
750 
751 /*
752  * Diem's Computime Radio Clock Receiver
753  */
754 #define COMPUTIME_FLAGS       0
755 #define COMPUTIME_ROOTDELAY   0.0
756 #define COMPUTIME_BASEDELAY   0.0
757 #define COMPUTIME_ID          DCF_ID
758 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
759 #define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
760 #define COMPUTIME_TYPE        DCF_TYPE
761 #define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
762 #define COMPUTIME_SPEED       (B9600)
763 #define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
764 #define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
765 #define COMPUTIME_OFLAG       0
766 #define COMPUTIME_LFLAG       0
767 #define COMPUTIME_SAMPLES     5
768 #define COMPUTIME_KEEP        3
769 
770 static 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 
791 static 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 
1243 static 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 
1257 static struct parseunit *parseunits[MAXUNITS];
1258 
1259 static 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 
1263 static void parse_event   P((struct parseunit *, int));
1264 static void parse_process P((struct parseunit *, parsetime_t *));
1265 static void clear_err     P((struct parseunit *, u_long));
1266 static int  list_err      P((struct parseunit *, u_long));
1267 static char * l_mktime    P((u_long));
1268 
1269 /**===========================================================================
1270  ** implementation error message regression module
1271  **/
1272 static void
1273 clear_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 
1301 static int
1302 list_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 
1356 static char *
1357 mkreadable(
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  */
1426 static char *
1427 mkascii(
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
1446 static int  ppsclock_init   P((struct parseunit *));
1447 static int  stream_init     P((struct parseunit *));
1448 static void stream_end      P((struct parseunit *));
1449 static int  stream_enable   P((struct parseunit *));
1450 static int  stream_disable  P((struct parseunit *));
1451 static int  stream_setcs    P((struct parseunit *, parsectl_t *));
1452 static int  stream_getfmt   P((struct parseunit *, parsectl_t *));
1453 static int  stream_setfmt   P((struct parseunit *, parsectl_t *));
1454 static int  stream_timecode P((struct parseunit *, parsectl_t *));
1455 static void stream_receive  P((struct recvbuf *));
1456 #endif
1457 
1458 static int  local_init     P((struct parseunit *));
1459 static void local_end      P((struct parseunit *));
1460 static int  local_nop      P((struct parseunit *));
1461 static int  local_setcs    P((struct parseunit *, parsectl_t *));
1462 static int  local_getfmt   P((struct parseunit *, parsectl_t *));
1463 static int  local_setfmt   P((struct parseunit *, parsectl_t *));
1464 static int  local_timecode P((struct parseunit *, parsectl_t *));
1465 static void local_receive  P((struct recvbuf *));
1466 static int  local_input    P((struct recvbuf *));
1467 
1468 static 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  */
1544 static int
1545 ppsclock_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  */
1579 static int
1580 stream_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  */
1621 static void
1622 stream_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  */
1633 static int
1634 stream_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  */
1657 static int
1658 stream_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  */
1681 static int
1682 stream_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  */
1705 static int
1706 stream_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  */
1728 static int
1729 stream_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  */
1753 static int
1754 stream_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  */
1779 static void
1780 stream_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  */
1843 static int
1844 local_init(
1845 	struct parseunit *parse
1846 	)
1847 {
1848 	return parse_ioinit(&parse->parseio);
1849 }
1850 
1851 /*--------------------------------------------------
1852  * local end
1853  */
1854 static void
1855 local_end(
1856 	struct parseunit *parse
1857 	)
1858 {
1859 	parse_ioend(&parse->parseio);
1860 }
1861 
1862 
1863 /*--------------------------------------------------
1864  * local nop
1865  */
1866 static int
1867 local_nop(
1868 	struct parseunit *parse
1869 	)
1870 {
1871 	return 1;
1872 }
1873 
1874 /*--------------------------------------------------
1875  * local setcs
1876  */
1877 static int
1878 local_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  */
1889 static int
1890 local_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  */
1901 static int
1902 local_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  */
1913 static int
1914 local_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  */
1926 static int
1927 local_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  */
2053 static void
2054 local_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  */
2101 static bind_t *
2102 init_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  */
2126 static char *
2127 parsestate(
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  */
2216 static char *
2217 parsestatus(
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  */
2259 static const char *
2260 clockstatus(
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  */
2301 static char *
2302 l_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  */
2332 static void
2333 parse_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  */
2380 static void
2381 cparse_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  */
2397 static void
2398 parse_init(void)
2399 {
2400 	memset((caddr_t)parseunits, 0, sizeof parseunits);
2401 }
2402 
2403 
2404 /*--------------------------------------------------
2405  * parse_shutdown - shut down a PARSE clock
2406  */
2407 static void
2408 parse_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  */
2454 static int
2455 parse_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  */
2798 static void
2799 parse_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  */
2854 static void
2855 parse_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  */
3068 static void
3069 parse_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  */
3120 static void
3121 parse_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 
3545 static void
3546 mk_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  */
3589 static void
3590 gps16x_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  */
3980 static void
3981 gps16x_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  */
4058 static int
4059 gps16x_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
4073 static void
4074 gps16x_message(
4075 	       struct parseunit *parse,
4076 	       parsetime_t      *parsetime
4077 	       )
4078 {}
4079 static int
4080 gps16x_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  */
4095 static void
4096 poll_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  */
4122 static void
4123 poll_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  */
4141 static int
4142 poll_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  */
4162 static int
4163 trimbletaip_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  */
4197 static 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 
4204 static void
4205 trimbletaip_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 
4333 typedef 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 
4341 union uval {
4342 	u_char  bd[8];
4343 	int     iv;
4344 	float   fv;
4345 	double  dv;
4346 };
4347 
4348 struct txbuf
4349 {
4350 	short idx;			/* index to first unused byte */
4351 	u_char *txt;			/* pointer to actual data buffer */
4352 };
4353 
4354 void	sendcmd		P((struct txbuf *buf, int c));
4355 void	sendbyte	P((struct txbuf *buf, int b));
4356 void	sendetx		P((struct txbuf *buf, struct parseunit *parse));
4357 void	sendint		P((struct txbuf *buf, int a));
4358 void	sendflt		P((struct txbuf *buf, double a));
4359 
4360 void
4361 sendcmd(
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 
4371 void
4372 sendbyte(
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 
4382 void
4383 sendetx(
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 
4413 void
4414 sendint(
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 
4424 void
4425 sendflt(
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  */
4448 static int
4449 trimbletsip_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  */
4501 static void
4502 trimble_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  */
4549 static void
4550 trimbletsip_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  */
4567 static int
4568 trimbletsip_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  */
4632 static void
4633 trimbletsip_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 
4661 static float
4662 getflt(
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 
4682 static double
4683 getdbl(
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 
4711 static int
4712 getshort(
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 
4725 static void
4726 trimbletsip_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))
5148 static int
5149 rawdcf_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
5172 static int
5173 rawdcfdtr_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))
5187 static int
5188 rawdcf_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
5211 static int
5212 rawdcf_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) */
5222 int 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