Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / ntp / ntpd / refclock_parse.c
1 /*
2  * /src/NTP/ntp-4/ntpd/refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A
3  *
4  * refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A
5  *
6  * generic reference clock driver for receivers
7  *
8  * optionally make use of a STREAMS module for input processing where
9  * available and configured. Currently the STREAMS module
10  * is only available for Suns running SunOS 4.x and SunOS5.x
11  *
12  * the STREAMS module is not required for operation and may be omitted
13  * at the cost of reduced accuracy. As new kernel interfaces emerger this
14  * restriction may be lifted in future.
15  *
16  * Copyright (c) 1995-1999 by Frank Kardel <kardel@acm.org>
17  * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
18  *
19  * This software may not be sold for profit without a written consent
20  * from the author.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25  *
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
33
34 /*
35  * This driver currently provides the support for
36  *   - Meinberg receiver DCF77 PZF 535 (TCXO version)       (DCF)
37  *   - Meinberg receiver DCF77 PZF 535 (OCXO version)       (DCF)
38  *   - Meinberg receiver DCF77 PZF 509                      (DCF)
39  *   - Meinberg receiver DCF77 AM receivers (e.g. C51)      (DCF)
40  *   - IGEL CLOCK                                           (DCF)
41  *   - ELV DCF7000                                          (DCF)
42  *   - Schmid clock                                         (DCF)
43  *   - Conrad DCF77 receiver module                         (DCF)
44  *   - FAU DCF77 NTP receiver (TimeBrick)                   (DCF)
45  *
46  *   - Meinberg GPS166/GPS167                               (GPS)
47  *   - Trimble (TSIP and TAIP protocol)                     (GPS)
48  *
49  *   - RCC8000 MSF Receiver                                 (MSF)
50  *   - WHARTON 400A Series clock                            (DCF)
51  *   - VARITEXT clock                                       (MSF)
52  */
53
54 /*
55  * Meinberg receivers are usually connected via a
56  * 9600 baud serial line
57  *
58  * The Meinberg GPS receivers also have a special NTP time stamp
59  * format. The firmware release is Uni-Erlangen.
60  *
61  * Meinberg generic receiver setup:
62  *      output time code every second
63  *      Baud rate 9600 7E2S
64  *
65  * Meinberg GPS16x setup:
66  *      output time code every second
67  *      Baudrate 19200 8N1
68  *
69  * This software supports the standard data formats used
70  * in Meinberg receivers.
71  *
72  * Special software versions are only sensible for the
73  * GPS 16x family of receivers.
74  *
75  * Meinberg can be reached via: http://www.meinberg.de/
76  */
77
78 #include "ntpd.h"
79 #include "ntp_refclock.h"
80 #include "ntp_unixtime.h"       /* includes <sys/time.h> */
81 #include "ntp_control.h"
82
83 #include <stdio.h>
84 #include <ctype.h>
85 #ifndef TM_IN_SYS_TIME
86 # include <time.h>
87 #endif
88
89 #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
90 # include "Bletch:  Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
91 #endif
92
93 #ifdef STREAM
94 # include <sys/stream.h>
95 # include <sys/stropts.h>
96 #endif
97
98 #ifdef HAVE_TERMIOS
99 # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
100 # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
101 # undef HAVE_SYSV_TTYS
102 #endif
103
104 #ifdef HAVE_SYSV_TTYS
105 # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
106 # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
107 #endif
108
109 #ifdef HAVE_BSD_TTYS
110 /* #error CURRENTLY NO BSD TTY SUPPORT */
111 # include "Bletch: BSD TTY not currently supported"
112 #endif
113
114 #ifdef HAVE_SYS_IOCTL_H
115 # include <sys/ioctl.h>
116 #endif
117
118 #ifdef PPS
119 #ifdef HAVE_SYS_PPSCLOCK_H
120 #include <sys/ppsclock.h>
121 #endif
122 #ifdef HAVE_TIO_SERIAL_STUFF
123 #include <linux/serial.h>
124 #endif
125 #endif
126
127 #include "ntp_io.h"
128 #include "ntp_stdlib.h"
129
130 #include "parse.h"
131 #include "mbg_gps166.h"
132 #include "trimble.h"
133 #include "binio.h"
134 #include "ascii.h"
135 #include "ieee754io.h"
136
137 static char rcsid[]="refclock_parse.c,v 4.36 1999/11/28 17:18:20 kardel RELEASE_19991128_A";
138
139 /**===========================================================================
140  ** external interface to ntp mechanism
141  **/
142
143 static  void    parse_init      P((void));
144 static  int     parse_start     P((int, struct peer *));
145 static  void    parse_shutdown  P((int, struct peer *));
146 static  void    parse_poll      P((int, struct peer *));
147 static  void    parse_control   P((int, struct refclockstat *, struct refclockstat *, struct peer *));
148
149 #define parse_buginfo   noentry
150
151 struct  refclock refclock_parse = {
152         parse_start,
153         parse_shutdown,
154         parse_poll,
155         parse_control,
156         parse_init,
157         parse_buginfo,
158         NOFLAGS
159 };
160
161 /*
162  * Definitions
163  */
164 #define MAXUNITS        4       /* maximum number of "PARSE" units permitted */
165 #define PARSEDEVICE     "/dev/refclock-%d" /* device to open %d is unit number */
166
167 #undef ABS
168 #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
169
170 /**===========================================================================
171  ** function vector for dynamically binding io handling mechanism
172  **/
173
174 struct parseunit;               /* to keep inquiring minds happy */
175
176 typedef struct bind
177 {
178   const char *bd_description;                                   /* name of type of binding */
179   int   (*bd_init)     P((struct parseunit *));                 /* initialize */
180   void  (*bd_end)      P((struct parseunit *));                 /* end */
181   int   (*bd_setcs)    P((struct parseunit *, parsectl_t *));   /* set character size */
182   int   (*bd_disable)  P((struct parseunit *));                 /* disable */
183   int   (*bd_enable)   P((struct parseunit *));                 /* enable */
184   int   (*bd_getfmt)   P((struct parseunit *, parsectl_t *));   /* get format */
185   int   (*bd_setfmt)   P((struct parseunit *, parsectl_t *));   /* setfmt */
186   int   (*bd_timecode) P((struct parseunit *, parsectl_t *));   /* get time code */
187   void  (*bd_receive)  P((struct recvbuf *));                   /* receive operation */
188   int   (*bd_io_input) P((struct recvbuf *));                   /* input operation */
189 } bind_t;
190
191 #define PARSE_END(_X_)                  (*(_X_)->binding->bd_end)(_X_)
192 #define PARSE_SETCS(_X_, _CS_)          (*(_X_)->binding->bd_setcs)(_X_, _CS_)
193 #define PARSE_ENABLE(_X_)               (*(_X_)->binding->bd_enable)(_X_)
194 #define PARSE_DISABLE(_X_)              (*(_X_)->binding->bd_disable)(_X_)
195 #define PARSE_GETFMT(_X_, _DCT_)        (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
196 #define PARSE_SETFMT(_X_, _DCT_)        (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
197 #define PARSE_GETTIMECODE(_X_, _DCT_)   (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
198
199 /*
200  * io modes
201  */
202 #define PARSE_F_PPSPPS          0x0001 /* use loopfilter PPS code (CIOGETEV) */
203 #define PARSE_F_PPSONSECOND     0x0002 /* PPS pulses are on second */
204
205
206 /**===========================================================================
207  ** error message regression handling
208  **
209  ** there are quite a few errors that can occur in rapid succession such as
210  ** noisy input data or no data at all. in order to reduce the amount of
211  ** syslog messages in such case, we are using a backoff algorithm. We limit
212  ** the number of error messages of a certain class to 1 per time unit. if a
213  ** configurable number of messages is displayed that way, we move on to the
214  ** next time unit / count for that class. a count of messages that have been
215  ** suppressed is held and displayed whenever a corresponding message is
216  ** displayed. the time units for a message class will also be displayed.
217  ** whenever an error condition clears we reset the error message state,
218  ** thus we would still generate much output on pathological conditions
219  ** where the system oscillates between OK and NOT OK states. coping
220  ** with that condition is currently considered too complicated.
221  **/
222
223 #define ERR_ALL         (unsigned)~0    /* "all" errors */
224 #define ERR_BADDATA     (unsigned)0     /* unusable input data/conversion errors */
225 #define ERR_NODATA      (unsigned)1     /* no input data */
226 #define ERR_BADIO       (unsigned)2     /* read/write/select errors */
227 #define ERR_BADSTATUS   (unsigned)3     /* unsync states */
228 #define ERR_BADEVENT    (unsigned)4     /* non nominal events */
229 #define ERR_INTERNAL    (unsigned)5     /* internal error */
230 #define ERR_CNT         (unsigned)(ERR_INTERNAL+1)
231
232 #define ERR(_X_)        if (list_err(parse, (_X_)))
233
234 struct errorregression
235 {
236         u_long err_count;       /* number of repititions per class */
237         u_long err_delay;       /* minimum delay between messages */
238 };
239
240 static struct errorregression
241 err_baddata[] =                 /* error messages for bad input data */
242 {
243         { 1,       0 },         /* output first message immediately */
244         { 5,      60 },         /* output next five messages in 60 second intervals */
245         { 3,    3600 },         /* output next 3 messages in hour intervals */
246         { 0, 12*3600 }          /* repeat messages only every 12 hours */
247 };
248
249 static struct errorregression
250 err_nodata[] =                  /* error messages for missing input data */
251 {
252         { 1,       0 },         /* output first message immediately */
253         { 5,      60 },         /* output next five messages in 60 second intervals */
254         { 3,    3600 },         /* output next 3 messages in hour intervals */
255         { 0, 12*3600 }          /* repeat messages only every 12 hours */
256 };
257
258 static struct errorregression
259 err_badstatus[] =               /* unsynchronized state messages */
260 {
261         { 1,       0 },         /* output first message immediately */
262         { 5,      60 },         /* output next five messages in 60 second intervals */
263         { 3,    3600 },         /* output next 3 messages in hour intervals */
264         { 0, 12*3600 }          /* repeat messages only every 12 hours */
265 };
266
267 static struct errorregression
268 err_badio[] =                   /* io failures (bad reads, selects, ...) */
269 {
270         { 1,       0 },         /* output first message immediately */
271         { 5,      60 },         /* output next five messages in 60 second intervals */
272         { 5,    3600 },         /* output next 3 messages in hour intervals */
273         { 0, 12*3600 }          /* repeat messages only every 12 hours */
274 };
275
276 static struct errorregression
277 err_badevent[] =                /* non nominal events */
278 {
279         { 20,      0 },         /* output first message immediately */
280         { 6,      60 },         /* output next five messages in 60 second intervals */
281         { 5,    3600 },         /* output next 3 messages in hour intervals */
282         { 0, 12*3600 }          /* repeat messages only every 12 hours */
283 };
284
285 static struct errorregression
286 err_internal[] =                /* really bad things - basically coding/OS errors */
287 {
288         { 0,       0 },         /* output all messages immediately */
289 };
290
291 static struct errorregression *
292 err_tbl[] =
293 {
294         err_baddata,
295         err_nodata,
296         err_badio,
297         err_badstatus,
298         err_badevent,
299         err_internal
300 };
301
302 struct errorinfo
303 {
304         u_long err_started;     /* begin time (ntp) of error condition */
305         u_long err_last;        /* last time (ntp) error occurred */
306         u_long err_cnt; /* number of error repititions */
307         u_long err_suppressed;  /* number of suppressed messages */
308         struct errorregression *err_stage; /* current error stage */
309 };
310
311 /**===========================================================================
312  ** refclock instance data
313  **/
314
315 struct parseunit
316 {
317         /*
318          * NTP management
319          */
320         struct peer         *peer;              /* backlink to peer structure - refclock inactive if 0  */
321         struct refclockproc *generic;           /* backlink to refclockproc structure */
322
323         /*
324          * PARSE io
325          */
326         bind_t       *binding;          /* io handling binding */
327         
328         /*
329          * parse state
330          */
331         parse_t       parseio;          /* io handling structure (user level parsing) */
332
333         /*
334          * type specific parameters
335          */
336         struct parse_clockinfo   *parse_type;           /* link to clock description */
337
338         /*
339          * clock state handling/reporting
340          */
341         u_char        flags;            /* flags (leap_control) */
342         u_long        lastchange;       /* time (ntp) when last state change accured */
343         u_long        statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
344         u_long        pollneeddata;     /* current_time(!=0) for receive sample expected in PPS mode */
345         u_short       lastformat;       /* last format used */
346         u_long        lastsync;         /* time (ntp) when clock was last seen fully synchronized */
347         u_long        lastmissed;       /* time (ntp) when poll didn't get data (powerup heuristic) */
348         u_long        ppsserial;        /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
349         parsetime_t   time;             /* last (parse module) data */
350         void         *localdata;        /* optional local, receiver-specific data */
351         unsigned long localstate;       /* private local state */
352         struct errorinfo errors[ERR_CNT];  /* error state table for suppressing excessive error messages */
353         struct ctl_var *kv;             /* additional pseudo variables */
354         u_long        laststatistic;    /* time when staticstics where output */
355 };
356
357
358 /**===========================================================================
359  ** Clockinfo section all parameter for specific clock types
360  ** includes NTP parameters, TTY parameters and IO handling parameters
361  **/
362
363 static  void    poll_dpoll      P((struct parseunit *));
364 static  void    poll_poll       P((struct peer *));
365 static  int     poll_init       P((struct parseunit *));
366
367 typedef struct poll_info
368 {
369         u_long      rate;               /* poll rate - once every "rate" seconds - 0 off */
370         const char *string;             /* string to send for polling */
371         u_long      count;              /* number of characters in string */
372 } poll_info_t;
373
374 #define NO_CL_FLAGS     0
375 #define NO_POLL         0
376 #define NO_INIT         0
377 #define NO_END          0
378 #define NO_EVENT        0
379 #define NO_DATA         0
380 #define NO_MESSAGE      0
381 #define NO_PPSDELAY     0
382
383 #define DCF_ID          "DCF"   /* generic DCF */
384 #define DCF_A_ID        "DCFa"  /* AM demodulation */
385 #define DCF_P_ID        "DCFp"  /* psuedo random phase shift */
386 #define GPS_ID          "GPS"   /* GPS receiver */
387
388 #define NOCLOCK_ROOTDELAY       0.0
389 #define NOCLOCK_BASEDELAY       0.0
390 #define NOCLOCK_DESCRIPTION     0
391 #define NOCLOCK_MAXUNSYNC       0
392 #define NOCLOCK_CFLAG           0
393 #define NOCLOCK_IFLAG           0
394 #define NOCLOCK_OFLAG           0
395 #define NOCLOCK_LFLAG           0
396 #define NOCLOCK_ID              "TILT"
397 #define NOCLOCK_POLL            NO_POLL
398 #define NOCLOCK_INIT            NO_INIT
399 #define NOCLOCK_END             NO_END
400 #define NOCLOCK_DATA            NO_DATA
401 #define NOCLOCK_FORMAT          ""
402 #define NOCLOCK_TYPE            CTL_SST_TS_UNSPEC
403 #define NOCLOCK_SAMPLES         0
404 #define NOCLOCK_KEEP            0 
405
406 #define DCF_TYPE                CTL_SST_TS_LF
407 #define GPS_TYPE                CTL_SST_TS_UHF
408
409 /*
410  * receiver specific constants
411  */
412 #define MBG_SPEED               (B9600)
413 #define MBG_CFLAG               (CS7|PARENB|CREAD|CLOCAL|HUPCL)
414 #define MBG_IFLAG               (IGNBRK|IGNPAR|ISTRIP)
415 #define MBG_OFLAG               0
416 #define MBG_LFLAG               0
417 #define MBG_FLAGS               PARSE_F_PPSONSECOND
418
419 /*
420  * Meinberg DCF77 receivers
421  */
422 #define DCFUA31_ROOTDELAY       0.0  /* 0 */
423 #define DCFUA31_BASEDELAY       0.010  /* 10.7421875ms: 10 ms (+/- 3 ms) */
424 #define DCFUA31_DESCRIPTION     "Meinberg DCF77 C51 or compatible"
425 #define DCFUA31_MAXUNSYNC       60*30       /* only trust clock for 1/2 hour */
426 #define DCFUA31_SPEED           MBG_SPEED
427 #define DCFUA31_CFLAG           MBG_CFLAG
428 #define DCFUA31_IFLAG           MBG_IFLAG
429 #define DCFUA31_OFLAG           MBG_OFLAG
430 #define DCFUA31_LFLAG           MBG_LFLAG
431 #define DCFUA31_SAMPLES         5
432 #define DCFUA31_KEEP            3
433 #define DCFUA31_FORMAT          "Meinberg Standard"
434
435 /*
436  * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
437  */
438 #define DCFPZF535_ROOTDELAY     0.0
439 #define DCFPZF535_BASEDELAY     0.001968  /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
440 #define DCFPZF535_DESCRIPTION   "Meinberg DCF PZF 535/509 / TCXO"
441 #define DCFPZF535_MAXUNSYNC     60*60*12           /* only trust clock for 12 hours
442                                                     * @ 5e-8df/f we have accumulated
443                                                     * at most 2.16 ms (thus we move to
444                                                     * NTP synchronisation */
445 #define DCFPZF535_SPEED         MBG_SPEED
446 #define DCFPZF535_CFLAG         MBG_CFLAG
447 #define DCFPZF535_IFLAG         MBG_IFLAG
448 #define DCFPZF535_OFLAG         MBG_OFLAG
449 #define DCFPZF535_LFLAG         MBG_LFLAG
450 #define DCFPZF535_SAMPLES              5
451 #define DCFPZF535_KEEP                 3
452 #define DCFPZF535_FORMAT        "Meinberg Standard"
453
454 /*
455  * Meinberg DCF PZF535/OCXO receiver
456  */
457 #define DCFPZF535OCXO_ROOTDELAY 0.0
458 #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
459 #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
460 #define DCFPZF535OCXO_MAXUNSYNC     60*60*96       /* only trust clock for 4 days
461                                                     * @ 5e-9df/f we have accumulated
462                                                     * at most an error of 1.73 ms
463                                                     * (thus we move to NTP synchronisation) */
464 #define DCFPZF535OCXO_SPEED         MBG_SPEED
465 #define DCFPZF535OCXO_CFLAG         MBG_CFLAG
466 #define DCFPZF535OCXO_IFLAG         MBG_IFLAG
467 #define DCFPZF535OCXO_OFLAG         MBG_OFLAG
468 #define DCFPZF535OCXO_LFLAG         MBG_LFLAG
469 #define DCFPZF535OCXO_SAMPLES              5
470 #define DCFPZF535OCXO_KEEP                 3
471 #define DCFPZF535OCXO_FORMAT        "Meinberg Standard"
472
473 /*
474  * Meinberg GPS16X receiver
475  */
476 static  void    gps16x_message   P((struct parseunit *, parsetime_t *));
477 static  int     gps16x_poll_init P((struct parseunit *));
478
479 #define GPS16X_ROOTDELAY        0.0         /* nothing here */
480 #define GPS16X_BASEDELAY        0.001968         /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
481 #define GPS16X_DESCRIPTION      "Meinberg GPS16x receiver"
482 #define GPS16X_MAXUNSYNC        60*60*96       /* only trust clock for 4 days
483                                                 * @ 5e-9df/f we have accumulated
484                                                 * at most an error of 1.73 ms
485                                                 * (thus we move to NTP synchronisation) */
486 #define GPS16X_SPEED            B19200
487 #define GPS16X_CFLAG            (CS8|CREAD|CLOCAL|HUPCL)
488 #define GPS16X_IFLAG            (IGNBRK|IGNPAR)
489 #define GPS16X_OFLAG            MBG_OFLAG
490 #define GPS16X_LFLAG            MBG_LFLAG
491 #define GPS16X_POLLRATE 6
492 #define GPS16X_POLLCMD  ""
493 #define GPS16X_CMDSIZE  0
494
495 static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
496
497 #define GPS16X_INIT             gps16x_poll_init
498 #define GPS16X_POLL             0
499 #define GPS16X_END              0
500 #define GPS16X_DATA             ((void *)(&gps16x_pollinfo))
501 #define GPS16X_MESSAGE          gps16x_message
502 #define GPS16X_ID               GPS_ID
503 #define GPS16X_FORMAT           "Meinberg GPS Extended"
504 #define GPS16X_SAMPLES          5
505 #define GPS16X_KEEP             3
506
507 /*
508  * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
509  *
510  * This is really not the hottest clock - but before you have nothing ...
511  */
512 #define DCF7000_ROOTDELAY       0.0 /* 0 */
513 #define DCF7000_BASEDELAY       0.405 /* slow blow */
514 #define DCF7000_DESCRIPTION     "ELV DCF7000"
515 #define DCF7000_MAXUNSYNC       (60*5) /* sorry - but it just was not build as a clock */
516 #define DCF7000_SPEED           (B9600)
517 #define DCF7000_CFLAG           (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
518 #define DCF7000_IFLAG           (IGNBRK)
519 #define DCF7000_OFLAG           0
520 #define DCF7000_LFLAG           0
521 #define DCF7000_SAMPLES         5
522 #define DCF7000_KEEP            3
523 #define DCF7000_FORMAT          "ELV DCF7000"
524
525 /*
526  * Schmid DCF Receiver Kit
527  *
528  * When the WSDCF clock is operating optimally we want the primary clock
529  * distance to come out at 300 ms.  Thus, peer.distance in the WSDCF peer
530  * structure is set to 290 ms and we compute delays which are at least
531  * 10 ms long.  The following are 290 ms and 10 ms expressed in u_fp format
532  */
533 #define WS_POLLRATE     1       /* every second - watch interdependency with poll routine */
534 #define WS_POLLCMD      "\163"
535 #define WS_CMDSIZE      1
536
537 static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
538
539 #define WSDCF_INIT              poll_init
540 #define WSDCF_POLL              poll_dpoll
541 #define WSDCF_END               0
542 #define WSDCF_DATA              ((void *)(&wsdcf_pollinfo))
543 #define WSDCF_ROOTDELAY         0.0     /* 0 */
544 #define WSDCF_BASEDELAY         0.010   /*  ~  10ms */
545 #define WSDCF_DESCRIPTION       "WS/DCF Receiver"
546 #define WSDCF_FORMAT            "Schmid"
547 #define WSDCF_MAXUNSYNC         (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
548 #define WSDCF_SPEED             (B1200)
549 #define WSDCF_CFLAG             (CS8|CREAD|CLOCAL)
550 #define WSDCF_IFLAG             0
551 #define WSDCF_OFLAG             0
552 #define WSDCF_LFLAG             0
553 #define WSDCF_SAMPLES           5
554 #define WSDCF_KEEP              3
555
556 /*
557  * RAW DCF77 - input of DCF marks via RS232 - many variants
558  */
559 #define RAWDCF_FLAGS            0
560 #define RAWDCF_ROOTDELAY        0.0 /* 0 */
561 #define RAWDCF_BASEDELAY        0.258
562 #define RAWDCF_FORMAT           "RAW DCF77 Timecode"
563 #define RAWDCF_MAXUNSYNC        (0) /* sorry - its a true receiver - no signal - no time */
564 #define RAWDCF_SPEED            (B50)
565 #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
566 /* somehow doesn't grok PARENB & IGNPAR (mj) */
567 # define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL)
568 #else
569 # define RAWDCF_CFLAG            (CS8|CREAD|CLOCAL|PARENB)
570 #endif
571 #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
572 # define RAWDCF_IFLAG           0
573 #else
574 # define RAWDCF_IFLAG           (IGNPAR)
575 #endif
576 #define RAWDCF_OFLAG            0
577 #define RAWDCF_LFLAG            0
578 #define RAWDCF_SAMPLES          20
579 #define RAWDCF_KEEP             12
580 #define RAWDCF_INIT             0
581
582 /*
583  * RAW DCF variants
584  */
585 /*
586  * Conrad receiver
587  *
588  * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
589  * (~40DM - roughly $30 ) followed by a level converter for RS232
590  */
591 #define CONRAD_BASEDELAY        0.292 /* Conrad receiver @ 50 Baud on a Sun */
592 #define CONRAD_DESCRIPTION      "RAW DCF77 CODE (Conrad DCF77 receiver module)"
593
594 /*
595  * TimeBrick receiver
596  */
597 #define TIMEBRICK_BASEDELAY     0.210 /* TimeBrick @ 50 Baud on a Sun */
598 #define TIMEBRICK_DESCRIPTION   "RAW DCF77 CODE (TimeBrick)"
599
600 /*
601  * IGEL:clock receiver
602  */
603 #define IGELCLOCK_BASEDELAY     0.258 /* IGEL:clock receiver */
604 #define IGELCLOCK_DESCRIPTION   "RAW DCF77 CODE (IGEL:clock)"
605 #define IGELCLOCK_SPEED         (B1200)
606 #define IGELCLOCK_CFLAG         (CS8|CREAD|HUPCL|CLOCAL)
607
608 /*
609  * RAWDCF receivers that need to be powered from DTR
610  * (like Expert mouse clock)
611  */
612 static  int     rawdcf_init_1   P((struct parseunit *));
613 #define RAWDCFDTRSET_DESCRIPTION        "RAW DCF77 CODE (DTR SET/RTS CLR)"
614 #define RAWDCFDTRSET_INIT               rawdcf_init_1
615
616 /*
617  * RAWDCF receivers that need to be powered from
618  * DTR CLR and RTS SET
619  */
620 static  int     rawdcf_init_2   P((struct parseunit *));
621 #define RAWDCFDTRCLRRTSSET_DESCRIPTION  "RAW DCF77 CODE (DTR CLR/RTS SET)"
622 #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
623
624 /*
625  * Trimble GPS receivers (TAIP and TSIP protocols)
626  */
627 #ifndef TRIM_POLLRATE
628 #define TRIM_POLLRATE   0       /* only true direct polling */
629 #endif
630
631 #define TRIM_TAIPPOLLCMD        ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
632 #define TRIM_TAIPCMDSIZE        (sizeof(TRIM_TAIPPOLLCMD)-1)
633
634 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
635 static  int     trimbletaip_init        P((struct parseunit *));
636 static  void    trimbletaip_event       P((struct parseunit *, int));
637
638 /* query time & UTC correction data */
639 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
640
641 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
642 static  int     trimbletsip_init        P((struct parseunit *));
643 static  void    trimbletsip_end         P((struct parseunit *));
644 static  void    trimbletsip_message     P((struct parseunit *, parsetime_t *));
645 static  void    trimbletsip_event       P((struct parseunit *, int));
646
647 #define TRIMBLETSIP_IDLE_TIME       (300) /* 5 minutes silence at most */
648
649 #define TRIMBLETAIP_SPEED           (B4800)
650 #define TRIMBLETAIP_CFLAG           (CS8|CREAD|CLOCAL)
651 #define TRIMBLETAIP_IFLAG           (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
652 #define TRIMBLETAIP_OFLAG           (OPOST|ONLCR)
653 #define TRIMBLETAIP_LFLAG           (0)
654
655 #define TRIMBLETSIP_SPEED           (B9600)
656 #define TRIMBLETSIP_CFLAG           (CS8|CLOCAL|CREAD|PARENB|PARODD)
657 #define TRIMBLETSIP_IFLAG           (IGNBRK)
658 #define TRIMBLETSIP_OFLAG           (0)
659 #define TRIMBLETSIP_LFLAG           (ICANON)
660
661 #define TRIMBLETSIP_SAMPLES         5
662 #define TRIMBLETSIP_KEEP            3
663 #define TRIMBLETAIP_SAMPLES         5
664 #define TRIMBLETAIP_KEEP            3
665
666 #define TRIMBLETAIP_FLAGS           (PARSE_F_PPSONSECOND)
667 #define TRIMBLETSIP_FLAGS           (TRIMBLETAIP_FLAGS)
668
669 #define TRIMBLETAIP_POLL            poll_dpoll
670 #define TRIMBLETSIP_POLL            poll_dpoll
671
672 #define TRIMBLETAIP_INIT            trimbletaip_init
673 #define TRIMBLETSIP_INIT            trimbletsip_init
674
675 #define TRIMBLETAIP_EVENT           trimbletaip_event   
676
677 #define TRIMBLETSIP_EVENT           trimbletsip_event   
678 #define TRIMBLETSIP_MESSAGE         trimbletsip_message
679
680 #define TRIMBLETAIP_END             0
681 #define TRIMBLETSIP_END             trimbletsip_end
682
683 #define TRIMBLETAIP_DATA            ((void *)(&trimbletaip_pollinfo))
684 #define TRIMBLETSIP_DATA            ((void *)(&trimbletsip_pollinfo))
685
686 #define TRIMBLETAIP_ID              GPS_ID
687 #define TRIMBLETSIP_ID              GPS_ID
688
689 #define TRIMBLETAIP_FORMAT          "Trimble TAIP"
690 #define TRIMBLETSIP_FORMAT          "Trimble TSIP"
691
692 #define TRIMBLETAIP_ROOTDELAY        0x0
693 #define TRIMBLETSIP_ROOTDELAY        0x0
694
695 #define TRIMBLETAIP_BASEDELAY        0.0
696 #define TRIMBLETSIP_BASEDELAY        0.020      /* GPS time message latency */
697
698 #define TRIMBLETAIP_DESCRIPTION      "Trimble GPS (TAIP) receiver"
699 #define TRIMBLETSIP_DESCRIPTION      "Trimble GPS (TSIP) receiver"
700
701 #define TRIMBLETAIP_MAXUNSYNC        0
702 #define TRIMBLETSIP_MAXUNSYNC        0
703
704 #define TRIMBLETAIP_EOL             '<'
705
706 /*
707  * RadioCode Clocks RCC 800 receiver
708  */
709 #define RCC_POLLRATE   0       /* only true direct polling */
710 #define RCC_POLLCMD    "\r"
711 #define RCC_CMDSIZE    1
712
713 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
714 #define RCC8000_FLAGS           0
715 #define RCC8000_POLL            poll_dpoll
716 #define RCC8000_INIT            poll_init
717 #define RCC8000_END             0
718 #define RCC8000_DATA            ((void *)(&rcc8000_pollinfo))
719 #define RCC8000_ROOTDELAY       0.0
720 #define RCC8000_BASEDELAY       0.0
721 #define RCC8000_ID              "MSF"
722 #define RCC8000_DESCRIPTION     "RCC 8000 MSF Receiver"
723 #define RCC8000_FORMAT          "Radiocode RCC8000"
724 #define RCC8000_MAXUNSYNC       (60*60) /* should be ok for an hour */
725 #define RCC8000_SPEED           (B2400)
726 #define RCC8000_CFLAG           (CS8|CREAD|CLOCAL)
727 #define RCC8000_IFLAG           (IGNBRK|IGNPAR)
728 #define RCC8000_OFLAG           0
729 #define RCC8000_LFLAG           0
730 #define RCC8000_SAMPLES         5
731 #define RCC8000_KEEP            3
732
733 /*
734  * Hopf Radio clock 6021 Format 
735  *
736  */
737 #define HOPF6021_ROOTDELAY      0.0
738 #define HOPF6021_BASEDELAY      0.0
739 #define HOPF6021_DESCRIPTION    "HOPF 6021"
740 #define HOPF6021_FORMAT         "hopf Funkuhr 6021"
741 #define HOPF6021_MAXUNSYNC      (60*60)  /* should be ok for an hour */
742 #define HOPF6021_SPEED         (B9600)
743 #define HOPF6021_CFLAG          (CS8|CREAD|CLOCAL)
744 #define HOPF6021_IFLAG          (IGNBRK|ISTRIP)
745 #define HOPF6021_OFLAG          0
746 #define HOPF6021_LFLAG          0
747 #define HOPF6021_FLAGS          0
748 #define HOPF6021_SAMPLES        5
749 #define HOPF6021_KEEP           3
750
751 /*
752  * Diem's Computime Radio Clock Receiver
753  */
754 #define COMPUTIME_FLAGS       0
755 #define COMPUTIME_ROOTDELAY   0.0
756 #define COMPUTIME_BASEDELAY   0.0
757 #define COMPUTIME_ID          DCF_ID
758 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
759 #define COMPUTIME_FORMAT      "Diem's Computime Radio Clock"
760 #define COMPUTIME_TYPE        DCF_TYPE
761 #define COMPUTIME_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
762 #define COMPUTIME_SPEED       (B9600)
763 #define COMPUTIME_CFLAG       (CSTOPB|CS7|CREAD|CLOCAL)
764 #define COMPUTIME_IFLAG       (IGNBRK|IGNPAR|ISTRIP)
765 #define COMPUTIME_OFLAG       0
766 #define COMPUTIME_LFLAG       0
767 #define COMPUTIME_SAMPLES     5
768 #define COMPUTIME_KEEP        3
769
770 /*
771  * Varitext Radio Clock Receiver
772  */
773 #define VARITEXT_FLAGS       0
774 #define VARITEXT_ROOTDELAY   0.0
775 #define VARITEXT_BASEDELAY   0.0
776 #define VARITEXT_ID          "MSF"
777 #define VARITEXT_DESCRIPTION "Varitext receiver"
778 #define VARITEXT_FORMAT      "Varitext Radio Clock"
779 #define VARITEXT_TYPE        DCF_TYPE
780 #define VARITEXT_MAXUNSYNC   (60*60)       /* only trust clock for 1 hour */
781 #define VARITEXT_SPEED       (B9600)
782 #define VARITEXT_CFLAG       (CS7|CREAD|CLOCAL|PARENB|PARODD)
783 #define VARITEXT_IFLAG       (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
784 #define VARITEXT_OFLAG       0
785 #define VARITEXT_LFLAG       0
786 #define VARITEXT_SAMPLES     32
787 #define VARITEXT_KEEP        20
788
789 static struct parse_clockinfo
790 {
791         u_long  cl_flags;               /* operation flags (io modes) */
792   void  (*cl_poll)    P((struct parseunit *));                  /* active poll routine */
793   int   (*cl_init)    P((struct parseunit *));                  /* active poll init routine */
794   void  (*cl_event)   P((struct parseunit *, int));             /* special event handling (e.g. reset clock) */
795   void  (*cl_end)     P((struct parseunit *));                  /* active poll end routine */
796   void  (*cl_message) P((struct parseunit *, parsetime_t *));   /* process a lower layer message */
797         void   *cl_data;                /* local data area for "poll" mechanism */
798         double    cl_rootdelay;         /* rootdelay */
799         double    cl_basedelay;         /* current offset by which the RS232
800                                 time code is delayed from the actual time */
801         const char *cl_id;              /* ID code */
802         const char *cl_description;             /* device name */
803         const char *cl_format;          /* fixed format */
804         u_char  cl_type;                /* clock type (ntp control) */
805         u_long  cl_maxunsync;           /* time to trust oscillator after loosing synch */
806         u_long  cl_speed;               /* terminal input & output baudrate */
807         u_long  cl_cflag;             /* terminal control flags */
808         u_long  cl_iflag;             /* terminal input flags */
809         u_long  cl_oflag;             /* terminal output flags */
810         u_long  cl_lflag;             /* terminal local flags */
811         u_long  cl_samples;           /* samples for median filter */
812         u_long  cl_keep;              /* samples for median filter to keep */
813 } parse_clockinfo[] =
814 {
815         {                               /* mode 0 */
816                 MBG_FLAGS,
817                 NO_POLL,
818                 NO_INIT,
819                 NO_EVENT,
820                 NO_END,
821                 NO_MESSAGE,
822                 NO_DATA,
823                 DCFPZF535_ROOTDELAY,
824                 DCFPZF535_BASEDELAY,
825                 DCF_P_ID,
826                 DCFPZF535_DESCRIPTION,
827                 DCFPZF535_FORMAT,
828                 DCF_TYPE,
829                 DCFPZF535_MAXUNSYNC,
830                 DCFPZF535_SPEED,
831                 DCFPZF535_CFLAG,
832                 DCFPZF535_IFLAG,
833                 DCFPZF535_OFLAG,
834                 DCFPZF535_LFLAG,
835                 DCFPZF535_SAMPLES,
836                 DCFPZF535_KEEP
837         },
838         {                               /* mode 1 */
839                 MBG_FLAGS,
840                 NO_POLL,
841                 NO_INIT,
842                 NO_EVENT,
843                 NO_END,
844                 NO_MESSAGE,
845                 NO_DATA,
846                 DCFPZF535OCXO_ROOTDELAY,
847                 DCFPZF535OCXO_BASEDELAY,
848                 DCF_P_ID,
849                 DCFPZF535OCXO_DESCRIPTION,
850                 DCFPZF535OCXO_FORMAT,
851                 DCF_TYPE,
852                 DCFPZF535OCXO_MAXUNSYNC,
853                 DCFPZF535OCXO_SPEED,
854                 DCFPZF535OCXO_CFLAG,
855                 DCFPZF535OCXO_IFLAG,
856                 DCFPZF535OCXO_OFLAG,
857                 DCFPZF535OCXO_LFLAG,
858                 DCFPZF535OCXO_SAMPLES,
859                 DCFPZF535OCXO_KEEP
860         },
861         {                               /* mode 2 */
862                 MBG_FLAGS,
863                 NO_POLL,
864                 NO_INIT,
865                 NO_EVENT,
866                 NO_END,
867                 NO_MESSAGE,
868                 NO_DATA,
869                 DCFUA31_ROOTDELAY,
870                 DCFUA31_BASEDELAY,
871                 DCF_A_ID,
872                 DCFUA31_DESCRIPTION,
873                 DCFUA31_FORMAT,
874                 DCF_TYPE,
875                 DCFUA31_MAXUNSYNC,
876                 DCFUA31_SPEED,
877                 DCFUA31_CFLAG,
878                 DCFUA31_IFLAG,
879                 DCFUA31_OFLAG,
880                 DCFUA31_LFLAG,
881                 DCFUA31_SAMPLES,
882                 DCFUA31_KEEP
883         },
884         {                               /* mode 3 */
885                 MBG_FLAGS,
886                 NO_POLL,
887                 NO_INIT,
888                 NO_EVENT,
889                 NO_END,
890                 NO_MESSAGE,
891                 NO_DATA,
892                 DCF7000_ROOTDELAY,
893                 DCF7000_BASEDELAY,
894                 DCF_A_ID,
895                 DCF7000_DESCRIPTION,
896                 DCF7000_FORMAT,
897                 DCF_TYPE,
898                 DCF7000_MAXUNSYNC,
899                 DCF7000_SPEED,
900                 DCF7000_CFLAG,
901                 DCF7000_IFLAG,
902                 DCF7000_OFLAG,
903                 DCF7000_LFLAG,
904                 DCF7000_SAMPLES,
905                 DCF7000_KEEP
906         },
907         {                               /* mode 4 */
908                 NO_CL_FLAGS,
909                 WSDCF_POLL,
910                 WSDCF_INIT,
911                 NO_EVENT,
912                 WSDCF_END,
913                 NO_MESSAGE,
914                 WSDCF_DATA,
915                 WSDCF_ROOTDELAY,
916                 WSDCF_BASEDELAY,
917                 DCF_A_ID,
918                 WSDCF_DESCRIPTION,
919                 WSDCF_FORMAT,
920                 DCF_TYPE,
921                 WSDCF_MAXUNSYNC,
922                 WSDCF_SPEED,
923                 WSDCF_CFLAG,
924                 WSDCF_IFLAG,
925                 WSDCF_OFLAG,
926                 WSDCF_LFLAG,
927                 WSDCF_SAMPLES,
928                 WSDCF_KEEP
929         },
930         {                               /* mode 5 */
931                 RAWDCF_FLAGS,
932                 NO_POLL,
933                 RAWDCF_INIT,
934                 NO_EVENT,
935                 NO_END,
936                 NO_MESSAGE,
937                 NO_DATA,
938                 RAWDCF_ROOTDELAY,
939                 CONRAD_BASEDELAY,
940                 DCF_A_ID,
941                 CONRAD_DESCRIPTION,
942                 RAWDCF_FORMAT,
943                 DCF_TYPE,
944                 RAWDCF_MAXUNSYNC,
945                 RAWDCF_SPEED,
946                 RAWDCF_CFLAG,
947                 RAWDCF_IFLAG,
948                 RAWDCF_OFLAG,
949                 RAWDCF_LFLAG,
950                 RAWDCF_SAMPLES,
951                 RAWDCF_KEEP
952         },
953         {                               /* mode 6 */
954                 RAWDCF_FLAGS,
955                 NO_POLL,
956                 RAWDCF_INIT,
957                 NO_EVENT,
958                 NO_END,
959                 NO_MESSAGE,
960                 NO_DATA,
961                 RAWDCF_ROOTDELAY,
962                 TIMEBRICK_BASEDELAY,
963                 DCF_A_ID,
964                 TIMEBRICK_DESCRIPTION,
965                 RAWDCF_FORMAT,
966                 DCF_TYPE,
967                 RAWDCF_MAXUNSYNC,
968                 RAWDCF_SPEED,
969                 RAWDCF_CFLAG,
970                 RAWDCF_IFLAG,
971                 RAWDCF_OFLAG,
972                 RAWDCF_LFLAG,
973                 RAWDCF_SAMPLES,
974                 RAWDCF_KEEP
975         },
976         {                               /* mode 7 */
977                 MBG_FLAGS,
978                 GPS16X_POLL,
979                 GPS16X_INIT,
980                 NO_EVENT,
981                 GPS16X_END,
982                 GPS16X_MESSAGE,
983                 GPS16X_DATA,
984                 GPS16X_ROOTDELAY,
985                 GPS16X_BASEDELAY,
986                 GPS16X_ID,
987                 GPS16X_DESCRIPTION,
988                 GPS16X_FORMAT,
989                 GPS_TYPE,
990                 GPS16X_MAXUNSYNC,
991                 GPS16X_SPEED,
992                 GPS16X_CFLAG,
993                 GPS16X_IFLAG,
994                 GPS16X_OFLAG,
995                 GPS16X_LFLAG,
996                 GPS16X_SAMPLES,
997                 GPS16X_KEEP
998         },
999         {                               /* mode 8 */
1000                 RAWDCF_FLAGS,
1001                 NO_POLL,
1002                 NO_INIT,
1003                 NO_EVENT,
1004                 NO_END,
1005                 NO_MESSAGE,
1006                 NO_DATA,
1007                 RAWDCF_ROOTDELAY,
1008                 IGELCLOCK_BASEDELAY,
1009                 DCF_A_ID,
1010                 IGELCLOCK_DESCRIPTION,
1011                 RAWDCF_FORMAT,
1012                 DCF_TYPE,
1013                 RAWDCF_MAXUNSYNC,
1014                 IGELCLOCK_SPEED,
1015                 IGELCLOCK_CFLAG,
1016                 RAWDCF_IFLAG,
1017                 RAWDCF_OFLAG,
1018                 RAWDCF_LFLAG,
1019                 RAWDCF_SAMPLES,
1020                 RAWDCF_KEEP
1021         },
1022         {                               /* mode 9 */
1023                 TRIMBLETAIP_FLAGS,
1024 #if TRIM_POLLRATE               /* DHD940515: Allow user config */
1025                 NO_POLL,
1026 #else
1027                 TRIMBLETAIP_POLL,
1028 #endif
1029                 TRIMBLETAIP_INIT,
1030                 TRIMBLETAIP_EVENT,
1031                 TRIMBLETAIP_END,
1032                 NO_MESSAGE,
1033                 TRIMBLETAIP_DATA,
1034                 TRIMBLETAIP_ROOTDELAY,
1035                 TRIMBLETAIP_BASEDELAY,
1036                 TRIMBLETAIP_ID,
1037                 TRIMBLETAIP_DESCRIPTION,
1038                 TRIMBLETAIP_FORMAT,
1039                 GPS_TYPE,
1040                 TRIMBLETAIP_MAXUNSYNC,
1041                 TRIMBLETAIP_SPEED,
1042                 TRIMBLETAIP_CFLAG,
1043                 TRIMBLETAIP_IFLAG,
1044                 TRIMBLETAIP_OFLAG,
1045                 TRIMBLETAIP_LFLAG,
1046                 TRIMBLETAIP_SAMPLES,
1047                 TRIMBLETAIP_KEEP
1048         },
1049         {                               /* mode 10 */
1050                 TRIMBLETSIP_FLAGS,
1051 #if TRIM_POLLRATE               /* DHD940515: Allow user config */
1052                 NO_POLL,
1053 #else
1054                 TRIMBLETSIP_POLL,
1055 #endif
1056                 TRIMBLETSIP_INIT,
1057                 TRIMBLETSIP_EVENT,
1058                 TRIMBLETSIP_END,
1059                 TRIMBLETSIP_MESSAGE,
1060                 TRIMBLETSIP_DATA,
1061                 TRIMBLETSIP_ROOTDELAY,
1062                 TRIMBLETSIP_BASEDELAY,
1063                 TRIMBLETSIP_ID,
1064                 TRIMBLETSIP_DESCRIPTION,
1065                 TRIMBLETSIP_FORMAT,
1066                 GPS_TYPE,
1067                 TRIMBLETSIP_MAXUNSYNC,
1068                 TRIMBLETSIP_SPEED,
1069                 TRIMBLETSIP_CFLAG,
1070                 TRIMBLETSIP_IFLAG,
1071                 TRIMBLETSIP_OFLAG,
1072                 TRIMBLETSIP_LFLAG,
1073                 TRIMBLETSIP_SAMPLES,
1074                 TRIMBLETSIP_KEEP
1075         },
1076         {                             /* mode 11 */
1077                 NO_CL_FLAGS,
1078                 RCC8000_POLL,
1079                 RCC8000_INIT,
1080                 NO_EVENT,
1081                 RCC8000_END,
1082                 NO_MESSAGE,
1083                 RCC8000_DATA,
1084                 RCC8000_ROOTDELAY,
1085                 RCC8000_BASEDELAY,
1086                 RCC8000_ID,
1087                 RCC8000_DESCRIPTION,
1088                 RCC8000_FORMAT,
1089                 DCF_TYPE,
1090                 RCC8000_MAXUNSYNC,
1091                 RCC8000_SPEED,
1092                 RCC8000_CFLAG,
1093                 RCC8000_IFLAG,
1094                 RCC8000_OFLAG,
1095                 RCC8000_LFLAG,
1096                 RCC8000_SAMPLES,
1097                 RCC8000_KEEP
1098         },
1099         {                             /* mode 12 */
1100                 HOPF6021_FLAGS,
1101                 NO_POLL,     
1102                 NO_INIT,
1103                 NO_EVENT,
1104                 NO_END,
1105                 NO_MESSAGE,
1106                 NO_DATA,
1107                 HOPF6021_ROOTDELAY,
1108                 HOPF6021_BASEDELAY,
1109                 DCF_ID,
1110                 HOPF6021_DESCRIPTION,
1111                 HOPF6021_FORMAT,
1112                 DCF_TYPE,
1113                 HOPF6021_MAXUNSYNC,
1114                 HOPF6021_SPEED,
1115                 HOPF6021_CFLAG,
1116                 HOPF6021_IFLAG,
1117                 HOPF6021_OFLAG,
1118                 HOPF6021_LFLAG,
1119                 HOPF6021_SAMPLES,
1120                 HOPF6021_KEEP
1121         },
1122         {                            /* mode 13 */
1123                 COMPUTIME_FLAGS,
1124                 NO_POLL,
1125                 NO_INIT,
1126                 NO_EVENT,
1127                 NO_END,
1128                 NO_MESSAGE,
1129                 NO_DATA,
1130                 COMPUTIME_ROOTDELAY,
1131                 COMPUTIME_BASEDELAY,
1132                 COMPUTIME_ID,
1133                 COMPUTIME_DESCRIPTION,
1134                 COMPUTIME_FORMAT,
1135                 COMPUTIME_TYPE,
1136                 COMPUTIME_MAXUNSYNC,
1137                 COMPUTIME_SPEED,
1138                 COMPUTIME_CFLAG,
1139                 COMPUTIME_IFLAG,
1140                 COMPUTIME_OFLAG,
1141                 COMPUTIME_LFLAG,
1142                 COMPUTIME_SAMPLES,
1143                 COMPUTIME_KEEP
1144         },
1145         {                               /* mode 14 */
1146                 RAWDCF_FLAGS,
1147                 NO_POLL,
1148                 RAWDCFDTRSET_INIT,
1149                 NO_EVENT,
1150                 NO_END,
1151                 NO_MESSAGE,
1152                 NO_DATA,
1153                 RAWDCF_ROOTDELAY,
1154                 RAWDCF_BASEDELAY,
1155                 DCF_A_ID,
1156                 RAWDCFDTRSET_DESCRIPTION,
1157                 RAWDCF_FORMAT,
1158                 DCF_TYPE,
1159                 RAWDCF_MAXUNSYNC,
1160                 RAWDCF_SPEED,
1161                 RAWDCF_CFLAG,
1162                 RAWDCF_IFLAG,
1163                 RAWDCF_OFLAG,
1164                 RAWDCF_LFLAG,
1165                 RAWDCF_SAMPLES,
1166                 RAWDCF_KEEP
1167         },
1168         {                               /* mode 15 */
1169                 0,                              /* operation flags (io modes) */
1170                 NO_POLL,                        /* active poll routine */
1171                 NO_INIT,                        /* active poll init routine */
1172                 NO_EVENT,                       /* special event handling (e.g. reset clock) */
1173                 NO_END,                         /* active poll end routine */
1174                 NO_MESSAGE,                     /* process a lower layer message */
1175                 NO_DATA,                        /* local data area for "poll" mechanism */
1176                 0,                              /* rootdelay */
1177                 11.0 /* bits */ / 9600,         /* current offset by which the RS232
1178                                                 time code is delayed from the actual time */
1179                 DCF_ID,                         /* ID code */
1180                 "WHARTON 400A Series clock",    /* device name */
1181                 "WHARTON 400A Series clock Output Format 1",    /* fixed format */
1182                         /* Must match a format-name in a libparse/clk_xxx.c file */
1183                 DCF_TYPE,                       /* clock type (ntp control) */
1184                 (1*60*60),                      /* time to trust oscillator after loosing synch */
1185                 B9600,                          /* terminal input & output baudrate */
1186                 (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1187                 0,                              /* terminal input flags */
1188                 0,                              /* terminal output flags */
1189                 0,                              /* terminal local flags */
1190                 5,                              /* samples for median filter */
1191                 3,                              /* samples for median filter to keep */
1192         },
1193         {                               /* mode 16 - RAWDCF RTS set, DTR clr */
1194                 RAWDCF_FLAGS,
1195                 NO_POLL,
1196                 RAWDCFDTRCLRRTSSET_INIT,
1197                 NO_EVENT,
1198                 NO_END,
1199                 NO_MESSAGE,
1200                 NO_DATA,
1201                 RAWDCF_ROOTDELAY,
1202                 RAWDCF_BASEDELAY,
1203                 DCF_A_ID,
1204                 RAWDCFDTRCLRRTSSET_DESCRIPTION,
1205                 RAWDCF_FORMAT,
1206                 DCF_TYPE,
1207                 RAWDCF_MAXUNSYNC,
1208                 RAWDCF_SPEED,
1209                 RAWDCF_CFLAG,
1210                 RAWDCF_IFLAG,
1211                 RAWDCF_OFLAG,
1212                 RAWDCF_LFLAG,
1213                 RAWDCF_SAMPLES,
1214                 RAWDCF_KEEP
1215         },
1216         {                            /* mode 17 */
1217                 VARITEXT_FLAGS,
1218                 NO_POLL,
1219                 NO_INIT,
1220                 NO_EVENT,
1221                 NO_END,
1222                 NO_MESSAGE,
1223                 NO_DATA,
1224                 VARITEXT_ROOTDELAY,
1225                 VARITEXT_BASEDELAY,
1226                 VARITEXT_ID,
1227                 VARITEXT_DESCRIPTION,
1228                 VARITEXT_FORMAT,
1229                 VARITEXT_TYPE,
1230                 VARITEXT_MAXUNSYNC,
1231                 VARITEXT_SPEED,
1232                 VARITEXT_CFLAG,
1233                 VARITEXT_IFLAG,
1234                 VARITEXT_OFLAG,
1235                 VARITEXT_LFLAG,
1236                 VARITEXT_SAMPLES,
1237                 VARITEXT_KEEP
1238         }
1239 };
1240
1241 static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1242
1243 #define CLK_REALTYPE(x) ((int)(((x)->ttlmax) & 0x7F))
1244 #define CLK_TYPE(x)     ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1245 #define CLK_UNIT(x)     ((int)REFCLOCKUNIT(&(x)->srcadr))
1246 #define CLK_PPS(x)      (((x)->ttlmax) & 0x80)
1247
1248 /*
1249  * Other constant stuff
1250  */
1251 #define PARSEHSREFID    0x7f7f08ff      /* 127.127.8.255 refid for hi strata */
1252
1253 #define PARSESTATISTICS   (60*60)               /* output state statistics every hour */
1254
1255 static struct parseunit *parseunits[MAXUNITS];
1256
1257 static int notice = 0;
1258
1259 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1260
1261 static void parse_event   P((struct parseunit *, int));
1262 static void parse_process P((struct parseunit *, parsetime_t *));
1263 static void clear_err     P((struct parseunit *, u_long));
1264 static int  list_err      P((struct parseunit *, u_long));
1265 static char * l_mktime    P((u_long));
1266
1267 /**===========================================================================
1268  ** implementation error message regression module
1269  **/
1270 static void
1271 clear_err(
1272         struct parseunit *parse,
1273         u_long            lstate
1274         )
1275 {
1276         if (lstate == ERR_ALL)
1277         {
1278                 int i;
1279
1280                 for (i = 0; i < ERR_CNT; i++)
1281                 {
1282                         parse->errors[i].err_stage   = err_tbl[i];
1283                         parse->errors[i].err_cnt     = 0;
1284                         parse->errors[i].err_last    = 0;
1285                         parse->errors[i].err_started = 0;
1286                         parse->errors[i].err_suppressed = 0;
1287                 }
1288         }
1289         else
1290         {
1291                 parse->errors[lstate].err_stage   = err_tbl[lstate];
1292                 parse->errors[lstate].err_cnt     = 0;
1293                 parse->errors[lstate].err_last    = 0;
1294                 parse->errors[lstate].err_started = 0;
1295                 parse->errors[lstate].err_suppressed = 0;
1296         }
1297 }
1298
1299 static int
1300 list_err(
1301         struct parseunit *parse,
1302         u_long            lstate
1303         )
1304 {
1305         int do_it;
1306         struct errorinfo *err = &parse->errors[lstate];
1307
1308         if (err->err_started == 0)
1309         {
1310                 err->err_started = current_time;
1311         }
1312
1313         do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1314
1315         if (do_it)
1316             err->err_cnt++;
1317   
1318         if (err->err_stage->err_count &&
1319             (err->err_cnt >= err->err_stage->err_count))
1320         {
1321                 err->err_stage++;
1322                 err->err_cnt = 0;
1323         }
1324
1325         if (!err->err_cnt && do_it)
1326             msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1327                     CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1328
1329         if (!do_it)
1330             err->err_suppressed++;
1331         else
1332             err->err_last = current_time;
1333
1334         if (do_it && err->err_suppressed)
1335         {
1336                 msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1337                         CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1338                         l_mktime(current_time - err->err_started));
1339                 err->err_suppressed = 0;
1340         }
1341   
1342         return do_it;
1343 }
1344
1345 /*--------------------------------------------------
1346  * mkreadable - make a printable ascii string (without
1347  * embedded quotes so that the ntpq protocol isn't
1348  * fooled
1349  */
1350 #ifndef isprint
1351 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1352 #endif
1353
1354 static char *
1355 mkreadable(
1356         char  *buffer,
1357         long  blen,
1358         const char  *src,
1359         u_long  srclen,
1360         int hex
1361         )
1362 {
1363         char *b    = buffer;
1364         char *endb = (char *)0;
1365
1366         if (blen < 4)
1367                 return (char *)0;               /* don't bother with mini buffers */
1368
1369         endb = buffer + blen - 4;
1370
1371         blen--;                 /* account for '\0' */
1372
1373         while (blen && srclen--)
1374         {
1375                 if (!hex &&             /* no binary only */
1376                     (*src != '\\') &&   /* no plain \ */
1377                     (*src != '"') &&    /* no " */
1378                     isprint((int)*src)) /* only printables */
1379                 {                       /* they are easy... */
1380                         *buffer++ = *src++;
1381                         blen--;
1382                 }
1383                 else
1384                 {
1385                         if (blen < 4)
1386                         {
1387                                 while (blen--)
1388                                 {
1389                                         *buffer++ = '.';
1390                                 }
1391                                 *buffer = '\0';
1392                                 return b;
1393                         }
1394                         else
1395                         {
1396                                 if (*src == '\\')
1397                                 {
1398                                         strcpy(buffer,"\\\\");
1399                                         buffer += 2;
1400                                         blen   -= 2;
1401                                         src++;
1402                                 }
1403                                 else
1404                                 {
1405                                         sprintf(buffer, "\\x%02x", *src++);
1406                                         blen   -= 4;
1407                                         buffer += 4;
1408                                 }
1409                         }
1410                 }
1411                 if (srclen && !blen && endb) /* overflow - set last chars to ... */
1412                         strcpy(endb, "...");
1413         }
1414
1415         *buffer = '\0';
1416         return b;
1417 }
1418
1419
1420 /*--------------------------------------------------
1421  * mkascii - make a printable ascii string
1422  * assumes (unless defined better) 7-bit ASCII
1423  */
1424 static char *
1425 mkascii(
1426         char  *buffer,
1427         long  blen,
1428         const char  *src,
1429         u_long  srclen
1430         )
1431 {
1432         return mkreadable(buffer, blen, src, srclen, 0);
1433 }
1434
1435 /**===========================================================================
1436  ** implementation of i/o handling methods
1437  ** (all STREAM, partial STREAM, user level)
1438  **/
1439
1440 /*
1441  * define possible io handling methods
1442  */
1443 #ifdef STREAM
1444 static int  ppsclock_init   P((struct parseunit *));
1445 static int  stream_init     P((struct parseunit *));
1446 static void stream_end      P((struct parseunit *));
1447 static int  stream_enable   P((struct parseunit *));
1448 static int  stream_disable  P((struct parseunit *));
1449 static int  stream_setcs    P((struct parseunit *, parsectl_t *));
1450 static int  stream_getfmt   P((struct parseunit *, parsectl_t *));
1451 static int  stream_setfmt   P((struct parseunit *, parsectl_t *));
1452 static int  stream_timecode P((struct parseunit *, parsectl_t *));
1453 static void stream_receive  P((struct recvbuf *));
1454 #endif
1455                                          
1456 static int  local_init     P((struct parseunit *));
1457 static void local_end      P((struct parseunit *));
1458 static int  local_nop      P((struct parseunit *));
1459 static int  local_setcs    P((struct parseunit *, parsectl_t *));
1460 static int  local_getfmt   P((struct parseunit *, parsectl_t *));
1461 static int  local_setfmt   P((struct parseunit *, parsectl_t *));
1462 static int  local_timecode P((struct parseunit *, parsectl_t *));
1463 static void local_receive  P((struct recvbuf *));
1464 static int  local_input    P((struct recvbuf *));
1465
1466 static bind_t io_bindings[] =
1467 {
1468 #ifdef STREAM
1469         {
1470                 "parse STREAM",
1471                 stream_init,
1472                 stream_end,
1473                 stream_setcs,
1474                 stream_disable,
1475                 stream_enable,
1476                 stream_getfmt,
1477                 stream_setfmt,
1478                 stream_timecode,
1479                 stream_receive,
1480                 0,
1481         },
1482         {
1483                 "ppsclock STREAM",
1484                 ppsclock_init,
1485                 local_end,
1486                 local_setcs,
1487                 local_nop,
1488                 local_nop,
1489                 local_getfmt,
1490                 local_setfmt,
1491                 local_timecode,
1492                 local_receive,
1493                 local_input,
1494         },
1495 #endif
1496         {
1497                 "normal",
1498                 local_init,
1499                 local_end,
1500                 local_setcs,
1501                 local_nop,
1502                 local_nop,
1503                 local_getfmt,
1504                 local_setfmt,
1505                 local_timecode,
1506                 local_receive,
1507                 local_input,
1508         },
1509         {
1510                 (char *)0,
1511         }
1512 };
1513
1514 #ifdef STREAM
1515
1516 #define fix_ts(_X_) \
1517                         if ((&(_X_))->tv.tv_usec >= 1000000)                \
1518                           {                                                 \
1519                             (&(_X_))->tv.tv_usec -= 1000000;                \
1520                             (&(_X_))->tv.tv_sec  += 1;                      \
1521                           }
1522
1523 #define cvt_ts(_X_, _Y_) \
1524                         {                                                   \
1525                           l_fp ts;                                          \
1526                           fix_ts((_X_));                                    \
1527                           if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1528                             {                                               \
1529                               ERR(ERR_BADDATA)                              \
1530                                 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1531                               return;                                       \
1532                             }                                               \
1533                           else                                              \
1534                             {                                               \
1535                               (&(_X_))->fp = ts;                            \
1536                             }                                               \
1537                         }
1538
1539 /*--------------------------------------------------
1540  * ppsclock STREAM init
1541  */
1542 static int
1543 ppsclock_init(
1544         struct parseunit *parse
1545         )
1546 {
1547         static char m1[] = "ppsclocd";
1548         static char m2[] = "ppsclock";
1549         
1550         /*
1551          * now push the parse streams module
1552          * it will ensure exclusive access to the device
1553          */
1554         if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1 &&
1555             ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m2) == -1)
1556         {
1557                 if (errno != EINVAL)
1558                 {
1559                         msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1560                                 CLK_UNIT(parse->peer));
1561                 }
1562                 return 0;
1563         }
1564         if (!local_init(parse))
1565         {
1566                 (void)ioctl(parse->generic->io.fd, I_POP, (caddr_t)0);
1567                 return 0;
1568         }
1569
1570         parse->flags |= PARSE_PPSCLOCK;
1571         return 1;
1572 }
1573
1574 /*--------------------------------------------------
1575  * parse STREAM init
1576  */
1577 static int
1578 stream_init(
1579         struct parseunit *parse
1580         )
1581 {
1582         static char m1[] = "parse";
1583         /*
1584          * now push the parse streams module
1585          * to test whether it is there (neat interface 8-( )
1586          */
1587         if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1588         {
1589                 if (errno != EINVAL) /* accept non-existence */
1590                 {
1591                         msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1592                 }
1593                 return 0;
1594         }
1595         else
1596         {
1597                 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1598                     /* empty loop */;
1599
1600                 /*
1601                  * now push it a second time after we have removed all
1602                  * module garbage
1603                  */
1604                 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1605                 {
1606                         msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1607                         return 0;
1608                 }
1609                 else
1610                 {
1611                         return 1;
1612                 }
1613         }
1614 }
1615
1616 /*--------------------------------------------------
1617  * parse STREAM end
1618  */
1619 static void
1620 stream_end(
1621         struct parseunit *parse
1622         )
1623 {
1624         while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1625             /* empty loop */;
1626 }
1627
1628 /*--------------------------------------------------
1629  * STREAM setcs
1630  */
1631 static int
1632 stream_setcs(
1633         struct parseunit *parse,
1634         parsectl_t  *tcl
1635         )
1636 {
1637         struct strioctl strioc;
1638   
1639         strioc.ic_cmd     = PARSEIOC_SETCS;
1640         strioc.ic_timout  = 0;
1641         strioc.ic_dp      = (char *)tcl;
1642         strioc.ic_len     = sizeof (*tcl);
1643
1644         if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1645         {
1646                 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1647                 return 0;
1648         }
1649         return 1;
1650 }
1651
1652 /*--------------------------------------------------
1653  * STREAM enable
1654  */
1655 static int
1656 stream_enable(
1657         struct parseunit *parse
1658         )
1659 {
1660         struct strioctl strioc;
1661   
1662         strioc.ic_cmd     = PARSEIOC_ENABLE;
1663         strioc.ic_timout  = 0;
1664         strioc.ic_dp      = (char *)0;
1665         strioc.ic_len     = 0;
1666
1667         if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1668         {
1669                 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1670                 return 0;
1671         }
1672         parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1673         return 1;
1674 }
1675
1676 /*--------------------------------------------------
1677  * STREAM disable
1678  */
1679 static int
1680 stream_disable(
1681         struct parseunit *parse
1682         )
1683 {
1684         struct strioctl strioc;
1685   
1686         strioc.ic_cmd     = PARSEIOC_DISABLE;
1687         strioc.ic_timout  = 0;
1688         strioc.ic_dp      = (char *)0;
1689         strioc.ic_len     = 0;
1690
1691         if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1692         {
1693                 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1694                 return 0;
1695         }
1696         parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1697         return 1;
1698 }
1699
1700 /*--------------------------------------------------
1701  * STREAM getfmt
1702  */
1703 static int
1704 stream_getfmt(
1705         struct parseunit *parse,
1706         parsectl_t  *tcl
1707         )
1708 {
1709         struct strioctl strioc;
1710   
1711         strioc.ic_cmd     = PARSEIOC_GETFMT;
1712         strioc.ic_timout  = 0;
1713         strioc.ic_dp      = (char *)tcl;
1714         strioc.ic_len     = sizeof (*tcl);
1715         if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1716         {
1717                 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1718                 return 0;
1719         }
1720         return 1;
1721 }
1722
1723 /*--------------------------------------------------
1724  * STREAM setfmt
1725  */
1726 static int
1727 stream_setfmt(
1728         struct parseunit *parse,
1729         parsectl_t  *tcl
1730         )
1731 {
1732         struct strioctl strioc;
1733   
1734         strioc.ic_cmd     = PARSEIOC_SETFMT;
1735         strioc.ic_timout  = 0;
1736         strioc.ic_dp      = (char *)tcl;
1737         strioc.ic_len     = sizeof (*tcl);
1738
1739         if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1740         {
1741                 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1742                 return 0;
1743         }
1744         return 1;
1745 }
1746
1747
1748 /*--------------------------------------------------
1749  * STREAM timecode
1750  */
1751 static int
1752 stream_timecode(
1753         struct parseunit *parse,
1754         parsectl_t  *tcl
1755         )
1756 {
1757         struct strioctl strioc;
1758   
1759         strioc.ic_cmd     = PARSEIOC_TIMECODE;
1760         strioc.ic_timout  = 0;
1761         strioc.ic_dp      = (char *)tcl;
1762         strioc.ic_len     = sizeof (*tcl);
1763         
1764         if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1765         {
1766                 ERR(ERR_INTERNAL)
1767                         msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
1768                 return 0;
1769         }
1770         clear_err(parse, ERR_INTERNAL);
1771         return 1;
1772 }
1773
1774 /*--------------------------------------------------
1775  * STREAM receive
1776  */
1777 static void
1778 stream_receive(
1779         struct recvbuf *rbufp
1780         )
1781 {
1782         struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1783         parsetime_t parsetime;
1784
1785         if (!parse->peer)
1786             return;
1787
1788         if (rbufp->recv_length != sizeof(parsetime_t))
1789         {
1790                 ERR(ERR_BADIO)
1791                         msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1792                                 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
1793                 parse->generic->baddata++;
1794                 parse_event(parse, CEVNT_BADREPLY);
1795                 return;
1796         }
1797         clear_err(parse, ERR_BADIO);
1798   
1799         memmove((caddr_t)&parsetime,
1800                 (caddr_t)rbufp->recv_buffer,
1801                 sizeof(parsetime_t));
1802
1803 #ifdef DEBUG
1804         if (debug > 3)
1805           {
1806             printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1807                    CLK_UNIT(parse->peer),
1808                    (unsigned int)parsetime.parse_status,
1809                    (unsigned int)parsetime.parse_state,
1810                    (long)parsetime.parse_time.tv.tv_sec,
1811                    (long)parsetime.parse_time.tv.tv_usec,
1812                    (long)parsetime.parse_stime.tv.tv_sec,
1813                    (long)parsetime.parse_stime.tv.tv_usec,
1814                    (long)parsetime.parse_ptime.tv.tv_sec,
1815                    (long)parsetime.parse_ptime.tv.tv_usec);
1816           }
1817 #endif
1818
1819         /*
1820          * switch time stamp world - be sure to normalize small usec field
1821          * errors.
1822          */
1823
1824         cvt_ts(parsetime.parse_stime, "parse_stime");
1825
1826         if (PARSE_TIMECODE(parsetime.parse_state))
1827         {
1828             cvt_ts(parsetime.parse_time, "parse_time");
1829         }
1830
1831         if (PARSE_PPS(parsetime.parse_state))
1832             cvt_ts(parsetime.parse_ptime, "parse_ptime");
1833
1834         parse_process(parse, &parsetime);
1835 }
1836 #endif
1837
1838 /*--------------------------------------------------
1839  * local init
1840  */
1841 static int
1842 local_init(
1843         struct parseunit *parse
1844         )
1845 {
1846         return parse_ioinit(&parse->parseio);
1847 }
1848
1849 /*--------------------------------------------------
1850  * local end
1851  */
1852 static void
1853 local_end(
1854         struct parseunit *parse
1855         )
1856 {
1857         parse_ioend(&parse->parseio);
1858 }
1859
1860
1861 /*--------------------------------------------------
1862  * local nop
1863  */
1864 static int
1865 local_nop(
1866         struct parseunit *parse
1867         )
1868 {
1869         return 1;
1870 }
1871
1872 /*--------------------------------------------------
1873  * local setcs
1874  */
1875 static int
1876 local_setcs(
1877         struct parseunit *parse,
1878         parsectl_t  *tcl
1879         )
1880 {
1881         return parse_setcs(tcl, &parse->parseio);
1882 }
1883
1884 /*--------------------------------------------------
1885  * local getfmt
1886  */
1887 static int
1888 local_getfmt(
1889         struct parseunit *parse,
1890         parsectl_t  *tcl
1891         )
1892 {
1893         return parse_getfmt(tcl, &parse->parseio);
1894 }
1895
1896 /*--------------------------------------------------
1897  * local setfmt
1898  */
1899 static int
1900 local_setfmt(
1901         struct parseunit *parse,
1902         parsectl_t  *tcl
1903         )
1904 {
1905         return parse_setfmt(tcl, &parse->parseio);
1906 }
1907
1908 /*--------------------------------------------------
1909  * local timecode
1910  */
1911 static int
1912 local_timecode(
1913         struct parseunit *parse,
1914         parsectl_t  *tcl
1915         )
1916 {
1917         return parse_timecode(tcl, &parse->parseio);
1918 }
1919
1920
1921 /*--------------------------------------------------
1922  * local input
1923  */
1924 static int
1925 local_input(
1926         struct recvbuf *rbufp
1927         )
1928 {
1929         struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1930         int count;
1931         unsigned char *s;
1932         timestamp_t ts;
1933
1934         if (!parse->peer)
1935                 return 0;
1936
1937         /*
1938          * eat all characters, parsing then and feeding complete samples
1939          */
1940         count = rbufp->recv_length;
1941         s = (unsigned char *)rbufp->recv_buffer;
1942         ts.fp = rbufp->recv_time;
1943
1944         while (count--)
1945         {
1946                 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
1947                 {
1948                         struct recvbuf buf;
1949
1950                         /*
1951                          * got something good to eat
1952                          */
1953                         if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
1954                         {
1955 #ifdef TIOCDCDTIMESTAMP
1956                                 struct timeval dcd_time;
1957                                 
1958                                 if (ioctl(rbufp->fd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
1959                                 {
1960                                         l_fp tstmp;
1961                                         
1962                                         TVTOTS(&dcd_time, &tstmp);
1963                                         tstmp.l_ui += JAN_1970;
1964                                         L_SUB(&ts.fp, &tstmp);
1965                                         if (ts.fp.l_ui == 0)
1966                                         {
1967 #ifdef DEBUG
1968                                                 if (debug)
1969                                                 {
1970                                                         printf(
1971                                                                "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
1972                                                                rbufp->fd,
1973                                                                lfptoa(&tstmp, 6));
1974                                                         printf(" sigio %s\n",
1975                                                                lfptoa(&ts.fp, 6));
1976                                                 }
1977 #endif
1978                                                 parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
1979                                                 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
1980                                         }
1981                                 }
1982 #else /* TIOCDCDTIMESTAMP */
1983 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
1984                                 if (parse->flags & PARSE_PPSCLOCK)
1985                                 {
1986                                         l_fp tts;
1987                                         struct ppsclockev ev;
1988
1989 #ifdef HAVE_CIOGETEV
1990                                         if (ioctl(parse->generic->io.fd, CIOGETEV, (caddr_t)&ev) == 0)
1991 #endif
1992 #ifdef HAVE_TIOCGPPSEV
1993                                         if (ioctl(parse->generic->io.fd, TIOCGPPSEV, (caddr_t)&ev) == 0)
1994 #endif
1995                                         {
1996                                                 if (ev.serial != parse->ppsserial)
1997                                                 {
1998                                                         /*
1999                                                          * add PPS time stamp if available via ppsclock module
2000                                                          * and not supplied already.
2001                                                          */
2002                                                         if (!buftvtots((const char *)&ev.tv, &tts))
2003                                                         {
2004                                                                 ERR(ERR_BADDATA)
2005                                                                         msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2006                                                         }
2007                                                         else
2008                                                         {
2009                                                                 parse->parseio.parse_dtime.parse_ptime.fp = tts;
2010                                                                 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2011                                                         }
2012                                                 }
2013                                                 parse->ppsserial = ev.serial;
2014                                         }
2015                                 }
2016 #endif
2017 #endif /* TIOCDCDTIMESTAMP */
2018                         }
2019                         if (count)
2020                         {       /* simulate receive */
2021                                 memmove((caddr_t)buf.recv_buffer,
2022                                         (caddr_t)&parse->parseio.parse_dtime,
2023                                         sizeof(parsetime_t));
2024                                 parse_iodone(&parse->parseio);
2025                                 buf.recv_length = sizeof(parsetime_t);
2026                                 buf.recv_time = rbufp->recv_time;
2027                                 buf.srcadr = rbufp->srcadr;
2028                                 buf.dstadr = rbufp->dstadr;
2029                                 buf.fd     = rbufp->fd;
2030                                 buf.next = 0;
2031                                 buf.X_from_where = rbufp->X_from_where;
2032                                 rbufp->receiver(&buf);
2033                         }
2034                         else
2035                         {
2036                                 memmove((caddr_t)rbufp->recv_buffer,
2037                                         (caddr_t)&parse->parseio.parse_dtime,
2038                                         sizeof(parsetime_t));
2039                                 parse_iodone(&parse->parseio);
2040                                 rbufp->recv_length = sizeof(parsetime_t);
2041                                 return 1; /* got something & in place return */
2042                         }
2043                 }
2044         }
2045         return 0;               /* nothing to pass up */
2046 }
2047
2048 /*--------------------------------------------------
2049  * local receive
2050  */
2051 static void
2052 local_receive(
2053         struct recvbuf *rbufp
2054         )
2055 {
2056         struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2057         parsetime_t parsetime;
2058
2059         if (!parse->peer)
2060             return;
2061
2062         if (rbufp->recv_length != sizeof(parsetime_t))
2063         {
2064                 ERR(ERR_BADIO)
2065                         msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2066                                 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2067                 parse->generic->baddata++;
2068                 parse_event(parse, CEVNT_BADREPLY);
2069                 return;
2070         }
2071         clear_err(parse, ERR_BADIO);
2072   
2073         memmove((caddr_t)&parsetime,
2074                 (caddr_t)rbufp->recv_buffer,
2075                 sizeof(parsetime_t));
2076
2077 #ifdef DEBUG
2078         if (debug > 3)
2079           {
2080             printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
2081                    CLK_UNIT(parse->peer),
2082                    (unsigned int)parsetime.parse_status,
2083                    (unsigned int)parsetime.parse_state,
2084                    (long)parsetime.parse_time.tv.tv_sec,
2085                    (long)parsetime.parse_time.tv.tv_usec,
2086                    (long)parsetime.parse_stime.tv.tv_sec,
2087                    (long)parsetime.parse_stime.tv.tv_usec,
2088                    (long)parsetime.parse_ptime.tv.tv_sec,
2089                    (long)parsetime.parse_ptime.tv.tv_usec);
2090           }
2091 #endif
2092
2093         parse_process(parse, &parsetime);
2094 }
2095
2096 /*--------------------------------------------------
2097  * init_iobinding - find and initialize lower layers
2098  */
2099 static bind_t *
2100 init_iobinding(
2101         struct parseunit *parse
2102         )
2103 {
2104   bind_t *b = io_bindings;
2105
2106         while (b->bd_description != (char *)0)
2107         {
2108                 if ((*b->bd_init)(parse))
2109                 {
2110                         return b;
2111                 }
2112                 b++;
2113         }
2114         return (bind_t *)0;
2115 }
2116
2117 /**===========================================================================
2118  ** support routines
2119  **/
2120
2121 /*--------------------------------------------------
2122  * convert a flag field to a string
2123  */
2124 static char *
2125 parsestate(
2126         u_long lstate,
2127         char *buffer
2128         )
2129 {
2130         static struct bits
2131         {
2132                 u_long      bit;
2133                 const char *name;
2134         } flagstrings[] =
2135           {
2136                   { PARSEB_ANNOUNCE,   "DST SWITCH WARNING" },
2137                   { PARSEB_POWERUP,    "NOT SYNCHRONIZED" },
2138                   { PARSEB_NOSYNC,     "TIME CODE NOT CONFIRMED" },
2139                   { PARSEB_DST,        "DST" },
2140                   { PARSEB_UTC,        "UTC DISPLAY" },
2141                   { PARSEB_LEAPADD,    "LEAP ADD WARNING" },
2142                   { PARSEB_LEAPDEL,    "LEAP DELETE WARNING" },
2143                   { PARSEB_LEAPSECOND, "LEAP SECOND" },
2144                   { PARSEB_ALTERNATE,  "ALTERNATE ANTENNA" },
2145                   { PARSEB_TIMECODE,   "TIME CODE" },
2146                   { PARSEB_PPS,        "PPS" },
2147                   { PARSEB_POSITION,   "POSITION" },
2148                   { 0 }
2149           };
2150
2151         static struct sbits
2152         {
2153                 u_long      bit;
2154                 const char *name;
2155         } sflagstrings[] =
2156           {
2157                   { PARSEB_S_LEAP,     "LEAP INDICATION" },
2158                   { PARSEB_S_PPS,      "PPS SIGNAL" },
2159                   { PARSEB_S_ANTENNA,  "ANTENNA" },
2160                   { PARSEB_S_POSITION, "POSITION" },
2161                   { 0 }
2162           };
2163         int i;
2164
2165         *buffer = '\0';
2166
2167         i = 0;
2168         while (flagstrings[i].bit)
2169         {
2170                 if (flagstrings[i].bit & lstate)
2171                 {
2172                         if (buffer[0])
2173                             strcat(buffer, "; ");
2174                         strcat(buffer, flagstrings[i].name);
2175                 }
2176                 i++;
2177         }
2178
2179         if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2180         {
2181       char *s, *t;
2182
2183                 if (buffer[0])
2184                     strcat(buffer, "; ");
2185
2186                 strcat(buffer, "(");
2187
2188                 t = s = buffer + strlen(buffer);
2189
2190                 i = 0;
2191                 while (sflagstrings[i].bit)
2192                 {
2193                         if (sflagstrings[i].bit & lstate)
2194                         {
2195                                 if (t != s)
2196                                 {
2197                                         strcpy(t, "; ");
2198                                         t += 2;
2199                                 }
2200         
2201                                 strcpy(t, sflagstrings[i].name);
2202                                 t += strlen(t);
2203                         }
2204                         i++;
2205                 }
2206                 strcpy(t, ")");
2207         }
2208         return buffer;
2209 }
2210
2211 /*--------------------------------------------------
2212  * convert a status flag field to a string
2213  */
2214 static char *
2215 parsestatus(
2216         u_long lstate,
2217         char *buffer
2218         )
2219 {
2220         static struct bits
2221         {
2222                 u_long      bit;
2223                 const char *name;
2224         } flagstrings[] =
2225           {
2226                   { CVT_OK,      "CONVERSION SUCCESSFUL" },
2227                   { CVT_NONE,    "NO CONVERSION" },
2228                   { CVT_FAIL,    "CONVERSION FAILED" },
2229                   { CVT_BADFMT,  "ILLEGAL FORMAT" },
2230                   { CVT_BADDATE, "DATE ILLEGAL" },
2231                   { CVT_BADTIME, "TIME ILLEGAL" },
2232                   { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2233                   { 0 }
2234           };
2235         int i;
2236
2237         *buffer = '\0';
2238
2239         i = 0;
2240         while (flagstrings[i].bit)
2241         {
2242                 if (flagstrings[i].bit & lstate)
2243                 {
2244                         if (buffer[0])
2245                             strcat(buffer, "; ");
2246                         strcat(buffer, flagstrings[i].name);
2247                 }
2248                 i++;
2249         }
2250
2251         return buffer;
2252 }
2253
2254 /*--------------------------------------------------
2255  * convert a clock status flag field to a string
2256  */
2257 static const char *
2258 clockstatus(
2259         u_long lstate
2260         )
2261 {
2262         static char buffer[20];
2263         static struct status
2264         {
2265                 u_long      value;
2266                 const char *name;
2267         } flagstrings[] =
2268           {
2269                   { CEVNT_NOMINAL, "NOMINAL" },
2270                   { CEVNT_TIMEOUT, "NO RESPONSE" },
2271                   { CEVNT_BADREPLY,"BAD FORMAT" },
2272                   { CEVNT_FAULT,   "FAULT" },
2273                   { CEVNT_PROP,    "PROPAGATION DELAY" },
2274                   { CEVNT_BADDATE, "ILLEGAL DATE" },
2275                   { CEVNT_BADTIME, "ILLEGAL TIME" },
2276                   { (unsigned)~0L }
2277           };
2278         int i;
2279
2280         i = 0;
2281         while (flagstrings[i].value != ~0)
2282         {
2283                 if (flagstrings[i].value == lstate)
2284                 {
2285                         return flagstrings[i].name;
2286                 }
2287                 i++;
2288         }
2289
2290         sprintf(buffer, "unknown #%ld", (u_long)lstate);
2291
2292         return buffer;
2293 }
2294
2295
2296 /*--------------------------------------------------
2297  * l_mktime - make representation of a relative time
2298  */
2299 static char *
2300 l_mktime(
2301         u_long delta
2302         )
2303 {
2304         u_long tmp, m, s;
2305         static char buffer[40];
2306
2307         buffer[0] = '\0';
2308
2309         if ((tmp = delta / (60*60*24)) != 0)
2310         {
2311                 sprintf(buffer, "%ldd+", (u_long)tmp);
2312                 delta -= tmp * 60*60*24;
2313         }
2314
2315         s = delta % 60;
2316         delta /= 60;
2317         m = delta % 60;
2318         delta /= 60;
2319
2320         sprintf(buffer+strlen(buffer), "%02d:%02d:%02d",
2321                 (int)delta, (int)m, (int)s);
2322
2323         return buffer;
2324 }
2325
2326
2327 /*--------------------------------------------------
2328  * parse_statistics - list summary of clock states
2329  */
2330 static void
2331 parse_statistics(
2332         struct parseunit *parse
2333         )
2334 {
2335         int i;
2336
2337         NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2338                 {
2339                         msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2340                                 CLK_UNIT(parse->peer),
2341                                 l_mktime(current_time - parse->generic->timestarted));
2342
2343                         msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2344                                 CLK_UNIT(parse->peer),
2345                                 clockstatus(parse->generic->currentstatus));
2346
2347                         for (i = 0; i <= CEVNT_MAX; i++)
2348                         {
2349                                 u_long s_time;
2350                                 u_long percent, d = current_time - parse->generic->timestarted;
2351
2352                                 percent = s_time = PARSE_STATETIME(parse, i);
2353
2354                                 while (((u_long)(~0) / 10000) < percent)
2355                                 {
2356                                         percent /= 10;
2357                                         d       /= 10;
2358                                 }
2359
2360                                 if (d)
2361                                     percent = (percent * 10000) / d;
2362                                 else
2363                                     percent = 10000;
2364
2365                                 if (s_time)
2366                                     msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2367                                             CLK_UNIT(parse->peer),
2368                                             clockstatus((unsigned int)i),
2369                                             l_mktime(s_time),
2370                                             percent / 100, percent % 100);
2371                         }
2372                 }
2373 }
2374
2375 /*--------------------------------------------------
2376  * cparse_statistics - wrapper for statistics call
2377  */
2378 static void
2379 cparse_statistics(
2380         register struct parseunit *parse
2381         )
2382 {
2383         if (parse->laststatistic + PARSESTATISTICS < current_time)
2384                 parse_statistics(parse);
2385         parse->laststatistic = current_time;
2386 }
2387
2388 /**===========================================================================
2389  ** ntp interface routines
2390  **/
2391
2392 /*--------------------------------------------------
2393  * parse_init - initialize internal parse driver data
2394  */
2395 static void
2396 parse_init(void)
2397 {
2398         memset((caddr_t)parseunits, 0, sizeof parseunits);
2399 }
2400
2401
2402 /*--------------------------------------------------
2403  * parse_shutdown - shut down a PARSE clock
2404  */
2405 static void
2406 parse_shutdown(
2407         int unit,
2408         struct peer *peer
2409         )
2410 {
2411         struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
2412
2413         if (parse && !parse->peer)
2414         {
2415                 msyslog(LOG_ERR,
2416                         "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit);
2417                 return;
2418         }
2419
2420         /*
2421          * print statistics a last time and
2422          * stop statistics machine
2423          */
2424         parse_statistics(parse);
2425
2426         if (parse->parse_type->cl_end)
2427         {
2428                 parse->parse_type->cl_end(parse);
2429         }
2430         
2431         if (parse->binding)
2432             PARSE_END(parse);
2433
2434         /*
2435          * Tell the I/O module to turn us off.  We're history.
2436          */
2437         io_closeclock(&parse->generic->io);
2438
2439         free_varlist(parse->kv);
2440   
2441         NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2442                 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2443                         CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2444
2445         parse->peer = (struct peer *)0; /* unused now */
2446         free(parse);
2447 }
2448
2449 /*--------------------------------------------------
2450  * parse_start - open the PARSE devices and initialize data for processing
2451  */
2452 static int
2453 parse_start(
2454         int sysunit,
2455         struct peer *peer
2456         )
2457 {
2458         u_int unit;
2459         int fd232;
2460 #ifdef HAVE_TERMIOS
2461         struct termios tio;             /* NEEDED FOR A LONG TIME ! */
2462 #endif
2463 #ifdef HAVE_SYSV_TTYS
2464         struct termio tio;              /* NEEDED FOR A LONG TIME ! */
2465 #endif
2466         struct parseunit * parse;
2467         char parsedev[sizeof(PARSEDEVICE)+20];
2468         parsectl_t tmp_ctl;
2469         u_int type;
2470
2471         type = CLK_TYPE(peer);
2472         unit = CLK_UNIT(peer);
2473
2474         if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
2475         {
2476                 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2477                         unit, CLK_REALTYPE(peer), ncltypes-1);
2478                 return 0;
2479         }
2480
2481         /*
2482          * Unit okay, attempt to open the device.
2483          */
2484         (void) sprintf(parsedev, PARSEDEVICE, unit);
2485
2486 #ifndef O_NOCTTY
2487 #define O_NOCTTY 0
2488 #endif
2489
2490         fd232 = open(parsedev, O_RDWR | O_NOCTTY
2491 #ifdef O_NONBLOCK
2492                      | O_NONBLOCK
2493 #endif
2494                      , 0777);
2495
2496         if (fd232 == -1)
2497         {
2498                 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2499                 return 0;
2500         }
2501
2502         parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2503
2504         memset((char *)parse, 0, sizeof(struct parseunit));
2505
2506         parse->generic = peer->procptr;  /* link up */
2507         parse->generic->unitptr = (caddr_t)parse; /* link down */
2508
2509         /*
2510          * Set up the structures
2511          */
2512         parse->generic->timestarted    = current_time;
2513         parse->lastchange     = current_time;
2514
2515         parse->generic->currentstatus           = CEVNT_TIMEOUT; /* expect the worst */
2516
2517         parse->flags          = 0;
2518         parse->pollneeddata   = 0;
2519         parse->laststatistic  = current_time;
2520         parse->lastformat     = (unsigned short)~0;     /* assume no format known */
2521         parse->time.parse_status = (unsigned short)~0;  /* be sure to mark initial status change */
2522         parse->lastmissed     = 0;      /* assume got everything */
2523         parse->ppsserial      = 0;
2524         parse->localdata      = (void *)0;
2525         parse->localstate     = 0;
2526         parse->kv             = (struct ctl_var *)0;
2527
2528         clear_err(parse, ERR_ALL);
2529   
2530         parse->parse_type     = &parse_clockinfo[type];
2531         
2532         parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
2533
2534         parse->generic->fudgetime2 = 0.0;
2535
2536         parse->generic->clockdesc = parse->parse_type->cl_description;
2537
2538         peer->rootdelay       = parse->parse_type->cl_rootdelay;
2539         peer->sstclktype      = parse->parse_type->cl_type;
2540         peer->precision       = sys_precision;
2541         
2542         peer->stratum         = STRATUM_REFCLOCK;
2543         if (peer->stratum <= 1)
2544             memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
2545         else
2546             parse->generic->refid = htonl(PARSEHSREFID);
2547         
2548         parse->generic->io.fd = fd232;
2549         
2550         parse->peer = peer;             /* marks it also as busy */
2551
2552         /*
2553          * configure terminal line
2554          */
2555         if (TTY_GETATTR(fd232, &tio) == -1)
2556         {
2557                 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
2558                 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2559                 return 0;
2560         }
2561         else
2562         {
2563 #ifndef _PC_VDISABLE
2564                 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
2565 #else
2566                 int disablec;
2567                 errno = 0;              /* pathconf can deliver -1 without changing errno ! */
2568
2569                 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
2570                 if (disablec == -1 && errno)
2571                 {
2572                         msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
2573                         memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
2574                 }
2575                 else
2576                     if (disablec != -1)
2577                         memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
2578 #endif
2579
2580 #if defined (VMIN) || defined(VTIME)
2581                 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
2582                 {
2583 #ifdef VMIN
2584                         tio.c_cc[VMIN]   = 1;
2585 #endif
2586 #ifdef VTIME
2587                         tio.c_cc[VTIME]  = 0;
2588 #endif
2589                 }
2590 #endif
2591
2592                 tio.c_cflag = parse_clockinfo[type].cl_cflag;
2593                 tio.c_iflag = parse_clockinfo[type].cl_iflag;
2594                 tio.c_oflag = parse_clockinfo[type].cl_oflag;
2595                 tio.c_lflag = parse_clockinfo[type].cl_lflag;
2596         
2597
2598 #ifdef HAVE_TERMIOS
2599                 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
2600                     (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
2601                 {
2602                         msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
2603                         parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2604                         return 0;
2605                 }
2606 #else
2607                 tio.c_cflag     |= parse_clockinfo[type].cl_speed;
2608 #endif
2609
2610 #if defined(HAVE_TIO_SERIAL_STUFF)              /* Linux hack: define PPS interface */
2611                 {
2612                   struct serial_struct  ss;
2613                   if (ioctl(fd232, TIOCGSERIAL, &ss) < 0 ||
2614                       (
2615 #ifdef ASYNC_LOW_LATENCY
2616                        ss.flags |= ASYNC_LOW_LATENCY,
2617 #endif
2618 #ifdef ASYNC_PPS_CD_NEG
2619                        ss.flags |= ASYNC_PPS_CD_NEG,
2620 #endif
2621                        ioctl(fd232, TIOCSSERIAL, &ss)) < 0) {
2622                     msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", fd232);
2623                     msyslog(LOG_NOTICE,
2624                             "refclock_parse: optional PPS processing not available");
2625                   } else {
2626                     parse->flags    |= PARSE_PPSCLOCK;
2627                     msyslog(LOG_INFO,
2628                             "refclock_parse: PPS detection on");
2629                   }
2630                 }
2631 #endif
2632 #ifdef HAVE_TIOCSPPS                    /* SUN PPS support */
2633                 if (CLK_PPS(parse->peer))
2634                   {
2635                     int i = 1;
2636                     
2637                     if (ioctl(fd232, TIOCSPPS, (caddr_t)&i) == 0)
2638                       {
2639                         parse->flags |= PARSE_PPSCLOCK;
2640                       }
2641                   }
2642 #endif
2643
2644                 if (TTY_SETATTR(fd232, &tio) == -1)
2645                 {
2646                         msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
2647                         parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2648                         return 0;
2649                 }
2650         }
2651
2652         /*
2653          * Insert in async io device list.
2654          */
2655         parse->generic->io.srcclock = (caddr_t)parse;
2656         parse->generic->io.datalen = 0;
2657         
2658         if (!io_addclock(&parse->generic->io))
2659         {
2660                 msyslog(LOG_ERR,
2661                         "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
2662                 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2663                 return 0;
2664         }
2665
2666         parse->binding = init_iobinding(parse);
2667         parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
2668         parse->generic->io.io_input   = parse->binding->bd_io_input; /* pick correct input routine */
2669
2670         if (parse->binding == (bind_t *)0)
2671                 {
2672                         msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
2673                         parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2674                         return 0;                       /* well, ok - special initialisation broke */
2675                 }      
2676
2677         /*
2678          * as we always(?) get 8 bit chars we want to be
2679          * sure, that the upper bits are zero for less
2680          * than 8 bit I/O - so we pass that information on.
2681          * note that there can be only one bit count format
2682          * per file descriptor
2683          */
2684
2685         switch (tio.c_cflag & CSIZE)
2686         {
2687             case CS5:
2688                 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
2689                 break;
2690
2691             case CS6:
2692                 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
2693                 break;
2694
2695             case CS7:
2696                 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
2697                 break;
2698
2699             case CS8:
2700                 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
2701                 break;
2702         }
2703
2704         if (!PARSE_SETCS(parse, &tmp_ctl))
2705         {
2706                 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
2707                 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2708                 return 0;                       /* well, ok - special initialisation broke */
2709         }
2710   
2711         strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format);
2712         tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
2713
2714         if (!PARSE_SETFMT(parse, &tmp_ctl))
2715         {
2716                 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
2717                 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2718                 return 0;                       /* well, ok - special initialisation broke */
2719         }
2720   
2721         /*
2722          * get rid of all IO accumulated so far
2723          */
2724 #ifdef HAVE_TERMIOS
2725         (void) tcflush(parse->generic->io.fd, TCIOFLUSH);
2726 #else
2727 #ifdef TCFLSH
2728         {
2729 #ifndef TCIOFLUSH
2730 #define TCIOFLUSH 2
2731 #endif
2732                 int flshcmd = TCIOFLUSH;
2733
2734                 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
2735         }
2736 #endif
2737 #endif
2738
2739         /*
2740          * try to do any special initializations
2741          */
2742         if (parse->parse_type->cl_init)
2743                 {
2744                         if (parse->parse_type->cl_init(parse))
2745                                 {
2746                                         parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2747                                         return 0;               /* well, ok - special initialisation broke */
2748                                 }
2749                 }
2750         
2751         /*
2752          * get out Copyright information once
2753          */
2754         if (!notice)
2755         {
2756                 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2757                         msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1999, Frank Kardel");
2758                 notice = 1;
2759         }
2760
2761         /*
2762          * print out configuration
2763          */
2764         NLOG(NLOG_CLOCKINFO)
2765                 {
2766                         /* conditional if clause for conditional syslog */
2767                         msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added",
2768                                 CLK_UNIT(parse->peer),
2769                                 parse->parse_type->cl_description, parsedev);
2770
2771                         msyslog(LOG_INFO, "PARSE receiver #%d:  Stratum %d, %sPPS support, trust time %s, precision %d",
2772                                 CLK_UNIT(parse->peer),
2773                                 parse->peer->stratum, CLK_PPS(parse->peer) ? "" : "no ",
2774                                 l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision);
2775
2776                         msyslog(LOG_INFO, "PARSE receiver #%d:  rootdelay %.6f s, phaseadjust %.6f s, %s IO handling",
2777                                 CLK_UNIT(parse->peer),
2778                                 parse->parse_type->cl_rootdelay,
2779                                 parse->generic->fudgetime1,
2780                                 parse->binding->bd_description);
2781
2782                         msyslog(LOG_INFO, "PARSE receiver #%d:  Format recognition: %s", CLK_UNIT(parse->peer),
2783                                 parse->parse_type->cl_format);
2784 #ifdef PPS
2785                         msyslog(LOG_INFO, "PARSE receiver #%d:  %sPPS ioctl support", CLK_UNIT(parse->peer),
2786                                 (parse->flags & PARSE_PPSCLOCK) ? "" : "NO ");
2787 #endif
2788                 }
2789
2790         return 1;
2791 }
2792
2793 /*--------------------------------------------------
2794  * parse_poll - called by the transmit procedure
2795  */
2796 static void
2797 parse_poll(
2798         int unit,
2799         struct peer *peer
2800         )
2801 {
2802         struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
2803
2804         if (peer != parse->peer)
2805         {
2806                 msyslog(LOG_ERR,
2807                         "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
2808                         unit);
2809                 return;
2810         }
2811
2812         /*
2813          * Update clock stat counters
2814          */
2815         parse->generic->polls++;
2816
2817         if (parse->pollneeddata && 
2818             ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
2819         {
2820                 /*
2821                  * start worrying when exceeding a poll inteval
2822                  * bad news - didn't get a response last time
2823                  */
2824                 parse->generic->noreply++;
2825                 parse->lastmissed = current_time;
2826                 parse_event(parse, CEVNT_TIMEOUT);
2827                 
2828                 ERR(ERR_NODATA)
2829                         msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / cableling)", CLK_UNIT(parse->peer));
2830         }
2831
2832         /*
2833          * we just mark that we want the next sample for the clock filter
2834          */
2835         parse->pollneeddata = current_time;
2836
2837         if (parse->parse_type->cl_poll)
2838         {
2839                 parse->parse_type->cl_poll(parse);
2840         }
2841
2842         cparse_statistics(parse);
2843
2844         return;
2845 }
2846
2847 #define LEN_STATES 300          /* length of state string */
2848
2849 /*--------------------------------------------------
2850  * parse_control - set fudge factors, return statistics
2851  */
2852 static void
2853 parse_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  */
3066 static void
3067 parse_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  */
3118 static void
3119 parse_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 \f
3539 /**===========================================================================
3540  ** special code for special clocks
3541  **/
3542
3543 static void
3544 mk_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  */
3587 static void
3588 gps16x_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  */
3978 static void
3979 gps16x_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  */
4056 static int
4057 gps16x_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
4071 static void
4072 gps16x_message(
4073                struct parseunit *parse,
4074                parsetime_t      *parsetime
4075                )
4076 {}
4077 static int
4078 gps16x_poll_init(
4079         struct parseunit *parse
4080         )
4081 {
4082         return 1;
4083 }
4084 #endif /* CLOCK_MEINBERG */
4085 \f
4086 /**===========================================================================
4087  ** clock polling support
4088  **/
4089
4090 /*--------------------------------------------------
4091  * direct poll routine
4092  */
4093 static void
4094 poll_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  */
4120 static void
4121 poll_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  */
4139 static int
4140 poll_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 \f
4153 /**===========================================================================
4154  ** Trimble support
4155  **/
4156
4157 /*-------------------------------------------------------------
4158  * trimble TAIP init routine - setup EOL and then do poll_init.
4159  */
4160 static int
4161 trimbletaip_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  */
4195 static 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       
4202 static void
4203 trimbletaip_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
4331 typedef 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
4339 union uval {
4340         u_char  bd[8];
4341         int     iv;
4342         float   fv;
4343         double  dv;
4344 };
4345   
4346 struct txbuf
4347 {
4348         short idx;                      /* index to first unused byte */
4349         u_char *txt;                    /* pointer to actual data buffer */
4350 };
4351
4352 void    sendcmd         P((struct txbuf *buf, int c)); 
4353 void    sendbyte        P((struct txbuf *buf, int b)); 
4354 void    sendetx         P((struct txbuf *buf, struct parseunit *parse)); 
4355 void    sendint         P((struct txbuf *buf, int a)); 
4356 void    sendflt         P((struct txbuf *buf, double a)); 
4357  
4358 void
4359 sendcmd(
4360         struct txbuf *buf,
4361         int c
4362         )
4363 {
4364         buf->txt[0] = DLE;
4365         buf->txt[1] = (u_char)c;
4366         buf->idx = 2;
4367 }
4368
4369 void
4370 sendbyte(
4371         struct txbuf *buf,
4372         int b
4373         )
4374 {
4375         if (b == DLE)
4376             buf->txt[buf->idx++] = DLE;
4377         buf->txt[buf->idx++] = (u_char)b;
4378 }
4379
4380 void
4381 sendetx(
4382         struct txbuf *buf,
4383         struct parseunit *parse
4384         )
4385 {
4386         buf->txt[buf->idx++] = DLE;
4387         buf->txt[buf->idx++] = ETX;
4388
4389         if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
4390         {
4391                 ERR(ERR_BADIO)
4392                         msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4393         }
4394         else
4395         {
4396 #ifdef DEBUG
4397           if (debug > 2)
4398           {
4399                   char buffer[256];
4400                   
4401                   mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
4402                   printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4403                          CLK_UNIT(parse->peer),
4404                          buf->idx, buffer); 
4405           }
4406 #endif
4407                 clear_err(parse, ERR_BADIO);
4408         }
4409 }
4410
4411 void  
4412 sendint(
4413         struct txbuf *buf,
4414         int a
4415         )
4416 {
4417         /* send 16bit int, msbyte first */
4418         sendbyte(buf, (u_char)((a>>8) & 0xff));
4419         sendbyte(buf, (u_char)(a & 0xff));
4420 }
4421
4422 void
4423 sendflt(
4424         struct txbuf *buf,
4425         double a
4426         )
4427 {
4428         int i;
4429         union uval uval;
4430
4431         uval.fv = a;
4432 #ifdef WORDS_BIGENDIAN
4433         for (i=0; i<=3; i++)
4434 #else
4435             for (i=3; i>=0; i--)
4436 #endif
4437                 sendbyte(buf, uval.bd[i]);
4438 }
4439
4440 #define TRIM_POS_OPT    0x13    /* output position with high precision */
4441 #define TRIM_TIME_OPT   0x03    /* use UTC time stamps, on second */
4442
4443 /*--------------------------------------------------
4444  * trimble TSIP setup routine
4445  */
4446 static int
4447 trimbletsip_setup(
4448                   struct parseunit *parse,
4449                   const char *reason
4450                   )
4451 {
4452         u_char buffer[256];
4453         struct txbuf buf;
4454
4455         buf.txt = buffer;
4456   
4457         sendcmd(&buf, CMD_CVERSION);    /* request software versions */
4458         sendetx(&buf, parse);
4459         
4460         sendcmd(&buf, CMD_COPERPARAM);  /* set operating parameters */
4461         sendbyte(&buf, 4);      /* static */
4462         sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
4463         sendflt(&buf, 4.0);     /* s/n ratio mask = 6 XXX */
4464         sendflt(&buf, 12.0);    /* PDOP mask = 12 */
4465         sendflt(&buf, 8.0);     /* PDOP switch level = 8 */
4466         sendetx(&buf, parse);
4467         
4468         sendcmd(&buf, CMD_CMODESEL);    /* fix mode select */
4469         sendbyte(&buf, 0);      /* automatic */
4470         sendetx(&buf, parse);
4471         
4472         sendcmd(&buf, CMD_CMESSAGE);    /* request system message */
4473         sendetx(&buf, parse);
4474         
4475         sendcmd(&buf, CMD_CSUPER);      /* superpacket fix */
4476         sendbyte(&buf, 0x2);    /* binary mode */
4477         sendetx(&buf, parse);
4478         
4479         sendcmd(&buf, CMD_CIOOPTIONS);  /* set I/O options */
4480         sendbyte(&buf, TRIM_POS_OPT);   /* position output */
4481         sendbyte(&buf, 0x00);   /* no velocity output */
4482         sendbyte(&buf, TRIM_TIME_OPT);  /* UTC, compute on seconds */
4483         sendbyte(&buf, 0x00);   /* no raw measurements */
4484         sendetx(&buf, parse);
4485         
4486         sendcmd(&buf, CMD_CUTCPARAM);   /* request UTC correction data */
4487         sendetx(&buf, parse);
4488
4489         NLOG(NLOG_CLOCKINFO)
4490                 ERR(ERR_BADIO)
4491                 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
4492
4493         return 0;
4494 }
4495
4496 /*--------------------------------------------------
4497  * TRIMBLE TSIP check routine
4498  */
4499 static void
4500 trimble_check(
4501               struct peer *peer
4502               )
4503 {
4504         struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4505         trimble_t *t = parse->localdata;
4506         u_char buffer[256];
4507         struct txbuf buf;
4508         buf.txt = buffer;
4509         
4510         if (t)
4511         {
4512                 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
4513                         (void)trimbletsip_setup(parse, "message timeout");
4514         }
4515         poll_poll(parse->peer); /* emit query string and re-arm timer */
4516         
4517         if (t->qtracking)
4518         {
4519                 u_long oldsats = t->ltrack & ~t->ctrack;
4520                 
4521                 t->qtracking = 0;
4522                 t->ltrack = t->ctrack;
4523                 
4524                 if (oldsats)
4525                 {
4526                         int i;
4527                                 
4528                         for (i = 0; oldsats; i++)
4529                                 if (oldsats & (1 << i))
4530                                         {
4531                                                 sendcmd(&buf, CMD_CSTATTRACK);
4532                                                 sendbyte(&buf, i+1);    /* old sat */
4533                                                 sendetx(&buf, parse);
4534                                         }
4535                         oldsats &= ~(1 << i);
4536                 }
4537                                                 
4538                 sendcmd(&buf, CMD_CSTATTRACK);
4539                 sendbyte(&buf, 0x00);   /* current tracking set */
4540                 sendetx(&buf, parse);
4541         }
4542 }
4543
4544 /*--------------------------------------------------
4545  * TRIMBLE TSIP end routine
4546  */
4547 static void
4548 trimbletsip_end(
4549               struct parseunit *parse
4550               )
4551 {       trimble_t *t = parse->localdata;
4552         
4553         if (t)
4554         {
4555                 free(t);
4556                 parse->localdata = (void *)0;
4557         }
4558         parse->peer->nextaction = 0;
4559         parse->peer->action = (void (*) P((struct peer *)))0;
4560 }
4561
4562 /*--------------------------------------------------
4563  * TRIMBLE TSIP init routine
4564  */
4565 static int
4566 trimbletsip_init(
4567         struct parseunit *parse
4568         )
4569 {
4570 #if defined(VEOL) || defined(VEOL2)
4571 #ifdef HAVE_TERMIOS
4572         struct termios tio;             /* NEEDED FOR A LONG TIME ! */
4573 #endif
4574 #ifdef HAVE_SYSV_TTYS
4575         struct termio tio;              /* NEEDED FOR A LONG TIME ! */
4576 #endif
4577         /*
4578          * allocate local data area
4579          */
4580         if (!parse->localdata)
4581         {
4582                 trimble_t *t;
4583                 
4584                 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
4585                 
4586                 if (t)
4587                 {
4588                         memset((char *)t, 0, sizeof(trimble_t));
4589                         t->last_msg = current_time;
4590                 }
4591         }
4592
4593         parse->peer->action     = trimble_check;
4594         parse->peer->nextaction = current_time;
4595
4596         /*
4597          * configure terminal line for ICANON mode with VEOL characters
4598          */
4599         if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4600         {
4601                 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
4602                 return 0;
4603         }
4604         else
4605         {
4606                 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
4607                 {
4608 #ifdef VEOL
4609                         tio.c_cc[VEOL]  = ETX;
4610 #endif
4611 #ifdef VEOL2
4612                         tio.c_cc[VEOL2]  = DLE;
4613 #endif
4614                 }
4615
4616                 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4617                 {
4618                         msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
4619                         return 0;
4620                 }
4621         }
4622 #endif
4623         return trimbletsip_setup(parse, "initial startup");
4624 }
4625
4626 /*------------------------------------------------------------
4627  * trimbletsip_event - handle Trimble events
4628  * simple evente handler - attempt to re-initialize receiver
4629  */
4630 static void
4631 trimbletsip_event(
4632         struct parseunit *parse,
4633         int event
4634         )
4635 {
4636         switch (event)
4637         {
4638             case CEVNT_BADREPLY:        /* reset on garbled input */
4639             case CEVNT_TIMEOUT:         /* reset on no input */
4640                     (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
4641                     break;
4642
4643             default:                    /* ignore */
4644                 break;
4645         }
4646 }
4647
4648 /*
4649  * getflt, getint convert fields in the incoming data into the
4650  * appropriate type of item
4651  *
4652  * CAVEAT: these routines are currently definitely byte order dependent
4653  * and assume Representation(float) == IEEE754
4654  * These functions MUST be converted to portable versions (especially
4655  * converting the float representation into ntp_fp formats in order
4656  * to avoid floating point operations at all!
4657  */
4658
4659 static float
4660 getflt(
4661         u_char *bp
4662         )
4663 {
4664         union uval uval;
4665         
4666 #ifdef WORDS_BIGENDIAN
4667         uval.bd[0] = *bp++;
4668         uval.bd[1] = *bp++;
4669         uval.bd[2] = *bp++;
4670         uval.bd[3] = *bp;
4671 #else  /* ! WORDS_BIGENDIAN */
4672         uval.bd[3] = *bp++;
4673         uval.bd[2] = *bp++;
4674         uval.bd[1] = *bp++;
4675         uval.bd[0] = *bp;
4676 #endif /* ! WORDS_BIGENDIAN */
4677         return uval.fv;
4678 }
4679
4680 static double
4681 getdbl(
4682         u_char *bp
4683         )
4684 {
4685         union uval uval;
4686         
4687 #ifdef WORDS_BIGENDIAN
4688         uval.bd[0] = *bp++;
4689         uval.bd[1] = *bp++;
4690         uval.bd[2] = *bp++;
4691         uval.bd[3] = *bp++;
4692         uval.bd[4] = *bp++;
4693         uval.bd[5] = *bp++;
4694         uval.bd[6] = *bp++;
4695         uval.bd[7] = *bp;
4696 #else  /* ! WORDS_BIGENDIAN */
4697         uval.bd[7] = *bp++;
4698         uval.bd[6] = *bp++;
4699         uval.bd[5] = *bp++;
4700         uval.bd[4] = *bp++;
4701         uval.bd[3] = *bp++;
4702         uval.bd[2] = *bp++;
4703         uval.bd[1] = *bp++;
4704         uval.bd[0] = *bp;
4705 #endif /* ! WORDS_BIGENDIAN */
4706         return uval.dv;
4707 }
4708
4709 static int
4710 getshort(
4711          unsigned char *p
4712          )
4713 {
4714         return get_msb_short(&p);
4715 }
4716
4717 /*--------------------------------------------------
4718  * trimbletsip_message - process trimble messages
4719  */
4720 #define RTOD (180.0 / 3.1415926535898)
4721 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
4722
4723 static void
4724 trimbletsip_message(
4725                     struct parseunit *parse,
4726                     parsetime_t      *parsetime
4727                     )
4728 {
4729         unsigned char *buffer = parsetime->parse_msg;
4730         unsigned int   size   = parsetime->parse_msglen;
4731         
4732         if ((size < 4) ||
4733             (buffer[0]      != DLE) ||
4734             (buffer[size-1] != ETX) ||
4735             (buffer[size-2] != DLE))
4736         {
4737 #ifdef DEBUG
4738                 if (debug > 2) {
4739                         int i;
4740
4741                         printf("TRIMBLE BAD packet, size %d:\n  ", size);
4742                         for (i = 0; i < size; i++) {
4743                                 printf ("%2.2x, ", buffer[i]&0xff);
4744                                 if (i%16 == 15) printf("\n\t");
4745                         }
4746                         printf("\n");
4747                 }
4748 #endif
4749                 return;
4750         }
4751         else
4752         {
4753                 int var_flag;
4754                 trimble_t *tr = parse->localdata;
4755                 unsigned int cmd = buffer[1];
4756                 char pbuffer[200];
4757                 char *t = pbuffer;
4758                 cmd_info_t *s;
4759                 
4760 #ifdef DEBUG
4761                 if (debug > 3) {
4762                         int i;
4763
4764                         printf("TRIMBLE packet 0x%02x, size %d:\n       ", cmd, size);
4765                         for (i = 0; i < size; i++) {
4766                                 printf ("%2.2x, ", buffer[i]&0xff);
4767                                 if (i%16 == 15) printf("\n\t");
4768                         }
4769                         printf("\n");
4770                 }
4771 #endif
4772
4773                 if (tr)
4774                         tr->last_msg = current_time;
4775                 
4776                 s = trimble_convert(cmd, trimble_rcmds);
4777                 
4778                 if (s)
4779                 {
4780                         sprintf(t, "%s=\"", s->varname);
4781                 }
4782                 else
4783                 {
4784                         printf("TRIMBLE unknown command 0x%02x\n", cmd);
4785                         return;
4786                 }
4787
4788                 var_flag = s->varmode;
4789
4790                 t += strlen(t);
4791                 
4792                 switch(cmd)
4793                 {
4794                 case CMD_RCURTIME:
4795                         sprintf(t, "%f, %d, %f",
4796                                 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
4797                                 getflt((unsigned char *)&mb(6)));
4798                         break;
4799                         
4800                 case CMD_RBEST4:
4801                         strcpy(t, "mode: ");
4802                         t += strlen(t);
4803                         switch (mb(0) & 0xF)
4804                         {
4805                         default:
4806                                 sprintf(t, "0x%x", mb(0) & 0x7);
4807                                 break;
4808
4809                         case 1:
4810                                 strcat(t, "0D");
4811                                 break;
4812                                 
4813                         case 3:
4814                                 strcat(t, "2D");
4815                                 break;
4816                                 
4817                         case 4:
4818                                 strcat(t, "3D");
4819                                 break;
4820                         }
4821                         t += strlen(t);
4822                         if (mb(0) & 0x10)
4823                                 strcpy(t, "-MANUAL, ");
4824                         else
4825                                 strcpy(t, "-AUTO, ");
4826                         t += strlen(t);
4827                         
4828                         sprintf(t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
4829                                 mb(1), mb(2), mb(3), mb(4),
4830                                 getflt((unsigned char *)&mb(5)),
4831                                 getflt((unsigned char *)&mb(9)),
4832                                 getflt((unsigned char *)&mb(13)),
4833                                 getflt((unsigned char *)&mb(17)));
4834
4835                         break;
4836                         
4837                 case CMD_RVERSION:
4838                         sprintf(t, "%d.%d (%d/%d/%d)",
4839                                 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
4840                         break;
4841                         
4842                 case CMD_RRECVHEALTH:
4843                 {
4844                         static const char *msgs[] =
4845                         {
4846                                 "Battery backup failed",
4847                                 "Signal processor error",
4848                                 "Alignment error, channel or chip 1",
4849                                 "Alignment error, channel or chip 2",
4850                                 "Antenna feed line fault",
4851                                 "Excessive ref freq. error",
4852                                 "<BIT 6>",
4853                                 "<BIT 7>"
4854                         };
4855                         
4856                         int i, bits;
4857                         
4858                         switch (mb(0) & 0xFF)
4859                         {
4860                         default:
4861                                 sprintf(t, "illegal value 0x%02x", mb(0) & 0xFF);
4862                                 break;
4863                         case 0x00:
4864                                 strcpy(t, "doing position fixes");
4865                                 break;
4866                         case 0x01:
4867                                 strcpy(t, "no GPS time yet");
4868                                 break;
4869                         case 0x03:
4870                                 strcpy(t, "PDOP too high");
4871                                 break;
4872                         case 0x08:
4873                                 strcpy(t, "no usable satellites");
4874                                 break;
4875                         case 0x09:
4876                                 strcpy(t, "only ONE usable satellite");
4877                                 break;
4878                         case 0x0A:
4879                                 strcpy(t, "only TWO usable satellites");
4880                                 break;
4881                         case 0x0B:
4882                                 strcpy(t, "only THREE usable satellites");
4883                                 break;
4884                         case 0x0C:
4885                                 strcpy(t, "the chosen satellite is unusable");
4886                                 break;
4887                         }
4888
4889                         t += strlen(t);
4890
4891                         bits = mb(1) & 0xFF;
4892                         
4893                         for (i = 0; i < 8; i++)
4894                                 if (bits & (0x1<<i))
4895                                 {
4896                                         sprintf(t, ", %s", msgs[i]);
4897                                         t += strlen(t);
4898                                 }
4899                 }
4900                 break;
4901                         
4902                 case CMD_RMESSAGE:
4903                         mkreadable(t, (int)(sizeof(pbuffer) - (t - pbuffer)), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
4904                         break;
4905                         
4906                 case CMD_RMACHSTAT:
4907                 {
4908                         static const char *msgs[] =
4909                         {
4910                                 "Synthesizer Fault",
4911                                 "Battery Powered Time Clock Fault",
4912                                 "A-to-D Converter Fault",
4913                                 "The almanac stored in the receiver is not complete and current",
4914                                 "<BIT 4>",
4915                                 "<BIT 5",
4916                                 "<BIT 6>",
4917                                 "<BIT 7>"
4918                         };
4919                         
4920                         int i, bits;
4921
4922                         sprintf(t, "machine id 0x%02x", mb(0) & 0xFF);
4923                         t += strlen(t);
4924                         
4925                         bits = mb(1) & 0xFF;
4926                         
4927                         for (i = 0; i < 8; i++)
4928                                 if (bits & (0x1<<i))
4929                                 {
4930                                         sprintf(t, ", %s", msgs[i]);
4931                                         t += strlen(t);
4932                                 }
4933
4934                         sprintf(t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
4935                 }
4936                 break;
4937                         
4938                 case CMD_ROPERPARAM:
4939                         sprintf(t, "%2x %.1f %.1f %.1f %.1f",
4940                                 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
4941                                 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
4942                         break;
4943                         
4944                 case CMD_RUTCPARAM:
4945                 {
4946                         float t0t = getflt((unsigned char *)&mb(14));
4947                         short wnt = getshort((unsigned char *)&mb(18));
4948                         short dtls = getshort((unsigned char *)&mb(12));
4949                         short wnlsf = getshort((unsigned char *)&mb(20));
4950                         short dn = getshort((unsigned char *)&mb(22));
4951                         short dtlsf = getshort((unsigned char *)&mb(24));
4952
4953                         if ((int)t0t != 0)
4954                           {
4955                             mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf);
4956                           }
4957                         else
4958                           {
4959                             strcpy(t, "<NO UTC DATA>");
4960                           }
4961                 }
4962                 break;
4963
4964                 case CMD_RSAT1BIAS:
4965                         sprintf(t, "%.1fm %.2fm/s at %.1fs",
4966                                 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
4967                         break;
4968
4969                 case CMD_RIOOPTIONS:
4970                 {
4971                         sprintf(t, "%02x %02x %02x %02x",
4972                                 mb(0), mb(1), mb(2), mb(3));
4973                         if (mb(0) != TRIM_POS_OPT ||
4974                             mb(2) != TRIM_TIME_OPT)
4975                         {
4976                                 (void)trimbletsip_setup(parse, "bad io options");
4977                         }
4978                 }
4979                 break;
4980                 
4981                 case CMD_RSPOSXYZ:
4982                 {
4983                         double x = getflt((unsigned char *)&mb(0));
4984                         double y = getflt((unsigned char *)&mb(4));
4985                         double z = getflt((unsigned char *)&mb(8));
4986                         double f = getflt((unsigned char *)&mb(12));
4987                         
4988                         if (f > 0.0)
4989                           sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
4990                                   x, y, z,
4991                                   f);
4992                         else
4993                           return;
4994                 }
4995                 break;
4996
4997                 case CMD_RSLLAPOS:
4998                 {
4999                         double lat = getflt((unsigned char *)&mb(0));
5000                         double lng = getflt((unsigned char *)&mb(4));
5001                         double f   = getflt((unsigned char *)&mb(12));
5002                         
5003                         if (f > 0.0)
5004                           sprintf(t, "lat %f %c, long %f %c, alt %.2fm",
5005                                   ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5006                                   ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5007                                   getflt((unsigned char *)&mb(8)));
5008                         else
5009                           return;
5010                 }
5011                 break;
5012
5013                 case CMD_RDOUBLEXYZ:
5014                 {
5015                         double x = getdbl((unsigned char *)&mb(0));
5016                         double y = getdbl((unsigned char *)&mb(8));
5017                         double z = getdbl((unsigned char *)&mb(16));
5018                         sprintf(t, "x= %.1fm, y= %.1fm, z= %.1fm",
5019                                 x, y, z);
5020                 }
5021                 break;
5022                                 
5023                 case CMD_RDOUBLELLA:
5024                 {
5025                         double lat = getdbl((unsigned char *)&mb(0));
5026                         double lng = getdbl((unsigned char *)&mb(8));
5027                         sprintf(t, "lat %f %c, lon %f %c, alt %.2fm",
5028                                 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5029                                 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5030                                 getdbl((unsigned char *)&mb(16)));
5031                 }
5032                 break;
5033
5034                 case CMD_RALLINVIEW:
5035                 {
5036                         int i, sats;
5037                         
5038                         strcpy(t, "mode: ");
5039                         t += strlen(t);
5040                         switch (mb(0) & 0x7)
5041                         {
5042                         default:
5043                                 sprintf(t, "0x%x", mb(0) & 0x7);
5044                                 break;
5045
5046                         case 3:
5047                                 strcat(t, "2D");
5048                                 break;
5049                                 
5050                         case 4:
5051                                 strcat(t, "3D");
5052                                 break;
5053                         }
5054                         t += strlen(t);
5055                         if (mb(0) & 0x8)
5056                                 strcpy(t, "-MANUAL, ");
5057                         else
5058                                 strcpy(t, "-AUTO, ");
5059                         t += strlen(t);
5060                         
5061                         sats = (mb(0)>>4) & 0xF;
5062                         
5063                         sprintf(t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5064                                 getflt((unsigned char *)&mb(1)),
5065                                 getflt((unsigned char *)&mb(5)),
5066                                 getflt((unsigned char *)&mb(9)),
5067                                 getflt((unsigned char *)&mb(13)),
5068                                 sats, (sats == 1) ? "" : "s");
5069                         t += strlen(t);
5070
5071                         for (i=0; i < sats; i++)
5072                         {
5073                                 sprintf(t, "%s%02d", i ? ", " : "", mb(17+i));
5074                                 t += strlen(t);
5075                                 if (tr)
5076                                         tr->ctrack |= (1 << (mb(17+i)-1));
5077                         }
5078
5079                         if (tr)
5080                         { /* mark for tracking status query */
5081                                 tr->qtracking = 1;
5082                         }
5083                 }
5084                 break;
5085                 
5086                 case CMD_RSTATTRACK:
5087                 {
5088                         sprintf(t-2, "[%02d]=\"", mb(0)); /* add index to var name */
5089                         t += strlen(t);
5090
5091                         if (getflt((unsigned char *)&mb(4)) < 0.0)
5092                         {
5093                                 strcpy(t, "<NO MEASUREMENTS>");
5094                                 var_flag &= ~DEF;
5095                         }
5096                         else
5097                         {       
5098                                 sprintf(t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5099                                         (mb(1) & 0xFF)>>3,
5100                                         mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5101                                         mb(3),
5102                                         getflt((unsigned char *)&mb(4)),
5103                                         getflt((unsigned char *)&mb(12)) * RTOD,
5104                                         getflt((unsigned char *)&mb(16)) * RTOD);
5105                                 t += strlen(t);
5106                                 if (mb(20))
5107                                 {
5108                                         var_flag &= ~DEF;
5109                                         strcpy(t, ", OLD");
5110                                 }
5111                                 t += strlen(t);
5112                                 if (mb(22))
5113                                 {
5114                                         if (mb(22) == 1)
5115                                                 strcpy(t, ", BAD PARITY");
5116                                         else
5117                                                 if (mb(22) == 2)
5118                                                         strcpy(t, ", BAD EPH HEALTH");
5119                                 }
5120                                 t += strlen(t);
5121                                 if (mb(23))
5122                                         strcpy(t, ", collecting data");
5123                         }
5124                 }
5125                 break;
5126                 
5127                 default:
5128                         strcpy(t, "<UNDECODED>");
5129                         break;
5130                 }
5131                 strcat(t,"\"");
5132                 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5133         }
5134 }
5135
5136 \f
5137 /**============================================================
5138  ** RAWDCF support
5139  **/
5140
5141 /*--------------------------------------------------
5142  * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5143  * SET DTR line
5144  */
5145 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5146 static int
5147 rawdcf_init_1(
5148         struct parseunit *parse
5149         )
5150 {
5151         /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5152         /*
5153          * You can use the RS232 to supply the power for a DCF77 receiver.
5154          * Here a voltage between the DTR and the RTS line is used. Unfortunately
5155          * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5156          */
5157         int sl232;
5158
5159         if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5160         {
5161                 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5162                 return 0;
5163         }
5164
5165 #ifdef TIOCM_DTR
5166         sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR;       /* turn on DTR, clear RTS for power supply */
5167 #else
5168         sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR;       /* turn on DTR, clear RTS for power supply */
5169 #endif
5170
5171         if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5172         {
5173                 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5174         }
5175         return 0;
5176 }
5177 #else
5178 static int
5179 rawdcfdtr_init(
5180         struct parseunit *parse
5181         )
5182 {
5183         msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5184         return 0;
5185 }
5186 #endif  /* DTR initialisation type */
5187
5188 /*--------------------------------------------------
5189  * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5190  * CLR DTR line, SET RTS line
5191  */
5192 #if defined(TIOCMSET) &&  (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5193 static int
5194 rawdcf_init_2(
5195         struct parseunit *parse
5196         )
5197 {
5198         /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5199         /*
5200          * You can use the RS232 to supply the power for a DCF77 receiver.
5201          * Here a voltage between the DTR and the RTS line is used. Unfortunately
5202          * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5203          */
5204         int sl232;
5205
5206         if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5207         {
5208                 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5209                 return 0;
5210         }
5211
5212 #ifdef TIOCM_RTS
5213         sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS;       /* turn on RTS, clear DTR for power supply */
5214 #else
5215         sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS;       /* turn on RTS, clear DTR for power supply */
5216 #endif
5217
5218         if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5219         {
5220                 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5221         }
5222         return 0;
5223 }
5224 #else
5225 static int
5226 rawdcf_init_2(
5227         struct parseunit *parse
5228         )
5229 {
5230         msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5231         return 0;
5232 }
5233 #endif  /* DTR initialisation type */
5234
5235 #else   /* defined(REFCLOCK) && defined(PARSE) */
5236 int refclock_parse_bs;
5237 #endif  /* defined(REFCLOCK) && defined(PARSE) */
5238
5239 /*
5240  * History:
5241  *
5242  * refclock_parse.c,v
5243  * Revision 4.36  1999/11/28 17:18:20  kardel
5244  * disabled burst mode
5245  *
5246  * Revision 4.35  1999/11/28 09:14:14  kardel
5247  * RECON_4_0_98F
5248  *
5249  * Revision 4.34  1999/05/14 06:08:05  kardel
5250  * store current_time in a suitable container (u_long)
5251  *
5252  * Revision 4.33  1999/05/13 21:48:38  kardel
5253  * double the no response timeout interval
5254  *
5255  * Revision 4.32  1999/05/13 20:09:13  kardel
5256  * complain only about missing polls after a full poll interval
5257  *
5258  * Revision 4.31  1999/05/13 19:59:32  kardel
5259  * add clock type 16 for RTS set DTR clr in RAWDCF
5260  *
5261  * Revision 4.30  1999/02/28 20:36:43  kardel
5262  * fixed printf fmt
5263  *
5264  * Revision 4.29  1999/02/28 19:58:23  kardel
5265  * updated copyright information
5266  *
5267  * Revision 4.28  1999/02/28 19:01:50  kardel
5268  * improved debug out on sent Meinberg messages
5269  *
5270  * Revision 4.27  1999/02/28 18:05:55  kardel
5271  * no linux/ppsclock.h stuff
5272  *
5273  * Revision 4.26  1999/02/28 15:27:27  kardel
5274  * wharton clock integration
5275  *
5276  * Revision 4.25  1999/02/28 14:04:46  kardel
5277  * added missing double quotes to UTC information string
5278  *
5279  * Revision 4.24  1999/02/28 12:06:50  kardel
5280  * (parse_control): using gmprettydate instead of prettydate()
5281  * (mk_utcinfo): new function for formatting GPS derived UTC information
5282  * (gps16x_message): changed to use mk_utcinfo()
5283  * (trimbletsip_message): changed to use mk_utcinfo()
5284  * ignoring position information in unsynchronized mode
5285  * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5286  *
5287  * Revision 4.23  1999/02/23 19:47:53  kardel
5288  * fixed #endifs
5289  * (stream_receive): fixed formats
5290  *
5291  * Revision 4.22  1999/02/22 06:21:02  kardel
5292  * use new autoconfig symbols
5293  *
5294  * Revision 4.21  1999/02/21 12:18:13  kardel
5295  * 4.91f reconcilation
5296  *
5297  * Revision 4.20  1999/02/21 10:53:36  kardel
5298  * initial Linux PPSkit version
5299  *
5300  * Revision 4.19  1999/02/07 09:10:45  kardel
5301  * clarify STREAMS mitigation rules in comment
5302  *
5303  * Revision 4.18  1998/12/20 23:45:34  kardel
5304  * fix types and warnings
5305  *
5306  * Revision 4.17  1998/11/15 21:24:51  kardel
5307  * cannot access mbg_ routines when CLOCK_MEINBERG
5308  * is not defined
5309  *
5310  * Revision 4.16  1998/11/15 20:28:17  kardel
5311  * Release 4.0.73e13 reconcilation
5312  *
5313  * Revision 4.15  1998/08/22 21:56:08  kardel
5314  * fixed IO handling for non-STREAM IO
5315  *
5316  * Revision 4.14  1998/08/16 19:00:48  kardel
5317  * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5318  * made uval a local variable (killed one of the last globals)
5319  * (sendetx): added logging of messages when in debug mode
5320  * (trimble_check): added periodic checks to facilitate re-initialization
5321  * (trimbletsip_init): made use of EOL character if in non-kernel operation
5322  * (trimbletsip_message): extended message interpretation
5323  * (getdbl): fixed data conversion
5324  *
5325  * Revision 4.13  1998/08/09 22:29:13  kardel
5326  * Trimble TSIP support
5327  *
5328  * Revision 4.12  1998/07/11 10:05:34  kardel
5329  * Release 4.0.73d reconcilation
5330  *
5331  * Revision 4.11  1998/06/14 21:09:42  kardel
5332  * Sun acc cleanup
5333  *
5334  * Revision 4.10  1998/06/13 12:36:45  kardel
5335  * signed/unsigned, name clashes
5336  *
5337  * Revision 4.9  1998/06/12 15:30:00  kardel
5338  * prototype fixes
5339  *
5340  * Revision 4.8  1998/06/12 11:19:42  kardel
5341  * added direct input processing routine for refclocks in
5342  * order to avaiod that single character io gobbles up all
5343  * receive buffers and drops input data. (Problem started
5344  * with fast machines so a character a buffer was possible
5345  * one of the few cases where faster machines break existing
5346  * allocation algorithms)
5347  *
5348  * Revision 4.7  1998/06/06 18:35:20  kardel
5349  * (parse_start): added BURST mode initialisation
5350  *
5351  * Revision 4.6  1998/05/27 06:12:46  kardel
5352  * RAWDCF_BASEDELAY default added
5353  * old comment removed
5354  * casts for ioctl()
5355  *
5356  * Revision 4.5  1998/05/25 22:05:09  kardel
5357  * RAWDCF_SETDTR option removed
5358  * clock type 14 attempts to set DTR for
5359  * power supply of RAWDCF receivers
5360  *
5361  * Revision 4.4  1998/05/24 16:20:47  kardel
5362  * updated comments referencing Meinberg clocks
5363  * added RAWDCF clock with DTR set option as type 14
5364  *
5365  * Revision 4.3  1998/05/24 10:48:33  kardel
5366  * calibrated CONRAD RAWDCF default fudge factor
5367  *
5368  * Revision 4.2  1998/05/24 09:59:35  kardel
5369  * corrected version information (ntpq support)
5370  *
5371  * Revision 4.1  1998/05/24 09:52:31  kardel
5372  * use fixed format only (new IO model)
5373  * output debug to stdout instead of msyslog()
5374  * don't include >"< in ASCII output in order not to confuse
5375  * ntpq parsing
5376  *
5377  * Revision 4.0  1998/04/10 19:52:11  kardel
5378  * Start 4.0 release version numbering
5379  *
5380  * Revision 1.2  1998/04/10 19:28:04  kardel
5381  * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
5382  * derived from 3.105.1.2 from V3 tree
5383  *
5384  * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
5385  *
5386  */