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