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