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