Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / ntpd / refclock_parse.c
blobdc9ff8893f56381100d668a7d64edc3e581956f8
1 /* $NetBSD: refclock_parse.c,v 1.9 2007/08/18 09:56:13 kardel Exp $ */
3 /*
4 * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
6 * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp
8 * generic reference clock driver for several DCF/GPS/MSF/... receivers
10 * PPS notes:
11 * On systems that support PPSAPI (RFC2783) PPSAPI is the
12 * preferred interface.
14 * Optionally make use of a STREAMS module for input processing where
15 * available and configured. This STREAMS module reduces the time
16 * stamp latency for serial and PPS events.
17 * Currently the STREAMS module is only available for Suns running
18 * SunOS 4.x and SunOS5.x.
20 * Copyright (c) 1995-2007 by Frank Kardel <kardel <AT> ntp.org>
21 * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. Neither the name of the author nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
49 #ifdef HAVE_CONFIG_H
50 # include "config.h"
51 #endif
53 #if defined(REFCLOCK) && defined(CLOCK_PARSE)
56 * This driver currently provides the support for
57 * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF)
58 * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF)
59 * - Meinberg receiver DCF77 PZF 509 (DCF)
60 * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF)
61 * - IGEL CLOCK (DCF)
62 * - ELV DCF7000 (DCF)
63 * - Schmid clock (DCF)
64 * - Conrad DCF77 receiver module (DCF)
65 * - FAU DCF77 NTP receiver (TimeBrick) (DCF)
66 * - WHARTON 400A Series clock (DCF)
68 * - Meinberg GPS166/GPS167 (GPS)
69 * - Trimble (TSIP and TAIP protocol) (GPS)
71 * - RCC8000 MSF Receiver (MSF)
72 * - VARITEXT clock (MSF)
76 * Meinberg receivers are usually connected via a
77 * 9600 baud serial line
79 * The Meinberg GPS receivers also have a special NTP time stamp
80 * format. The firmware release is Uni-Erlangen.
82 * Meinberg generic receiver setup:
83 * output time code every second
84 * Baud rate 9600 7E2S
86 * Meinberg GPS16x setup:
87 * output time code every second
88 * Baudrate 19200 8N1
90 * This software supports the standard data formats used
91 * in Meinberg receivers.
93 * Special software versions are only sensible for the
94 * GPS 16x family of receivers.
96 * Meinberg can be reached via: http://www.meinberg.de/
99 #include "ntpd.h"
100 #include "ntp_refclock.h"
101 #include "ntp_unixtime.h" /* includes <sys/time.h> */
102 #include "ntp_control.h"
103 #include "ntp_string.h"
105 #include <stdio.h>
106 #include <ctype.h>
107 #ifndef TM_IN_SYS_TIME
108 # include <time.h>
109 #endif
111 #ifdef HAVE_UNISTD_H
112 # include <unistd.h>
113 #endif
115 #if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
116 # include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}"
117 #endif
119 #ifdef STREAM
120 # include <sys/stream.h>
121 # include <sys/stropts.h>
122 #endif
124 #ifdef HAVE_TERMIOS
125 # define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
126 # define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
127 # undef HAVE_SYSV_TTYS
128 #endif
130 #ifdef HAVE_SYSV_TTYS
131 # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
132 # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
133 #endif
135 #ifdef HAVE_BSD_TTYS
136 /* #error CURRENTLY NO BSD TTY SUPPORT */
137 # include "Bletch: BSD TTY not currently supported"
138 #endif
140 #ifdef HAVE_SYS_IOCTL_H
141 # include <sys/ioctl.h>
142 #endif
144 #ifdef HAVE_PPSAPI
145 # include "ppsapi_timepps.h"
146 #endif
148 #ifdef PPS
149 # ifdef HAVE_SYS_PPSCLOCK_H
150 # include <sys/ppsclock.h>
151 # endif
152 # ifdef HAVE_TIO_SERIAL_STUFF
153 # include <linux/serial.h>
154 # endif
155 #endif
157 #define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR))
158 #define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR))
161 * document type of PPS interfacing - copy of ifdef mechanism in local_input()
163 #undef PPS_METHOD
165 #ifdef HAVE_PPSAPI
166 #define PPS_METHOD "PPS API"
167 #else
168 #ifdef TIOCDCDTIMESTAMP
169 #define PPS_METHOD "TIOCDCDTIMESTAMP"
170 #else /* TIOCDCDTIMESTAMP */
171 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
172 #ifdef HAVE_CIOGETEV
173 #define PPS_METHOD "CIOGETEV"
174 #endif
175 #ifdef HAVE_TIOCGPPSEV
176 #define PPS_METHOD "TIOCGPPSEV"
177 #endif
178 #endif
179 #endif /* TIOCDCDTIMESTAMP */
180 #endif /* HAVE_PPSAPI */
182 #include "ntp_io.h"
183 #include "ntp_stdlib.h"
185 #include "parse.h"
186 #include "mbg_gps166.h"
187 #include "trimble.h"
188 #include "binio.h"
189 #include "ascii.h"
190 #include "ieee754io.h"
191 #include "recvbuff.h"
193 static char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp";
195 /**===========================================================================
196 ** external interface to ntp mechanism
199 static int parse_start P((int, struct peer *));
200 static void parse_shutdown P((int, struct peer *));
201 static void parse_poll P((int, struct peer *));
202 static void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *));
204 struct refclock refclock_parse = {
205 parse_start,
206 parse_shutdown,
207 parse_poll,
208 parse_control,
209 noentry,
210 noentry,
211 NOFLAGS
215 * Definitions
217 #define MAXUNITS 4 /* maximum number of "PARSE" units permitted */
218 #define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */
219 #define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */
221 #undef ABS
222 #define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_))
224 #define PARSE_HARDPPS_DISABLE 0
225 #define PARSE_HARDPPS_ENABLE 1
227 /**===========================================================================
228 ** function vector for dynamically binding io handling mechanism
231 struct parseunit; /* to keep inquiring minds happy */
233 typedef struct bind
235 const char *bd_description; /* name of type of binding */
236 int (*bd_init) P((struct parseunit *)); /* initialize */
237 void (*bd_end) P((struct parseunit *)); /* end */
238 int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */
239 int (*bd_disable) P((struct parseunit *)); /* disable */
240 int (*bd_enable) P((struct parseunit *)); /* enable */
241 int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */
242 int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */
243 int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */
244 void (*bd_receive) P((struct recvbuf *)); /* receive operation */
245 int (*bd_io_input) P((struct recvbuf *)); /* input operation */
246 } bind_t;
248 #define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
249 #define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
250 #define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
251 #define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
252 #define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
253 #define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
254 #define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
257 * io modes
259 #define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */
260 #define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */
263 /**===========================================================================
264 ** error message regression handling
266 ** there are quite a few errors that can occur in rapid succession such as
267 ** noisy input data or no data at all. in order to reduce the amount of
268 ** syslog messages in such case, we are using a backoff algorithm. We limit
269 ** the number of error messages of a certain class to 1 per time unit. if a
270 ** configurable number of messages is displayed that way, we move on to the
271 ** next time unit / count for that class. a count of messages that have been
272 ** suppressed is held and displayed whenever a corresponding message is
273 ** displayed. the time units for a message class will also be displayed.
274 ** whenever an error condition clears we reset the error message state,
275 ** thus we would still generate much output on pathological conditions
276 ** where the system oscillates between OK and NOT OK states. coping
277 ** with that condition is currently considered too complicated.
280 #define ERR_ALL (unsigned)~0 /* "all" errors */
281 #define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */
282 #define ERR_NODATA (unsigned)1 /* no input data */
283 #define ERR_BADIO (unsigned)2 /* read/write/select errors */
284 #define ERR_BADSTATUS (unsigned)3 /* unsync states */
285 #define ERR_BADEVENT (unsigned)4 /* non nominal events */
286 #define ERR_INTERNAL (unsigned)5 /* internal error */
287 #define ERR_CNT (unsigned)(ERR_INTERNAL+1)
289 #define ERR(_X_) if (list_err(parse, (_X_)))
291 struct errorregression
293 u_long err_count; /* number of repititions per class */
294 u_long err_delay; /* minimum delay between messages */
297 static struct errorregression
298 err_baddata[] = /* error messages for bad input data */
300 { 1, 0 }, /* output first message immediately */
301 { 5, 60 }, /* output next five messages in 60 second intervals */
302 { 3, 3600 }, /* output next 3 messages in hour intervals */
303 { 0, 12*3600 } /* repeat messages only every 12 hours */
306 static struct errorregression
307 err_nodata[] = /* error messages for missing input data */
309 { 1, 0 }, /* output first message immediately */
310 { 5, 60 }, /* output next five messages in 60 second intervals */
311 { 3, 3600 }, /* output next 3 messages in hour intervals */
312 { 0, 12*3600 } /* repeat messages only every 12 hours */
315 static struct errorregression
316 err_badstatus[] = /* unsynchronized state messages */
318 { 1, 0 }, /* output first message immediately */
319 { 5, 60 }, /* output next five messages in 60 second intervals */
320 { 3, 3600 }, /* output next 3 messages in hour intervals */
321 { 0, 12*3600 } /* repeat messages only every 12 hours */
324 static struct errorregression
325 err_badio[] = /* io failures (bad reads, selects, ...) */
327 { 1, 0 }, /* output first message immediately */
328 { 5, 60 }, /* output next five messages in 60 second intervals */
329 { 5, 3600 }, /* output next 3 messages in hour intervals */
330 { 0, 12*3600 } /* repeat messages only every 12 hours */
333 static struct errorregression
334 err_badevent[] = /* non nominal events */
336 { 20, 0 }, /* output first message immediately */
337 { 6, 60 }, /* output next five messages in 60 second intervals */
338 { 5, 3600 }, /* output next 3 messages in hour intervals */
339 { 0, 12*3600 } /* repeat messages only every 12 hours */
342 static struct errorregression
343 err_internal[] = /* really bad things - basically coding/OS errors */
345 { 0, 0 }, /* output all messages immediately */
348 static struct errorregression *
349 err_tbl[] =
351 err_baddata,
352 err_nodata,
353 err_badio,
354 err_badstatus,
355 err_badevent,
356 err_internal
359 struct errorinfo
361 u_long err_started; /* begin time (ntp) of error condition */
362 u_long err_last; /* last time (ntp) error occurred */
363 u_long err_cnt; /* number of error repititions */
364 u_long err_suppressed; /* number of suppressed messages */
365 struct errorregression *err_stage; /* current error stage */
368 /**===========================================================================
369 ** refclock instance data
372 struct parseunit
375 * NTP management
377 struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */
378 struct refclockproc *generic; /* backlink to refclockproc structure */
381 * PARSE io
383 bind_t *binding; /* io handling binding */
386 * parse state
388 parse_t parseio; /* io handling structure (user level parsing) */
391 * type specific parameters
393 struct parse_clockinfo *parse_type; /* link to clock description */
396 * clock state handling/reporting
398 u_char flags; /* flags (leap_control) */
399 u_long lastchange; /* time (ntp) when last state change accured */
400 u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
401 u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */
402 u_short lastformat; /* last format used */
403 u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */
404 u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */
405 double ppsphaseadjust; /* phase adjustment of PPS time stamp */
406 u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */
407 u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
408 int ppsfd; /* fd to ise for PPS io */
409 #ifdef HAVE_PPSAPI
410 pps_handle_t ppshandle; /* store PPSAPI handle */
411 pps_params_t ppsparams; /* current PPS parameters */
412 int hardppsstate; /* current hard pps state */
413 #endif
414 parsetime_t timedata; /* last (parse module) data */
415 void *localdata; /* optional local, receiver-specific data */
416 unsigned long localstate; /* private local state */
417 struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */
418 struct ctl_var *kv; /* additional pseudo variables */
419 u_long laststatistic; /* time when staticstics where output */
423 /**===========================================================================
424 ** Clockinfo section all parameter for specific clock types
425 ** includes NTP parameters, TTY parameters and IO handling parameters
428 static void poll_dpoll P((struct parseunit *));
429 static void poll_poll P((struct peer *));
430 static int poll_init P((struct parseunit *));
432 typedef struct poll_info
434 u_long rate; /* poll rate - once every "rate" seconds - 0 off */
435 const char *string; /* string to send for polling */
436 u_long count; /* number of characters in string */
437 } poll_info_t;
439 #define NO_CL_FLAGS 0
440 #define NO_POLL 0
441 #define NO_INIT 0
442 #define NO_END 0
443 #define NO_EVENT 0
444 #define NO_LCLDATA 0
445 #define NO_MESSAGE 0
446 #define NO_PPSDELAY 0
448 #define DCF_ID "DCF" /* generic DCF */
449 #define DCF_A_ID "DCFa" /* AM demodulation */
450 #define DCF_P_ID "DCFp" /* psuedo random phase shift */
451 #define GPS_ID "GPS" /* GPS receiver */
453 #define NOCLOCK_ROOTDELAY 0.0
454 #define NOCLOCK_BASEDELAY 0.0
455 #define NOCLOCK_DESCRIPTION 0
456 #define NOCLOCK_MAXUNSYNC 0
457 #define NOCLOCK_CFLAG 0
458 #define NOCLOCK_IFLAG 0
459 #define NOCLOCK_OFLAG 0
460 #define NOCLOCK_LFLAG 0
461 #define NOCLOCK_ID "TILT"
462 #define NOCLOCK_POLL NO_POLL
463 #define NOCLOCK_INIT NO_INIT
464 #define NOCLOCK_END NO_END
465 #define NOCLOCK_DATA NO_LCLDATA
466 #define NOCLOCK_FORMAT ""
467 #define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
468 #define NOCLOCK_SAMPLES 0
469 #define NOCLOCK_KEEP 0
471 #define DCF_TYPE CTL_SST_TS_LF
472 #define GPS_TYPE CTL_SST_TS_UHF
475 * receiver specific constants
477 #define MBG_SPEED (B9600)
478 #define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB)
479 #define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
480 #define MBG_OFLAG 0
481 #define MBG_LFLAG 0
482 #define MBG_FLAGS PARSE_F_PPSONSECOND
485 * Meinberg DCF77 receivers
487 #define DCFUA31_ROOTDELAY 0.0 /* 0 */
488 #define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */
489 #define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible"
490 #define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */
491 #define DCFUA31_SPEED MBG_SPEED
492 #define DCFUA31_CFLAG MBG_CFLAG
493 #define DCFUA31_IFLAG MBG_IFLAG
494 #define DCFUA31_OFLAG MBG_OFLAG
495 #define DCFUA31_LFLAG MBG_LFLAG
496 #define DCFUA31_SAMPLES 5
497 #define DCFUA31_KEEP 3
498 #define DCFUA31_FORMAT "Meinberg Standard"
501 * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
503 #define DCFPZF535_ROOTDELAY 0.0
504 #define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
505 #define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO"
506 #define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours
507 * @ 5e-8df/f we have accumulated
508 * at most 2.16 ms (thus we move to
509 * NTP synchronisation */
510 #define DCFPZF535_SPEED MBG_SPEED
511 #define DCFPZF535_CFLAG MBG_CFLAG
512 #define DCFPZF535_IFLAG MBG_IFLAG
513 #define DCFPZF535_OFLAG MBG_OFLAG
514 #define DCFPZF535_LFLAG MBG_LFLAG
515 #define DCFPZF535_SAMPLES 5
516 #define DCFPZF535_KEEP 3
517 #define DCFPZF535_FORMAT "Meinberg Standard"
520 * Meinberg DCF PZF535/OCXO receiver
522 #define DCFPZF535OCXO_ROOTDELAY 0.0
523 #define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
524 #define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO"
525 #define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
526 * @ 5e-9df/f we have accumulated
527 * at most an error of 1.73 ms
528 * (thus we move to NTP synchronisation) */
529 #define DCFPZF535OCXO_SPEED MBG_SPEED
530 #define DCFPZF535OCXO_CFLAG MBG_CFLAG
531 #define DCFPZF535OCXO_IFLAG MBG_IFLAG
532 #define DCFPZF535OCXO_OFLAG MBG_OFLAG
533 #define DCFPZF535OCXO_LFLAG MBG_LFLAG
534 #define DCFPZF535OCXO_SAMPLES 5
535 #define DCFPZF535OCXO_KEEP 3
536 #define DCFPZF535OCXO_FORMAT "Meinberg Standard"
539 * Meinberg GPS16X receiver
541 static void gps16x_message P((struct parseunit *, parsetime_t *));
542 static int gps16x_poll_init P((struct parseunit *));
544 #define GPS16X_ROOTDELAY 0.0 /* nothing here */
545 #define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
546 #define GPS16X_DESCRIPTION "Meinberg GPS16x receiver"
547 #define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
548 * @ 5e-9df/f we have accumulated
549 * at most an error of 1.73 ms
550 * (thus we move to NTP synchronisation) */
551 #define GPS16X_SPEED B19200
552 #define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL)
553 #define GPS16X_IFLAG (IGNBRK|IGNPAR)
554 #define GPS16X_OFLAG MBG_OFLAG
555 #define GPS16X_LFLAG MBG_LFLAG
556 #define GPS16X_POLLRATE 6
557 #define GPS16X_POLLCMD ""
558 #define GPS16X_CMDSIZE 0
560 static poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE };
562 #define GPS16X_INIT gps16x_poll_init
563 #define GPS16X_POLL 0
564 #define GPS16X_END 0
565 #define GPS16X_DATA ((void *)(&gps16x_pollinfo))
566 #define GPS16X_MESSAGE gps16x_message
567 #define GPS16X_ID GPS_ID
568 #define GPS16X_FORMAT "Meinberg GPS Extended"
569 #define GPS16X_SAMPLES 5
570 #define GPS16X_KEEP 3
573 * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
575 * This is really not the hottest clock - but before you have nothing ...
577 #define DCF7000_ROOTDELAY 0.0 /* 0 */
578 #define DCF7000_BASEDELAY 0.405 /* slow blow */
579 #define DCF7000_DESCRIPTION "ELV DCF7000"
580 #define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */
581 #define DCF7000_SPEED (B9600)
582 #define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
583 #define DCF7000_IFLAG (IGNBRK)
584 #define DCF7000_OFLAG 0
585 #define DCF7000_LFLAG 0
586 #define DCF7000_SAMPLES 5
587 #define DCF7000_KEEP 3
588 #define DCF7000_FORMAT "ELV DCF7000"
591 * Schmid DCF Receiver Kit
593 * When the WSDCF clock is operating optimally we want the primary clock
594 * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer
595 * structure is set to 290 ms and we compute delays which are at least
596 * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format
598 #define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */
599 #define WS_POLLCMD "\163"
600 #define WS_CMDSIZE 1
602 static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
604 #define WSDCF_INIT poll_init
605 #define WSDCF_POLL poll_dpoll
606 #define WSDCF_END 0
607 #define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
608 #define WSDCF_ROOTDELAY 0.0 /* 0 */
609 #define WSDCF_BASEDELAY 0.010 /* ~ 10ms */
610 #define WSDCF_DESCRIPTION "WS/DCF Receiver"
611 #define WSDCF_FORMAT "Schmid"
612 #define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
613 #define WSDCF_SPEED (B1200)
614 #define WSDCF_CFLAG (CS8|CREAD|CLOCAL)
615 #define WSDCF_IFLAG 0
616 #define WSDCF_OFLAG 0
617 #define WSDCF_LFLAG 0
618 #define WSDCF_SAMPLES 5
619 #define WSDCF_KEEP 3
622 * RAW DCF77 - input of DCF marks via RS232 - many variants
624 #define RAWDCF_FLAGS 0
625 #define RAWDCF_ROOTDELAY 0.0 /* 0 */
626 #define RAWDCF_BASEDELAY 0.258
627 #define RAWDCF_FORMAT "RAW DCF77 Timecode"
628 #define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
629 #define RAWDCF_SPEED (B50)
630 #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */
631 /* somehow doesn't grok PARENB & IGNPAR (mj) */
632 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
633 #else
634 # define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB)
635 #endif
636 #ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */
637 # define RAWDCF_IFLAG 0
638 #else
639 # define RAWDCF_IFLAG (IGNPAR)
640 #endif
641 #define RAWDCF_OFLAG 0
642 #define RAWDCF_LFLAG 0
643 #define RAWDCF_SAMPLES 20
644 #define RAWDCF_KEEP 12
645 #define RAWDCF_INIT 0
648 * RAW DCF variants
651 * Conrad receiver
653 * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
654 * (~40DM - roughly $30 ) followed by a level converter for RS232
656 #define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */
657 #define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
659 /* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */
660 #define GUDE_EMC_USB_V20_SPEED (B4800)
661 #define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */
662 #define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)"
665 * TimeBrick receiver
667 #define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */
668 #define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
671 * IGEL:clock receiver
673 #define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */
674 #define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)"
675 #define IGELCLOCK_SPEED (B1200)
676 #define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL)
679 * RAWDCF receivers that need to be powered from DTR
680 * (like Expert mouse clock)
682 static int rawdcf_init_1 P((struct parseunit *));
683 #define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)"
684 #define RAWDCFDTRSET_INIT rawdcf_init_1
687 * RAWDCF receivers that need to be powered from
688 * DTR CLR and RTS SET
690 static int rawdcf_init_2 P((struct parseunit *));
691 #define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)"
692 #define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2
695 * Trimble GPS receivers (TAIP and TSIP protocols)
697 #ifndef TRIM_POLLRATE
698 #define TRIM_POLLRATE 0 /* only true direct polling */
699 #endif
701 #define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<"
702 #define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1)
704 static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
705 static int trimbletaip_init P((struct parseunit *));
706 static void trimbletaip_event P((struct parseunit *, int));
708 /* query time & UTC correction data */
709 static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
711 static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
712 static int trimbletsip_init P((struct parseunit *));
713 static void trimbletsip_end P((struct parseunit *));
714 static void trimbletsip_message P((struct parseunit *, parsetime_t *));
715 static void trimbletsip_event P((struct parseunit *, int));
717 #define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */
718 #define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME
720 #define TRIMBLETAIP_SPEED (B4800)
721 #define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL)
722 #define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
723 #define TRIMBLETAIP_OFLAG (OPOST|ONLCR)
724 #define TRIMBLETAIP_LFLAG (0)
726 #define TRIMBLETSIP_SPEED (B9600)
727 #define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD)
728 #define TRIMBLETSIP_IFLAG (IGNBRK)
729 #define TRIMBLETSIP_OFLAG (0)
730 #define TRIMBLETSIP_LFLAG (ICANON)
732 #define TRIMBLETSIP_SAMPLES 5
733 #define TRIMBLETSIP_KEEP 3
734 #define TRIMBLETAIP_SAMPLES 5
735 #define TRIMBLETAIP_KEEP 3
737 #define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND)
738 #define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS)
740 #define TRIMBLETAIP_POLL poll_dpoll
741 #define TRIMBLETSIP_POLL poll_dpoll
743 #define TRIMBLETAIP_INIT trimbletaip_init
744 #define TRIMBLETSIP_INIT trimbletsip_init
746 #define TRIMBLETAIP_EVENT trimbletaip_event
748 #define TRIMBLETSIP_EVENT trimbletsip_event
749 #define TRIMBLETSIP_MESSAGE trimbletsip_message
751 #define TRIMBLETAIP_END 0
752 #define TRIMBLETSIP_END trimbletsip_end
754 #define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo))
755 #define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo))
757 #define TRIMBLETAIP_ID GPS_ID
758 #define TRIMBLETSIP_ID GPS_ID
760 #define TRIMBLETAIP_FORMAT "Trimble TAIP"
761 #define TRIMBLETSIP_FORMAT "Trimble TSIP"
763 #define TRIMBLETAIP_ROOTDELAY 0x0
764 #define TRIMBLETSIP_ROOTDELAY 0x0
766 #define TRIMBLETAIP_BASEDELAY 0.0
767 #define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */
769 #define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver"
770 #define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver"
772 #define TRIMBLETAIP_MAXUNSYNC 0
773 #define TRIMBLETSIP_MAXUNSYNC 0
775 #define TRIMBLETAIP_EOL '<'
778 * RadioCode Clocks RCC 800 receiver
780 #define RCC_POLLRATE 0 /* only true direct polling */
781 #define RCC_POLLCMD "\r"
782 #define RCC_CMDSIZE 1
784 static poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE };
785 #define RCC8000_FLAGS 0
786 #define RCC8000_POLL poll_dpoll
787 #define RCC8000_INIT poll_init
788 #define RCC8000_END 0
789 #define RCC8000_DATA ((void *)(&rcc8000_pollinfo))
790 #define RCC8000_ROOTDELAY 0.0
791 #define RCC8000_BASEDELAY 0.0
792 #define RCC8000_ID "MSF"
793 #define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver"
794 #define RCC8000_FORMAT "Radiocode RCC8000"
795 #define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */
796 #define RCC8000_SPEED (B2400)
797 #define RCC8000_CFLAG (CS8|CREAD|CLOCAL)
798 #define RCC8000_IFLAG (IGNBRK|IGNPAR)
799 #define RCC8000_OFLAG 0
800 #define RCC8000_LFLAG 0
801 #define RCC8000_SAMPLES 5
802 #define RCC8000_KEEP 3
805 * Hopf Radio clock 6021 Format
808 #define HOPF6021_ROOTDELAY 0.0
809 #define HOPF6021_BASEDELAY 0.0
810 #define HOPF6021_DESCRIPTION "HOPF 6021"
811 #define HOPF6021_FORMAT "hopf Funkuhr 6021"
812 #define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */
813 #define HOPF6021_SPEED (B9600)
814 #define HOPF6021_CFLAG (CS8|CREAD|CLOCAL)
815 #define HOPF6021_IFLAG (IGNBRK|ISTRIP)
816 #define HOPF6021_OFLAG 0
817 #define HOPF6021_LFLAG 0
818 #define HOPF6021_FLAGS 0
819 #define HOPF6021_SAMPLES 5
820 #define HOPF6021_KEEP 3
823 * Diem's Computime Radio Clock Receiver
825 #define COMPUTIME_FLAGS 0
826 #define COMPUTIME_ROOTDELAY 0.0
827 #define COMPUTIME_BASEDELAY 0.0
828 #define COMPUTIME_ID DCF_ID
829 #define COMPUTIME_DESCRIPTION "Diem's Computime receiver"
830 #define COMPUTIME_FORMAT "Diem's Computime Radio Clock"
831 #define COMPUTIME_TYPE DCF_TYPE
832 #define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
833 #define COMPUTIME_SPEED (B9600)
834 #define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL)
835 #define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP)
836 #define COMPUTIME_OFLAG 0
837 #define COMPUTIME_LFLAG 0
838 #define COMPUTIME_SAMPLES 5
839 #define COMPUTIME_KEEP 3
842 * Varitext Radio Clock Receiver
844 #define VARITEXT_FLAGS 0
845 #define VARITEXT_ROOTDELAY 0.0
846 #define VARITEXT_BASEDELAY 0.0
847 #define VARITEXT_ID "MSF"
848 #define VARITEXT_DESCRIPTION "Varitext receiver"
849 #define VARITEXT_FORMAT "Varitext Radio Clock"
850 #define VARITEXT_TYPE DCF_TYPE
851 #define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */
852 #define VARITEXT_SPEED (B9600)
853 #define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD)
854 #define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/
855 #define VARITEXT_OFLAG 0
856 #define VARITEXT_LFLAG 0
857 #define VARITEXT_SAMPLES 32
858 #define VARITEXT_KEEP 20
860 static struct parse_clockinfo
862 u_long cl_flags; /* operation flags (io modes) */
863 void (*cl_poll) P((struct parseunit *)); /* active poll routine */
864 int (*cl_init) P((struct parseunit *)); /* active poll init routine */
865 void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */
866 void (*cl_end) P((struct parseunit *)); /* active poll end routine */
867 void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */
868 void *cl_data; /* local data area for "poll" mechanism */
869 double cl_rootdelay; /* rootdelay */
870 double cl_basedelay; /* current offset by which the RS232
871 time code is delayed from the actual time */
872 const char *cl_id; /* ID code */
873 const char *cl_description; /* device name */
874 const char *cl_format; /* fixed format */
875 u_char cl_type; /* clock type (ntp control) */
876 u_long cl_maxunsync; /* time to trust oscillator after losing synch */
877 u_long cl_speed; /* terminal input & output baudrate */
878 u_long cl_cflag; /* terminal control flags */
879 u_long cl_iflag; /* terminal input flags */
880 u_long cl_oflag; /* terminal output flags */
881 u_long cl_lflag; /* terminal local flags */
882 u_long cl_samples; /* samples for median filter */
883 u_long cl_keep; /* samples for median filter to keep */
884 } parse_clockinfo[] =
886 { /* mode 0 */
887 MBG_FLAGS,
888 NO_POLL,
889 NO_INIT,
890 NO_EVENT,
891 NO_END,
892 NO_MESSAGE,
893 NO_LCLDATA,
894 DCFPZF535_ROOTDELAY,
895 DCFPZF535_BASEDELAY,
896 DCF_P_ID,
897 DCFPZF535_DESCRIPTION,
898 DCFPZF535_FORMAT,
899 DCF_TYPE,
900 DCFPZF535_MAXUNSYNC,
901 DCFPZF535_SPEED,
902 DCFPZF535_CFLAG,
903 DCFPZF535_IFLAG,
904 DCFPZF535_OFLAG,
905 DCFPZF535_LFLAG,
906 DCFPZF535_SAMPLES,
907 DCFPZF535_KEEP
909 { /* mode 1 */
910 MBG_FLAGS,
911 NO_POLL,
912 NO_INIT,
913 NO_EVENT,
914 NO_END,
915 NO_MESSAGE,
916 NO_LCLDATA,
917 DCFPZF535OCXO_ROOTDELAY,
918 DCFPZF535OCXO_BASEDELAY,
919 DCF_P_ID,
920 DCFPZF535OCXO_DESCRIPTION,
921 DCFPZF535OCXO_FORMAT,
922 DCF_TYPE,
923 DCFPZF535OCXO_MAXUNSYNC,
924 DCFPZF535OCXO_SPEED,
925 DCFPZF535OCXO_CFLAG,
926 DCFPZF535OCXO_IFLAG,
927 DCFPZF535OCXO_OFLAG,
928 DCFPZF535OCXO_LFLAG,
929 DCFPZF535OCXO_SAMPLES,
930 DCFPZF535OCXO_KEEP
932 { /* mode 2 */
933 MBG_FLAGS,
934 NO_POLL,
935 NO_INIT,
936 NO_EVENT,
937 NO_END,
938 NO_MESSAGE,
939 NO_LCLDATA,
940 DCFUA31_ROOTDELAY,
941 DCFUA31_BASEDELAY,
942 DCF_A_ID,
943 DCFUA31_DESCRIPTION,
944 DCFUA31_FORMAT,
945 DCF_TYPE,
946 DCFUA31_MAXUNSYNC,
947 DCFUA31_SPEED,
948 DCFUA31_CFLAG,
949 DCFUA31_IFLAG,
950 DCFUA31_OFLAG,
951 DCFUA31_LFLAG,
952 DCFUA31_SAMPLES,
953 DCFUA31_KEEP
955 { /* mode 3 */
956 MBG_FLAGS,
957 NO_POLL,
958 NO_INIT,
959 NO_EVENT,
960 NO_END,
961 NO_MESSAGE,
962 NO_LCLDATA,
963 DCF7000_ROOTDELAY,
964 DCF7000_BASEDELAY,
965 DCF_A_ID,
966 DCF7000_DESCRIPTION,
967 DCF7000_FORMAT,
968 DCF_TYPE,
969 DCF7000_MAXUNSYNC,
970 DCF7000_SPEED,
971 DCF7000_CFLAG,
972 DCF7000_IFLAG,
973 DCF7000_OFLAG,
974 DCF7000_LFLAG,
975 DCF7000_SAMPLES,
976 DCF7000_KEEP
978 { /* mode 4 */
979 NO_CL_FLAGS,
980 WSDCF_POLL,
981 WSDCF_INIT,
982 NO_EVENT,
983 WSDCF_END,
984 NO_MESSAGE,
985 WSDCF_DATA,
986 WSDCF_ROOTDELAY,
987 WSDCF_BASEDELAY,
988 DCF_A_ID,
989 WSDCF_DESCRIPTION,
990 WSDCF_FORMAT,
991 DCF_TYPE,
992 WSDCF_MAXUNSYNC,
993 WSDCF_SPEED,
994 WSDCF_CFLAG,
995 WSDCF_IFLAG,
996 WSDCF_OFLAG,
997 WSDCF_LFLAG,
998 WSDCF_SAMPLES,
999 WSDCF_KEEP
1001 { /* mode 5 */
1002 RAWDCF_FLAGS,
1003 NO_POLL,
1004 RAWDCF_INIT,
1005 NO_EVENT,
1006 NO_END,
1007 NO_MESSAGE,
1008 NO_LCLDATA,
1009 RAWDCF_ROOTDELAY,
1010 CONRAD_BASEDELAY,
1011 DCF_A_ID,
1012 CONRAD_DESCRIPTION,
1013 RAWDCF_FORMAT,
1014 DCF_TYPE,
1015 RAWDCF_MAXUNSYNC,
1016 RAWDCF_SPEED,
1017 RAWDCF_CFLAG,
1018 RAWDCF_IFLAG,
1019 RAWDCF_OFLAG,
1020 RAWDCF_LFLAG,
1021 RAWDCF_SAMPLES,
1022 RAWDCF_KEEP
1024 { /* mode 6 */
1025 RAWDCF_FLAGS,
1026 NO_POLL,
1027 RAWDCF_INIT,
1028 NO_EVENT,
1029 NO_END,
1030 NO_MESSAGE,
1031 NO_LCLDATA,
1032 RAWDCF_ROOTDELAY,
1033 TIMEBRICK_BASEDELAY,
1034 DCF_A_ID,
1035 TIMEBRICK_DESCRIPTION,
1036 RAWDCF_FORMAT,
1037 DCF_TYPE,
1038 RAWDCF_MAXUNSYNC,
1039 RAWDCF_SPEED,
1040 RAWDCF_CFLAG,
1041 RAWDCF_IFLAG,
1042 RAWDCF_OFLAG,
1043 RAWDCF_LFLAG,
1044 RAWDCF_SAMPLES,
1045 RAWDCF_KEEP
1047 { /* mode 7 */
1048 MBG_FLAGS,
1049 GPS16X_POLL,
1050 GPS16X_INIT,
1051 NO_EVENT,
1052 GPS16X_END,
1053 GPS16X_MESSAGE,
1054 GPS16X_DATA,
1055 GPS16X_ROOTDELAY,
1056 GPS16X_BASEDELAY,
1057 GPS16X_ID,
1058 GPS16X_DESCRIPTION,
1059 GPS16X_FORMAT,
1060 GPS_TYPE,
1061 GPS16X_MAXUNSYNC,
1062 GPS16X_SPEED,
1063 GPS16X_CFLAG,
1064 GPS16X_IFLAG,
1065 GPS16X_OFLAG,
1066 GPS16X_LFLAG,
1067 GPS16X_SAMPLES,
1068 GPS16X_KEEP
1070 { /* mode 8 */
1071 RAWDCF_FLAGS,
1072 NO_POLL,
1073 NO_INIT,
1074 NO_EVENT,
1075 NO_END,
1076 NO_MESSAGE,
1077 NO_LCLDATA,
1078 RAWDCF_ROOTDELAY,
1079 IGELCLOCK_BASEDELAY,
1080 DCF_A_ID,
1081 IGELCLOCK_DESCRIPTION,
1082 RAWDCF_FORMAT,
1083 DCF_TYPE,
1084 RAWDCF_MAXUNSYNC,
1085 IGELCLOCK_SPEED,
1086 IGELCLOCK_CFLAG,
1087 RAWDCF_IFLAG,
1088 RAWDCF_OFLAG,
1089 RAWDCF_LFLAG,
1090 RAWDCF_SAMPLES,
1091 RAWDCF_KEEP
1093 { /* mode 9 */
1094 TRIMBLETAIP_FLAGS,
1095 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1096 NO_POLL,
1097 #else
1098 TRIMBLETAIP_POLL,
1099 #endif
1100 TRIMBLETAIP_INIT,
1101 TRIMBLETAIP_EVENT,
1102 TRIMBLETAIP_END,
1103 NO_MESSAGE,
1104 TRIMBLETAIP_DATA,
1105 TRIMBLETAIP_ROOTDELAY,
1106 TRIMBLETAIP_BASEDELAY,
1107 TRIMBLETAIP_ID,
1108 TRIMBLETAIP_DESCRIPTION,
1109 TRIMBLETAIP_FORMAT,
1110 GPS_TYPE,
1111 TRIMBLETAIP_MAXUNSYNC,
1112 TRIMBLETAIP_SPEED,
1113 TRIMBLETAIP_CFLAG,
1114 TRIMBLETAIP_IFLAG,
1115 TRIMBLETAIP_OFLAG,
1116 TRIMBLETAIP_LFLAG,
1117 TRIMBLETAIP_SAMPLES,
1118 TRIMBLETAIP_KEEP
1120 { /* mode 10 */
1121 TRIMBLETSIP_FLAGS,
1122 #if TRIM_POLLRATE /* DHD940515: Allow user config */
1123 NO_POLL,
1124 #else
1125 TRIMBLETSIP_POLL,
1126 #endif
1127 TRIMBLETSIP_INIT,
1128 TRIMBLETSIP_EVENT,
1129 TRIMBLETSIP_END,
1130 TRIMBLETSIP_MESSAGE,
1131 TRIMBLETSIP_DATA,
1132 TRIMBLETSIP_ROOTDELAY,
1133 TRIMBLETSIP_BASEDELAY,
1134 TRIMBLETSIP_ID,
1135 TRIMBLETSIP_DESCRIPTION,
1136 TRIMBLETSIP_FORMAT,
1137 GPS_TYPE,
1138 TRIMBLETSIP_MAXUNSYNC,
1139 TRIMBLETSIP_SPEED,
1140 TRIMBLETSIP_CFLAG,
1141 TRIMBLETSIP_IFLAG,
1142 TRIMBLETSIP_OFLAG,
1143 TRIMBLETSIP_LFLAG,
1144 TRIMBLETSIP_SAMPLES,
1145 TRIMBLETSIP_KEEP
1147 { /* mode 11 */
1148 NO_CL_FLAGS,
1149 RCC8000_POLL,
1150 RCC8000_INIT,
1151 NO_EVENT,
1152 RCC8000_END,
1153 NO_MESSAGE,
1154 RCC8000_DATA,
1155 RCC8000_ROOTDELAY,
1156 RCC8000_BASEDELAY,
1157 RCC8000_ID,
1158 RCC8000_DESCRIPTION,
1159 RCC8000_FORMAT,
1160 DCF_TYPE,
1161 RCC8000_MAXUNSYNC,
1162 RCC8000_SPEED,
1163 RCC8000_CFLAG,
1164 RCC8000_IFLAG,
1165 RCC8000_OFLAG,
1166 RCC8000_LFLAG,
1167 RCC8000_SAMPLES,
1168 RCC8000_KEEP
1170 { /* mode 12 */
1171 HOPF6021_FLAGS,
1172 NO_POLL,
1173 NO_INIT,
1174 NO_EVENT,
1175 NO_END,
1176 NO_MESSAGE,
1177 NO_LCLDATA,
1178 HOPF6021_ROOTDELAY,
1179 HOPF6021_BASEDELAY,
1180 DCF_ID,
1181 HOPF6021_DESCRIPTION,
1182 HOPF6021_FORMAT,
1183 DCF_TYPE,
1184 HOPF6021_MAXUNSYNC,
1185 HOPF6021_SPEED,
1186 HOPF6021_CFLAG,
1187 HOPF6021_IFLAG,
1188 HOPF6021_OFLAG,
1189 HOPF6021_LFLAG,
1190 HOPF6021_SAMPLES,
1191 HOPF6021_KEEP
1193 { /* mode 13 */
1194 COMPUTIME_FLAGS,
1195 NO_POLL,
1196 NO_INIT,
1197 NO_EVENT,
1198 NO_END,
1199 NO_MESSAGE,
1200 NO_LCLDATA,
1201 COMPUTIME_ROOTDELAY,
1202 COMPUTIME_BASEDELAY,
1203 COMPUTIME_ID,
1204 COMPUTIME_DESCRIPTION,
1205 COMPUTIME_FORMAT,
1206 COMPUTIME_TYPE,
1207 COMPUTIME_MAXUNSYNC,
1208 COMPUTIME_SPEED,
1209 COMPUTIME_CFLAG,
1210 COMPUTIME_IFLAG,
1211 COMPUTIME_OFLAG,
1212 COMPUTIME_LFLAG,
1213 COMPUTIME_SAMPLES,
1214 COMPUTIME_KEEP
1216 { /* mode 14 */
1217 RAWDCF_FLAGS,
1218 NO_POLL,
1219 RAWDCFDTRSET_INIT,
1220 NO_EVENT,
1221 NO_END,
1222 NO_MESSAGE,
1223 NO_LCLDATA,
1224 RAWDCF_ROOTDELAY,
1225 RAWDCF_BASEDELAY,
1226 DCF_A_ID,
1227 RAWDCFDTRSET_DESCRIPTION,
1228 RAWDCF_FORMAT,
1229 DCF_TYPE,
1230 RAWDCF_MAXUNSYNC,
1231 RAWDCF_SPEED,
1232 RAWDCF_CFLAG,
1233 RAWDCF_IFLAG,
1234 RAWDCF_OFLAG,
1235 RAWDCF_LFLAG,
1236 RAWDCF_SAMPLES,
1237 RAWDCF_KEEP
1239 { /* mode 15 */
1240 0, /* operation flags (io modes) */
1241 NO_POLL, /* active poll routine */
1242 NO_INIT, /* active poll init routine */
1243 NO_EVENT, /* special event handling (e.g. reset clock) */
1244 NO_END, /* active poll end routine */
1245 NO_MESSAGE, /* process a lower layer message */
1246 NO_LCLDATA, /* local data area for "poll" mechanism */
1247 0, /* rootdelay */
1248 11.0 /* bits */ / 9600, /* current offset by which the RS232
1249 time code is delayed from the actual time */
1250 DCF_ID, /* ID code */
1251 "WHARTON 400A Series clock", /* device name */
1252 "WHARTON 400A Series clock Output Format 1", /* fixed format */
1253 /* Must match a format-name in a libparse/clk_xxx.c file */
1254 DCF_TYPE, /* clock type (ntp control) */
1255 (1*60*60), /* time to trust oscillator after losing synch */
1256 B9600, /* terminal input & output baudrate */
1257 (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */
1258 0, /* terminal input flags */
1259 0, /* terminal output flags */
1260 0, /* terminal local flags */
1261 5, /* samples for median filter */
1262 3, /* samples for median filter to keep */
1264 { /* mode 16 - RAWDCF RTS set, DTR clr */
1265 RAWDCF_FLAGS,
1266 NO_POLL,
1267 RAWDCFDTRCLRRTSSET_INIT,
1268 NO_EVENT,
1269 NO_END,
1270 NO_MESSAGE,
1271 NO_LCLDATA,
1272 RAWDCF_ROOTDELAY,
1273 RAWDCF_BASEDELAY,
1274 DCF_A_ID,
1275 RAWDCFDTRCLRRTSSET_DESCRIPTION,
1276 RAWDCF_FORMAT,
1277 DCF_TYPE,
1278 RAWDCF_MAXUNSYNC,
1279 RAWDCF_SPEED,
1280 RAWDCF_CFLAG,
1281 RAWDCF_IFLAG,
1282 RAWDCF_OFLAG,
1283 RAWDCF_LFLAG,
1284 RAWDCF_SAMPLES,
1285 RAWDCF_KEEP
1287 { /* mode 17 */
1288 VARITEXT_FLAGS,
1289 NO_POLL,
1290 NO_INIT,
1291 NO_EVENT,
1292 NO_END,
1293 NO_MESSAGE,
1294 NO_LCLDATA,
1295 VARITEXT_ROOTDELAY,
1296 VARITEXT_BASEDELAY,
1297 VARITEXT_ID,
1298 VARITEXT_DESCRIPTION,
1299 VARITEXT_FORMAT,
1300 VARITEXT_TYPE,
1301 VARITEXT_MAXUNSYNC,
1302 VARITEXT_SPEED,
1303 VARITEXT_CFLAG,
1304 VARITEXT_IFLAG,
1305 VARITEXT_OFLAG,
1306 VARITEXT_LFLAG,
1307 VARITEXT_SAMPLES,
1308 VARITEXT_KEEP
1310 { /* mode 18 */
1311 MBG_FLAGS,
1312 NO_POLL,
1313 NO_INIT,
1314 NO_EVENT,
1315 GPS16X_END,
1316 GPS16X_MESSAGE,
1317 GPS16X_DATA,
1318 GPS16X_ROOTDELAY,
1319 GPS16X_BASEDELAY,
1320 GPS16X_ID,
1321 GPS16X_DESCRIPTION,
1322 GPS16X_FORMAT,
1323 GPS_TYPE,
1324 GPS16X_MAXUNSYNC,
1325 GPS16X_SPEED,
1326 GPS16X_CFLAG,
1327 GPS16X_IFLAG,
1328 GPS16X_OFLAG,
1329 GPS16X_LFLAG,
1330 GPS16X_SAMPLES,
1331 GPS16X_KEEP
1333 { /* mode 19 */
1334 RAWDCF_FLAGS,
1335 NO_POLL,
1336 RAWDCF_INIT,
1337 NO_EVENT,
1338 NO_END,
1339 NO_MESSAGE,
1340 NO_LCLDATA,
1341 RAWDCF_ROOTDELAY,
1342 GUDE_EMC_USB_V20_BASEDELAY,
1343 DCF_A_ID,
1344 GUDE_EMC_USB_V20_DESCRIPTION,
1345 RAWDCF_FORMAT,
1346 DCF_TYPE,
1347 RAWDCF_MAXUNSYNC,
1348 GUDE_EMC_USB_V20_SPEED,
1349 RAWDCF_CFLAG,
1350 RAWDCF_IFLAG,
1351 RAWDCF_OFLAG,
1352 RAWDCF_LFLAG,
1353 RAWDCF_SAMPLES,
1354 RAWDCF_KEEP
1358 static int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo);
1360 #define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F))
1361 #define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x))
1362 #define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr))
1363 #define CLK_PPS(x) (((x)->ttl) & 0x80)
1366 * Other constant stuff
1368 #define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */
1370 #define PARSESTATISTICS (60*60) /* output state statistics every hour */
1372 static int notice = 0;
1374 #define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
1376 static void parse_event P((struct parseunit *, int));
1377 static void parse_process P((struct parseunit *, parsetime_t *));
1378 static void clear_err P((struct parseunit *, u_long));
1379 static int list_err P((struct parseunit *, u_long));
1380 static char * l_mktime P((u_long));
1382 /**===========================================================================
1383 ** implementation error message regression module
1385 static void
1386 clear_err(
1387 struct parseunit *parse,
1388 u_long lstate
1391 if (lstate == ERR_ALL)
1393 int i;
1395 for (i = 0; i < ERR_CNT; i++)
1397 parse->errors[i].err_stage = err_tbl[i];
1398 parse->errors[i].err_cnt = 0;
1399 parse->errors[i].err_last = 0;
1400 parse->errors[i].err_started = 0;
1401 parse->errors[i].err_suppressed = 0;
1404 else
1406 parse->errors[lstate].err_stage = err_tbl[lstate];
1407 parse->errors[lstate].err_cnt = 0;
1408 parse->errors[lstate].err_last = 0;
1409 parse->errors[lstate].err_started = 0;
1410 parse->errors[lstate].err_suppressed = 0;
1414 static int
1415 list_err(
1416 struct parseunit *parse,
1417 u_long lstate
1420 int do_it;
1421 struct errorinfo *err = &parse->errors[lstate];
1423 if (err->err_started == 0)
1425 err->err_started = current_time;
1428 do_it = (current_time - err->err_last) >= err->err_stage->err_delay;
1430 if (do_it)
1431 err->err_cnt++;
1433 if (err->err_stage->err_count &&
1434 (err->err_cnt >= err->err_stage->err_count))
1436 err->err_stage++;
1437 err->err_cnt = 0;
1440 if (!err->err_cnt && do_it)
1441 msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s",
1442 CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay));
1444 if (!do_it)
1445 err->err_suppressed++;
1446 else
1447 err->err_last = current_time;
1449 if (do_it && err->err_suppressed)
1451 msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s",
1452 CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where",
1453 l_mktime(current_time - err->err_started));
1454 err->err_suppressed = 0;
1457 return do_it;
1460 /*--------------------------------------------------
1461 * mkreadable - make a printable ascii string (without
1462 * embedded quotes so that the ntpq protocol isn't
1463 * fooled
1465 #ifndef isprint
1466 #define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
1467 #endif
1469 static char *
1470 mkreadable(
1471 char *buffer,
1472 long blen,
1473 const char *src,
1474 u_long srclen,
1475 int hex
1478 char *b = buffer;
1479 char *endb = (char *)0;
1481 if (blen < 4)
1482 return (char *)0; /* don't bother with mini buffers */
1484 endb = buffer + blen - 4;
1486 blen--; /* account for '\0' */
1488 while (blen && srclen--)
1490 if (!hex && /* no binary only */
1491 (*src != '\\') && /* no plain \ */
1492 (*src != '"') && /* no " */
1493 isprint((int)*src)) /* only printables */
1494 { /* they are easy... */
1495 *buffer++ = *src++;
1496 blen--;
1498 else
1500 if (blen < 4)
1502 while (blen--)
1504 *buffer++ = '.';
1506 *buffer = '\0';
1507 return b;
1509 else
1511 if (*src == '\\')
1513 strcpy(buffer,"\\\\");
1514 buffer += 2;
1515 blen -= 2;
1516 src++;
1518 else
1520 sprintf(buffer, "\\x%02x", *src++);
1521 blen -= 4;
1522 buffer += 4;
1526 if (srclen && !blen && endb) /* overflow - set last chars to ... */
1527 strcpy(endb, "...");
1530 *buffer = '\0';
1531 return b;
1535 /*--------------------------------------------------
1536 * mkascii - make a printable ascii string
1537 * assumes (unless defined better) 7-bit ASCII
1539 static char *
1540 mkascii(
1541 char *buffer,
1542 long blen,
1543 const char *src,
1544 u_long srclen
1547 return mkreadable(buffer, blen, src, srclen, 0);
1550 /**===========================================================================
1551 ** implementation of i/o handling methods
1552 ** (all STREAM, partial STREAM, user level)
1556 * define possible io handling methods
1558 #ifdef STREAM
1559 static int ppsclock_init P((struct parseunit *));
1560 static int stream_init P((struct parseunit *));
1561 static void stream_end P((struct parseunit *));
1562 static int stream_enable P((struct parseunit *));
1563 static int stream_disable P((struct parseunit *));
1564 static int stream_setcs P((struct parseunit *, parsectl_t *));
1565 static int stream_getfmt P((struct parseunit *, parsectl_t *));
1566 static int stream_setfmt P((struct parseunit *, parsectl_t *));
1567 static int stream_timecode P((struct parseunit *, parsectl_t *));
1568 static void stream_receive P((struct recvbuf *));
1569 #endif
1571 static int local_init P((struct parseunit *));
1572 static void local_end P((struct parseunit *));
1573 static int local_nop P((struct parseunit *));
1574 static int local_setcs P((struct parseunit *, parsectl_t *));
1575 static int local_getfmt P((struct parseunit *, parsectl_t *));
1576 static int local_setfmt P((struct parseunit *, parsectl_t *));
1577 static int local_timecode P((struct parseunit *, parsectl_t *));
1578 static void local_receive P((struct recvbuf *));
1579 static int local_input P((struct recvbuf *));
1581 static bind_t io_bindings[] =
1583 #ifdef STREAM
1585 "parse STREAM",
1586 stream_init,
1587 stream_end,
1588 stream_setcs,
1589 stream_disable,
1590 stream_enable,
1591 stream_getfmt,
1592 stream_setfmt,
1593 stream_timecode,
1594 stream_receive,
1598 "ppsclock STREAM",
1599 ppsclock_init,
1600 local_end,
1601 local_setcs,
1602 local_nop,
1603 local_nop,
1604 local_getfmt,
1605 local_setfmt,
1606 local_timecode,
1607 local_receive,
1608 local_input,
1610 #endif
1612 "normal",
1613 local_init,
1614 local_end,
1615 local_setcs,
1616 local_nop,
1617 local_nop,
1618 local_getfmt,
1619 local_setfmt,
1620 local_timecode,
1621 local_receive,
1622 local_input,
1625 (char *)0,
1629 #ifdef STREAM
1631 #define fix_ts(_X_) \
1632 if ((&(_X_))->tv.tv_usec >= 1000000) \
1634 (&(_X_))->tv.tv_usec -= 1000000; \
1635 (&(_X_))->tv.tv_sec += 1; \
1638 #define cvt_ts(_X_, _Y_) \
1640 l_fp ts; \
1641 fix_ts((_X_)); \
1642 if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
1644 ERR(ERR_BADDATA) \
1645 msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\
1646 return; \
1648 else \
1650 (&(_X_))->fp = ts; \
1654 /*--------------------------------------------------
1655 * ppsclock STREAM init
1657 static int
1658 ppsclock_init(
1659 struct parseunit *parse
1662 static char m1[] = "ppsclocd";
1663 static char m2[] = "ppsclock";
1666 * now push the parse streams module
1667 * it will ensure exclusive access to the device
1669 if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1670 ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
1672 if (errno != EINVAL)
1674 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1675 CLK_UNIT(parse->peer));
1677 return 0;
1679 if (!local_init(parse))
1681 (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
1682 return 0;
1685 parse->flags |= PARSE_PPSCLOCK;
1686 return 1;
1689 /*--------------------------------------------------
1690 * parse STREAM init
1692 static int
1693 stream_init(
1694 struct parseunit *parse
1697 static char m1[] = "parse";
1699 * now push the parse streams module
1700 * to test whether it is there (neat interface 8-( )
1702 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1704 if (errno != EINVAL) /* accept non-existence */
1706 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1708 return 0;
1710 else
1712 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1713 /* empty loop */;
1716 * now push it a second time after we have removed all
1717 * module garbage
1719 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1721 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1722 return 0;
1724 else
1726 return 1;
1731 /*--------------------------------------------------
1732 * parse STREAM end
1734 static void
1735 stream_end(
1736 struct parseunit *parse
1739 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1740 /* empty loop */;
1743 /*--------------------------------------------------
1744 * STREAM setcs
1746 static int
1747 stream_setcs(
1748 struct parseunit *parse,
1749 parsectl_t *tcl
1752 struct strioctl strioc;
1754 strioc.ic_cmd = PARSEIOC_SETCS;
1755 strioc.ic_timout = 0;
1756 strioc.ic_dp = (char *)tcl;
1757 strioc.ic_len = sizeof (*tcl);
1759 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1761 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1762 return 0;
1764 return 1;
1767 /*--------------------------------------------------
1768 * STREAM enable
1770 static int
1771 stream_enable(
1772 struct parseunit *parse
1775 struct strioctl strioc;
1777 strioc.ic_cmd = PARSEIOC_ENABLE;
1778 strioc.ic_timout = 0;
1779 strioc.ic_dp = (char *)0;
1780 strioc.ic_len = 0;
1782 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1784 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1785 return 0;
1787 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1788 return 1;
1791 /*--------------------------------------------------
1792 * STREAM disable
1794 static int
1795 stream_disable(
1796 struct parseunit *parse
1799 struct strioctl strioc;
1801 strioc.ic_cmd = PARSEIOC_DISABLE;
1802 strioc.ic_timout = 0;
1803 strioc.ic_dp = (char *)0;
1804 strioc.ic_len = 0;
1806 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1808 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1809 return 0;
1811 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1812 return 1;
1815 /*--------------------------------------------------
1816 * STREAM getfmt
1818 static int
1819 stream_getfmt(
1820 struct parseunit *parse,
1821 parsectl_t *tcl
1824 struct strioctl strioc;
1826 strioc.ic_cmd = PARSEIOC_GETFMT;
1827 strioc.ic_timout = 0;
1828 strioc.ic_dp = (char *)tcl;
1829 strioc.ic_len = sizeof (*tcl);
1830 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1832 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1833 return 0;
1835 return 1;
1838 /*--------------------------------------------------
1839 * STREAM setfmt
1841 static int
1842 stream_setfmt(
1843 struct parseunit *parse,
1844 parsectl_t *tcl
1847 struct strioctl strioc;
1849 strioc.ic_cmd = PARSEIOC_SETFMT;
1850 strioc.ic_timout = 0;
1851 strioc.ic_dp = (char *)tcl;
1852 strioc.ic_len = sizeof (*tcl);
1854 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1856 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1857 return 0;
1859 return 1;
1863 /*--------------------------------------------------
1864 * STREAM timecode
1866 static int
1867 stream_timecode(
1868 struct parseunit *parse,
1869 parsectl_t *tcl
1872 struct strioctl strioc;
1874 strioc.ic_cmd = PARSEIOC_TIMECODE;
1875 strioc.ic_timout = 0;
1876 strioc.ic_dp = (char *)tcl;
1877 strioc.ic_len = sizeof (*tcl);
1879 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1881 ERR(ERR_INTERNAL)
1882 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
1883 return 0;
1885 clear_err(parse, ERR_INTERNAL);
1886 return 1;
1889 /*--------------------------------------------------
1890 * STREAM receive
1892 static void
1893 stream_receive(
1894 struct recvbuf *rbufp
1897 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
1898 parsetime_t parsetime;
1900 if (!parse->peer)
1901 return;
1903 if (rbufp->recv_length != sizeof(parsetime_t))
1905 ERR(ERR_BADIO)
1906 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
1907 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
1908 parse_event(parse, CEVNT_BADREPLY);
1909 return;
1911 clear_err(parse, ERR_BADIO);
1913 memmove((caddr_t)&parsetime,
1914 (caddr_t)rbufp->recv_buffer,
1915 sizeof(parsetime_t));
1917 #ifdef DEBUG
1918 if (debug > 3)
1920 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
1921 CLK_UNIT(parse->peer),
1922 (unsigned int)parsetime.parse_status,
1923 (unsigned int)parsetime.parse_state,
1924 (unsigned long)parsetime.parse_time.tv.tv_sec,
1925 (unsigned long)parsetime.parse_time.tv.tv_usec,
1926 (unsigned long)parsetime.parse_stime.tv.tv_sec,
1927 (unsigned long)parsetime.parse_stime.tv.tv_usec,
1928 (unsigned long)parsetime.parse_ptime.tv.tv_sec,
1929 (unsigned long)parsetime.parse_ptime.tv.tv_usec);
1931 #endif
1934 * switch time stamp world - be sure to normalize small usec field
1935 * errors.
1938 cvt_ts(parsetime.parse_stime, "parse_stime");
1940 if (PARSE_TIMECODE(parsetime.parse_state))
1942 cvt_ts(parsetime.parse_time, "parse_time");
1945 if (PARSE_PPS(parsetime.parse_state))
1946 cvt_ts(parsetime.parse_ptime, "parse_ptime");
1948 parse_process(parse, &parsetime);
1950 #endif
1952 /*--------------------------------------------------
1953 * local init
1955 static int
1956 local_init(
1957 struct parseunit *parse
1960 return parse_ioinit(&parse->parseio);
1963 /*--------------------------------------------------
1964 * local end
1966 static void
1967 local_end(
1968 struct parseunit *parse
1971 parse_ioend(&parse->parseio);
1975 /*--------------------------------------------------
1976 * local nop
1978 static int
1979 local_nop(
1980 struct parseunit *parse
1983 return 1;
1986 /*--------------------------------------------------
1987 * local setcs
1989 static int
1990 local_setcs(
1991 struct parseunit *parse,
1992 parsectl_t *tcl
1995 return parse_setcs(tcl, &parse->parseio);
1998 /*--------------------------------------------------
1999 * local getfmt
2001 static int
2002 local_getfmt(
2003 struct parseunit *parse,
2004 parsectl_t *tcl
2007 return parse_getfmt(tcl, &parse->parseio);
2010 /*--------------------------------------------------
2011 * local setfmt
2013 static int
2014 local_setfmt(
2015 struct parseunit *parse,
2016 parsectl_t *tcl
2019 return parse_setfmt(tcl, &parse->parseio);
2022 /*--------------------------------------------------
2023 * local timecode
2025 static int
2026 local_timecode(
2027 struct parseunit *parse,
2028 parsectl_t *tcl
2031 return parse_timecode(tcl, &parse->parseio);
2035 /*--------------------------------------------------
2036 * local input
2038 static int
2039 local_input(
2040 struct recvbuf *rbufp
2043 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2044 int count;
2045 unsigned char *s;
2046 timestamp_t ts;
2048 if (!parse->peer)
2049 return 0;
2052 * eat all characters, parsing then and feeding complete samples
2054 count = rbufp->recv_length;
2055 s = (unsigned char *)rbufp->recv_buffer;
2056 ts.fp = rbufp->recv_time;
2058 while (count--)
2060 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
2062 struct recvbuf *buf;
2065 * got something good to eat
2067 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
2069 #ifdef HAVE_PPSAPI
2070 if (parse->flags & PARSE_PPSCLOCK)
2072 struct timespec pps_timeout;
2073 pps_info_t pps_info;
2075 pps_timeout.tv_sec = 0;
2076 pps_timeout.tv_nsec = 0;
2078 if (time_pps_fetch(parse->ppshandle, PPS_TSFMT_TSPEC, &pps_info,
2079 &pps_timeout) == 0)
2081 if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2083 double dtemp;
2085 struct timespec pts;
2087 * add PPS time stamp if available via ppsclock module
2088 * and not supplied already.
2090 if (parse->flags & PARSE_CLEAR)
2091 pts = pps_info.clear_timestamp;
2092 else
2093 pts = pps_info.assert_timestamp;
2095 parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
2097 dtemp = pts.tv_nsec / 1e9;
2098 if (dtemp < 0.) {
2099 dtemp += 1;
2100 parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2102 if (dtemp > 1.) {
2103 dtemp -= 1;
2104 parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2106 parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
2108 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2109 #ifdef DEBUG
2110 if (debug > 3)
2112 printf(
2113 "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2114 rbufp->fd,
2115 (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2116 lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2118 #endif
2120 #ifdef DEBUG
2121 else
2123 if (debug > 3)
2125 printf(
2126 "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2127 rbufp->fd,
2128 (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2131 #endif
2132 parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2134 #ifdef DEBUG
2135 else
2137 if (debug > 3)
2139 printf(
2140 "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2141 rbufp->fd,
2142 errno);
2145 #endif
2147 #else
2148 #ifdef TIOCDCDTIMESTAMP
2149 struct timeval dcd_time;
2151 if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
2153 l_fp tstmp;
2155 TVTOTS(&dcd_time, &tstmp);
2156 tstmp.l_ui += JAN_1970;
2157 L_SUB(&ts.fp, &tstmp);
2158 if (ts.fp.l_ui == 0)
2160 #ifdef DEBUG
2161 if (debug)
2163 printf(
2164 "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2165 parse->ppsfd,
2166 lfptoa(&tstmp, 6));
2167 printf(" sigio %s\n",
2168 lfptoa(&ts.fp, 6));
2170 #endif
2171 parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
2172 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2175 #else /* TIOCDCDTIMESTAMP */
2176 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
2177 if (parse->flags & PARSE_PPSCLOCK)
2179 l_fp tts;
2180 struct ppsclockev ev;
2182 #ifdef HAVE_CIOGETEV
2183 if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
2184 #endif
2185 #ifdef HAVE_TIOCGPPSEV
2186 if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
2187 #endif
2189 if (ev.serial != parse->ppsserial)
2192 * add PPS time stamp if available via ppsclock module
2193 * and not supplied already.
2195 if (!buftvtots((const char *)&ev.tv, &tts))
2197 ERR(ERR_BADDATA)
2198 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2200 else
2202 parse->parseio.parse_dtime.parse_ptime.fp = tts;
2203 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2206 parse->ppsserial = ev.serial;
2209 #endif
2210 #endif /* TIOCDCDTIMESTAMP */
2211 #endif /* !HAVE_PPSAPI */
2213 if (count)
2214 { /* simulate receive */
2215 buf = get_free_recv_buffer();
2216 if (buf != NULL) {
2217 memmove((caddr_t)buf->recv_buffer,
2218 (caddr_t)&parse->parseio.parse_dtime,
2219 sizeof(parsetime_t));
2220 buf->recv_length = sizeof(parsetime_t);
2221 buf->recv_time = rbufp->recv_time;
2222 buf->srcadr = rbufp->srcadr;
2223 buf->dstadr = rbufp->dstadr;
2224 buf->receiver = rbufp->receiver;
2225 buf->fd = rbufp->fd;
2226 buf->X_from_where = rbufp->X_from_where;
2227 add_full_recv_buffer(buf);
2229 parse_iodone(&parse->parseio);
2231 else
2233 memmove((caddr_t)rbufp->recv_buffer,
2234 (caddr_t)&parse->parseio.parse_dtime,
2235 sizeof(parsetime_t));
2236 parse_iodone(&parse->parseio);
2237 rbufp->recv_length = sizeof(parsetime_t);
2238 return 1; /* got something & in place return */
2242 return 0; /* nothing to pass up */
2245 /*--------------------------------------------------
2246 * local receive
2248 static void
2249 local_receive(
2250 struct recvbuf *rbufp
2253 struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock);
2254 parsetime_t parsetime;
2256 if (!parse->peer)
2257 return;
2259 if (rbufp->recv_length != sizeof(parsetime_t))
2261 ERR(ERR_BADIO)
2262 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2263 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2264 parse_event(parse, CEVNT_BADREPLY);
2265 return;
2267 clear_err(parse, ERR_BADIO);
2269 memmove((caddr_t)&parsetime,
2270 (caddr_t)rbufp->recv_buffer,
2271 sizeof(parsetime_t));
2273 #ifdef DEBUG
2274 if (debug > 3)
2276 printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
2277 CLK_UNIT(parse->peer),
2278 (unsigned int)parsetime.parse_status,
2279 (unsigned int)parsetime.parse_state,
2280 (unsigned long)parsetime.parse_time.fp.l_ui,
2281 (unsigned long)parsetime.parse_time.fp.l_uf,
2282 (unsigned long)parsetime.parse_stime.fp.l_ui,
2283 (unsigned long)parsetime.parse_stime.fp.l_uf,
2284 (unsigned long)parsetime.parse_ptime.fp.l_ui,
2285 (unsigned long)parsetime.parse_ptime.fp.l_uf);
2287 #endif
2289 parse_process(parse, &parsetime);
2292 /*--------------------------------------------------
2293 * init_iobinding - find and initialize lower layers
2295 static bind_t *
2296 init_iobinding(
2297 struct parseunit *parse
2300 bind_t *b = io_bindings;
2302 while (b->bd_description != (char *)0)
2304 if ((*b->bd_init)(parse))
2306 return b;
2308 b++;
2310 return (bind_t *)0;
2313 /**===========================================================================
2314 ** support routines
2317 /*--------------------------------------------------
2318 * convert a flag field to a string
2320 static char *
2321 parsestate(
2322 u_long lstate,
2323 char *buffer,
2324 int size
2327 static struct bits
2329 u_long bit;
2330 const char *name;
2331 } flagstrings[] =
2333 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
2334 { PARSEB_POWERUP, "NOT SYNCHRONIZED" },
2335 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
2336 { PARSEB_DST, "DST" },
2337 { PARSEB_UTC, "UTC DISPLAY" },
2338 { PARSEB_LEAPADD, "LEAP ADD WARNING" },
2339 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
2340 { PARSEB_LEAPSECOND, "LEAP SECOND" },
2341 { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" },
2342 { PARSEB_TIMECODE, "TIME CODE" },
2343 { PARSEB_PPS, "PPS" },
2344 { PARSEB_POSITION, "POSITION" },
2345 { 0 }
2348 static struct sbits
2350 u_long bit;
2351 const char *name;
2352 } sflagstrings[] =
2354 { PARSEB_S_LEAP, "LEAP INDICATION" },
2355 { PARSEB_S_PPS, "PPS SIGNAL" },
2356 { PARSEB_S_ANTENNA, "ANTENNA" },
2357 { PARSEB_S_POSITION, "POSITION" },
2358 { 0 }
2360 int i;
2361 char *s, *t;
2364 *buffer = '\0';
2365 s = t = buffer;
2367 i = 0;
2368 while (flagstrings[i].bit)
2370 if (flagstrings[i].bit & lstate)
2372 if (s != t)
2373 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2374 strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2375 t += strlen(t);
2377 i++;
2380 if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2382 if (s != t)
2383 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2385 t += strlen(t);
2387 strncpy(t, "(", BUFFER_SIZES(buffer, t, size));
2389 s = t = t + strlen(t);
2391 i = 0;
2392 while (sflagstrings[i].bit)
2394 if (sflagstrings[i].bit & lstate)
2396 if (t != s)
2398 strncpy(t, "; ", BUFFER_SIZES(buffer, t, size));
2399 t += 2;
2402 strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size));
2403 t += strlen(t);
2405 i++;
2407 strncpy(t, ")", BUFFER_SIZES(buffer, t, size));
2409 return buffer;
2412 /*--------------------------------------------------
2413 * convert a status flag field to a string
2415 static char *
2416 parsestatus(
2417 u_long lstate,
2418 char *buffer,
2419 int size
2422 static struct bits
2424 u_long bit;
2425 const char *name;
2426 } flagstrings[] =
2428 { CVT_OK, "CONVERSION SUCCESSFUL" },
2429 { CVT_NONE, "NO CONVERSION" },
2430 { CVT_FAIL, "CONVERSION FAILED" },
2431 { CVT_BADFMT, "ILLEGAL FORMAT" },
2432 { CVT_BADDATE, "DATE ILLEGAL" },
2433 { CVT_BADTIME, "TIME ILLEGAL" },
2434 { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2435 { 0 }
2437 int i;
2439 *buffer = '\0';
2441 i = 0;
2442 while (flagstrings[i].bit)
2444 if (flagstrings[i].bit & lstate)
2446 if (buffer[0])
2447 strncat(buffer, "; ", size);
2448 strncat(buffer, flagstrings[i].name, size);
2450 i++;
2453 return buffer;
2456 /*--------------------------------------------------
2457 * convert a clock status flag field to a string
2459 static const char *
2460 clockstatus(
2461 u_long lstate
2464 static char buffer[20];
2465 static struct status
2467 u_long value;
2468 const char *name;
2469 } flagstrings[] =
2471 { CEVNT_NOMINAL, "NOMINAL" },
2472 { CEVNT_TIMEOUT, "NO RESPONSE" },
2473 { CEVNT_BADREPLY,"BAD FORMAT" },
2474 { CEVNT_FAULT, "FAULT" },
2475 { CEVNT_PROP, "PROPAGATION DELAY" },
2476 { CEVNT_BADDATE, "ILLEGAL DATE" },
2477 { CEVNT_BADTIME, "ILLEGAL TIME" },
2478 { (unsigned)~0L }
2480 int i;
2482 i = 0;
2483 while (flagstrings[i].value != ~0)
2485 if (flagstrings[i].value == lstate)
2487 return flagstrings[i].name;
2489 i++;
2492 snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
2494 return buffer;
2498 /*--------------------------------------------------
2499 * l_mktime - make representation of a relative time
2501 static char *
2502 l_mktime(
2503 u_long delta
2506 u_long tmp, m, s;
2507 static char buffer[40];
2508 char *t;
2510 buffer[0] = '\0';
2512 if ((tmp = delta / (60*60*24)) != 0)
2514 snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp);
2515 delta -= tmp * 60*60*24;
2518 s = delta % 60;
2519 delta /= 60;
2520 m = delta % 60;
2521 delta /= 60;
2523 t = buffer + strlen(buffer);
2525 snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d",
2526 (int)delta, (int)m, (int)s);
2528 return buffer;
2532 /*--------------------------------------------------
2533 * parse_statistics - list summary of clock states
2535 static void
2536 parse_statistics(
2537 struct parseunit *parse
2540 int i;
2542 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2544 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2545 CLK_UNIT(parse->peer),
2546 l_mktime(current_time - parse->generic->timestarted));
2548 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2549 CLK_UNIT(parse->peer),
2550 clockstatus(parse->generic->currentstatus));
2552 for (i = 0; i <= CEVNT_MAX; i++)
2554 u_long s_time;
2555 u_long percent, d = current_time - parse->generic->timestarted;
2557 percent = s_time = PARSE_STATETIME(parse, i);
2559 while (((u_long)(~0) / 10000) < percent)
2561 percent /= 10;
2562 d /= 10;
2565 if (d)
2566 percent = (percent * 10000) / d;
2567 else
2568 percent = 10000;
2570 if (s_time)
2571 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2572 CLK_UNIT(parse->peer),
2573 clockstatus((unsigned int)i),
2574 l_mktime(s_time),
2575 percent / 100, percent % 100);
2580 /*--------------------------------------------------
2581 * cparse_statistics - wrapper for statistics call
2583 static void
2584 cparse_statistics(
2585 struct parseunit *parse
2588 if (parse->laststatistic + PARSESTATISTICS < current_time)
2589 parse_statistics(parse);
2590 parse->laststatistic = current_time;
2593 /**===========================================================================
2594 ** ntp interface routines
2597 /*--------------------------------------------------
2598 * parse_shutdown - shut down a PARSE clock
2600 static void
2601 parse_shutdown(
2602 int unit,
2603 struct peer *peer
2606 struct parseunit *parse = (struct parseunit *)0;
2608 if (peer && peer->procptr)
2609 parse = (struct parseunit *)peer->procptr->unitptr;
2611 if (!parse)
2613 /* nothing to clean up */
2614 return;
2617 if (!parse->peer)
2619 msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2620 return;
2623 #ifdef HAVE_PPSAPI
2624 if (parse->flags & PARSE_PPSCLOCK)
2626 (void)time_pps_destroy(parse->ppshandle);
2628 #endif
2629 if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2630 (void)close(parse->ppsfd); /* close separate PPS source */
2633 * print statistics a last time and
2634 * stop statistics machine
2636 parse_statistics(parse);
2638 if (parse->parse_type->cl_end)
2640 parse->parse_type->cl_end(parse);
2644 * cleanup before leaving this world
2646 if (parse->binding)
2647 PARSE_END(parse);
2650 * Tell the I/O module to turn us off. We're history.
2652 io_closeclock(&parse->generic->io);
2654 free_varlist(parse->kv);
2656 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2657 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2658 CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2660 parse->peer = (struct peer *)0; /* unused now */
2661 peer->procptr->unitptr = (caddr_t)0;
2662 free(parse);
2665 #ifdef HAVE_PPSAPI
2666 /*----------------------------------------
2667 * set up HARDPPS via PPSAPI
2669 static void
2670 parse_hardpps(
2671 struct parseunit *parse,
2672 int mode
2675 if (parse->hardppsstate == mode)
2676 return;
2678 if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2679 int i = 0;
2681 if (mode == PARSE_HARDPPS_ENABLE)
2683 if (parse->flags & PARSE_CLEAR)
2684 i = PPS_CAPTURECLEAR;
2685 else
2686 i = PPS_CAPTUREASSERT;
2689 if (time_pps_kcbind(parse->ppshandle, PPS_KC_HARDPPS, i,
2690 PPS_TSFMT_TSPEC) < 0) {
2691 msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2692 CLK_UNIT(parse->peer));
2693 } else {
2694 NLOG(NLOG_CLOCKINFO)
2695 msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2696 CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2698 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2700 if (mode == PARSE_HARDPPS_ENABLE)
2701 pps_enable = 1;
2705 parse->hardppsstate = mode;
2708 /*----------------------------------------
2709 * set up PPS via PPSAPI
2711 static int
2712 parse_ppsapi(
2713 struct parseunit *parse
2716 int cap, mode, mode1;
2717 char *cp;
2719 parse->flags &= ~PARSE_PPSCLOCK;
2721 if (time_pps_getcap(parse->ppshandle, &cap) < 0) {
2722 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2723 CLK_UNIT(parse->peer));
2725 return 0;
2728 if (time_pps_getparams(parse->ppshandle, &parse->ppsparams) < 0) {
2729 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getparams failed: %m",
2730 CLK_UNIT(parse->peer));
2731 return 0;
2734 /* nb. only turn things on, if someone else has turned something
2735 * on before we get here, leave it alone!
2738 if (parse->flags & PARSE_CLEAR) {
2739 cp = "CLEAR";
2740 mode = PPS_CAPTURECLEAR;
2741 mode1 = PPS_OFFSETCLEAR;
2742 } else {
2743 cp = "ASSERT";
2744 mode = PPS_CAPTUREASSERT;
2745 mode1 = PPS_OFFSETASSERT;
2748 msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2749 CLK_UNIT(parse->peer), cp);
2751 if (!(mode & cap)) {
2752 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED to initialize PPS to %s (PPS API capabilities=0x%x)",
2753 CLK_UNIT(parse->peer), cp, cap);
2755 return 0;
2758 if (!(mode1 & cap)) {
2759 msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2760 CLK_UNIT(parse->peer), cp, cap);
2761 mode1 = 0;
2762 } else {
2763 if (mode1 == PPS_OFFSETCLEAR)
2765 parse->ppsparams.clear_offset.tv_sec = -parse->ppsphaseadjust;
2766 parse->ppsparams.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2769 if (mode1 == PPS_OFFSETASSERT)
2771 parse->ppsparams.assert_offset.tv_sec = -parse->ppsphaseadjust;
2772 parse->ppsparams.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2776 /* only set what is legal */
2778 parse->ppsparams.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap;
2780 if (time_pps_setparams(parse->ppshandle, &parse->ppsparams) < 0) {
2781 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2782 CLK_UNIT(parse->peer));
2783 return 0;
2786 parse->flags |= PARSE_PPSCLOCK;
2787 return 1;
2789 #else
2790 #define parse_hardpps(_PARSE_, _MODE_) /* empty */
2791 #endif
2793 /*--------------------------------------------------
2794 * parse_start - open the PARSE devices and initialize data for processing
2796 static int
2797 parse_start(
2798 int sysunit,
2799 struct peer *peer
2802 u_int unit;
2803 int fd232;
2804 #ifdef HAVE_TERMIOS
2805 struct termios tio; /* NEEDED FOR A LONG TIME ! */
2806 #endif
2807 #ifdef HAVE_SYSV_TTYS
2808 struct termio tio; /* NEEDED FOR A LONG TIME ! */
2809 #endif
2810 struct parseunit * parse;
2811 char parsedev[sizeof(PARSEDEVICE)+20];
2812 char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
2813 parsectl_t tmp_ctl;
2814 u_int type;
2817 * get out Copyright information once
2819 if (!notice)
2821 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2822 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2006, Frank Kardel");
2823 notice = 1;
2826 type = CLK_TYPE(peer);
2827 unit = CLK_UNIT(peer);
2829 if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0))
2831 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2832 unit, CLK_REALTYPE(peer), ncltypes-1);
2833 return 0;
2837 * Unit okay, attempt to open the device.
2839 (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
2840 (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
2842 #ifndef O_NOCTTY
2843 #define O_NOCTTY 0
2844 #endif
2846 fd232 = open(parsedev, O_RDWR | O_NOCTTY
2847 #ifdef O_NONBLOCK
2848 | O_NONBLOCK
2849 #endif
2850 , 0777);
2852 if (fd232 == -1)
2854 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
2855 return 0;
2858 parse = (struct parseunit *)emalloc(sizeof(struct parseunit));
2860 memset((char *)parse, 0, sizeof(struct parseunit));
2862 parse->generic = peer->procptr; /* link up */
2863 parse->generic->unitptr = (caddr_t)parse; /* link down */
2866 * Set up the structures
2868 parse->generic->timestarted = current_time;
2869 parse->lastchange = current_time;
2871 parse->flags = 0;
2872 parse->pollneeddata = 0;
2873 parse->laststatistic = current_time;
2874 parse->lastformat = (unsigned short)~0; /* assume no format known */
2875 parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */
2876 parse->lastmissed = 0; /* assume got everything */
2877 parse->ppsserial = 0;
2878 parse->ppsfd = -1;
2879 parse->localdata = (void *)0;
2880 parse->localstate = 0;
2881 parse->kv = (struct ctl_var *)0;
2883 clear_err(parse, ERR_ALL);
2885 parse->parse_type = &parse_clockinfo[type];
2887 parse->maxunsync = parse->parse_type->cl_maxunsync;
2889 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
2891 parse->generic->fudgetime2 = 0.0;
2892 parse->ppsphaseadjust = parse->generic->fudgetime2;
2894 parse->generic->clockdesc = parse->parse_type->cl_description;
2896 peer->rootdelay = parse->parse_type->cl_rootdelay;
2897 peer->sstclktype = parse->parse_type->cl_type;
2898 peer->precision = sys_precision;
2900 peer->stratum = STRATUM_REFCLOCK;
2902 if (peer->stratum <= 1)
2903 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
2904 else
2905 parse->generic->refid = htonl(PARSEHSREFID);
2907 parse->generic->io.fd = fd232;
2909 parse->peer = peer; /* marks it also as busy */
2912 * configure terminal line
2914 if (TTY_GETATTR(fd232, &tio) == -1)
2916 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
2917 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2918 return 0;
2920 else
2922 #ifndef _PC_VDISABLE
2923 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
2924 #else
2925 int disablec;
2926 errno = 0; /* pathconf can deliver -1 without changing errno ! */
2928 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
2929 if (disablec == -1 && errno)
2931 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
2932 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
2934 else
2935 if (disablec != -1)
2936 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
2937 #endif
2939 #if defined (VMIN) || defined(VTIME)
2940 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
2942 #ifdef VMIN
2943 tio.c_cc[VMIN] = 1;
2944 #endif
2945 #ifdef VTIME
2946 tio.c_cc[VTIME] = 0;
2947 #endif
2949 #endif
2951 tio.c_cflag = parse_clockinfo[type].cl_cflag;
2952 tio.c_iflag = parse_clockinfo[type].cl_iflag;
2953 tio.c_oflag = parse_clockinfo[type].cl_oflag;
2954 tio.c_lflag = parse_clockinfo[type].cl_lflag;
2957 #ifdef HAVE_TERMIOS
2958 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
2959 (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
2961 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
2962 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
2963 return 0;
2965 #else
2966 tio.c_cflag |= parse_clockinfo[type].cl_speed;
2967 #endif
2970 * set up pps device
2971 * if the PARSEPPSDEVICE can be opened that will be used
2972 * for PPS else PARSEDEVICE will be used
2974 parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY
2975 #ifdef O_NONBLOCK
2976 | O_NONBLOCK
2977 #endif
2978 , 0777);
2980 if (parse->ppsfd == -1)
2982 parse->ppsfd = fd232;
2986 * Linux PPS - the old way
2988 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */
2990 struct serial_struct ss;
2991 if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
2993 #ifdef ASYNC_LOW_LATENCY
2994 ss.flags |= ASYNC_LOW_LATENCY,
2995 #endif
2996 #ifndef HAVE_PPSAPI
2997 #ifdef ASYNC_PPS_CD_NEG
2998 ss.flags |= ASYNC_PPS_CD_NEG,
2999 #endif
3000 #endif
3001 ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3002 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3003 msyslog(LOG_NOTICE,
3004 "refclock_parse: optional PPS processing not available");
3005 } else {
3006 parse->flags |= PARSE_PPSCLOCK;
3007 #ifdef ASYNC_PPS_CD_NEG
3008 NLOG(NLOG_CLOCKINFO)
3009 msyslog(LOG_INFO,
3010 "refclock_parse: PPS detection on");
3011 #endif
3014 #endif
3017 * SUN the Solaris way
3019 #ifdef HAVE_TIOCSPPS /* SUN PPS support */
3020 if (CLK_PPS(parse->peer))
3022 int i = 1;
3024 if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3026 parse->flags |= PARSE_PPSCLOCK;
3029 #endif
3032 * PPS via PPSAPI
3034 #if defined(HAVE_PPSAPI)
3035 parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3036 if (CLK_PPS(parse->peer))
3038 if (time_pps_create(parse->ppsfd, &parse->ppshandle) < 0)
3040 msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3042 else
3044 parse_ppsapi(parse);
3047 #endif
3049 if (TTY_SETATTR(fd232, &tio) == -1)
3051 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
3052 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3053 return 0;
3058 * pick correct input machine
3060 parse->generic->io.srcclock = (caddr_t)parse;
3061 parse->generic->io.datalen = 0;
3063 parse->binding = init_iobinding(parse);
3065 if (parse->binding == (bind_t *)0)
3067 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
3068 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3069 return 0; /* well, ok - special initialisation broke */
3072 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3073 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */
3076 * as we always(?) get 8 bit chars we want to be
3077 * sure, that the upper bits are zero for less
3078 * than 8 bit I/O - so we pass that information on.
3079 * note that there can be only one bit count format
3080 * per file descriptor
3083 switch (tio.c_cflag & CSIZE)
3085 case CS5:
3086 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
3087 break;
3089 case CS6:
3090 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
3091 break;
3093 case CS7:
3094 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
3095 break;
3097 case CS8:
3098 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
3099 break;
3102 if (!PARSE_SETCS(parse, &tmp_ctl))
3104 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
3105 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3106 return 0; /* well, ok - special initialisation broke */
3109 strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3110 tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
3112 if (!PARSE_SETFMT(parse, &tmp_ctl))
3114 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
3115 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3116 return 0; /* well, ok - special initialisation broke */
3120 * get rid of all IO accumulated so far
3122 #ifdef HAVE_TERMIOS
3123 (void) tcflush(parse->generic->io.fd, TCIOFLUSH);
3124 #else
3125 #if defined(TCFLSH) && defined(TCIOFLUSH)
3127 int flshcmd = TCIOFLUSH;
3129 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
3131 #endif
3132 #endif
3135 * try to do any special initializations
3137 if (parse->parse_type->cl_init)
3139 if (parse->parse_type->cl_init(parse))
3141 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3142 return 0; /* well, ok - special initialisation broke */
3147 * Insert in async io device list.
3149 if (!io_addclock(&parse->generic->io))
3151 msyslog(LOG_ERR,
3152 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3153 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3154 return 0;
3158 * print out configuration
3160 NLOG(NLOG_CLOCKINFO)
3162 /* conditional if clause for conditional syslog */
3163 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3164 CLK_UNIT(parse->peer),
3165 parse->parse_type->cl_description, parsedev,
3166 (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
3168 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3169 CLK_UNIT(parse->peer),
3170 parse->peer->stratum,
3171 l_mktime(parse->maxunsync), parse->peer->precision);
3173 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3174 CLK_UNIT(parse->peer),
3175 parse->parse_type->cl_rootdelay,
3176 parse->generic->fudgetime1,
3177 parse->ppsphaseadjust,
3178 parse->binding->bd_description);
3180 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
3181 parse->parse_type->cl_format);
3182 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3183 CLK_PPS(parse->peer) ? "" : "NO ",
3184 CLK_PPS(parse->peer) ?
3185 #ifdef PPS_METHOD
3186 " (implementation " PPS_METHOD ")"
3187 #else
3189 #endif
3190 : ""
3194 return 1;
3197 /*--------------------------------------------------
3198 * parse_ctl - process changes on flags/time values
3200 static void
3201 parse_ctl(
3202 struct parseunit *parse,
3203 struct refclockstat *in
3206 if (in)
3208 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3210 parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3211 (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3212 #if defined(HAVE_PPSAPI)
3213 if (CLK_PPS(parse->peer))
3215 parse_ppsapi(parse);
3217 #endif
3220 if (in->haveflags & CLK_HAVETIME1)
3222 parse->generic->fudgetime1 = in->fudgetime1;
3223 msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3224 CLK_UNIT(parse->peer),
3225 parse->generic->fudgetime1);
3228 if (in->haveflags & CLK_HAVETIME2)
3230 parse->generic->fudgetime2 = in->fudgetime2;
3231 if (parse->flags & PARSE_TRUSTTIME)
3233 parse->maxunsync = (u_long)ABS(in->fudgetime2);
3234 msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3235 CLK_UNIT(parse->peer),
3236 l_mktime(parse->maxunsync));
3238 else
3240 parse->ppsphaseadjust = in->fudgetime2;
3241 msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3242 CLK_UNIT(parse->peer),
3243 parse->ppsphaseadjust);
3244 #if defined(HAVE_PPSAPI)
3245 if (CLK_PPS(parse->peer))
3247 parse_ppsapi(parse);
3249 #endif
3255 /*--------------------------------------------------
3256 * parse_poll - called by the transmit procedure
3258 static void
3259 parse_poll(
3260 int unit,
3261 struct peer *peer
3264 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3266 if (peer != parse->peer)
3268 msyslog(LOG_ERR,
3269 "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3270 unit);
3271 return;
3275 * Update clock stat counters
3277 parse->generic->polls++;
3279 if (parse->pollneeddata &&
3280 ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
3283 * start worrying when exceeding a poll inteval
3284 * bad news - didn't get a response last time
3286 parse->lastmissed = current_time;
3287 parse_event(parse, CEVNT_TIMEOUT);
3289 ERR(ERR_NODATA)
3290 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
3294 * we just mark that we want the next sample for the clock filter
3296 parse->pollneeddata = current_time;
3298 if (parse->parse_type->cl_poll)
3300 parse->parse_type->cl_poll(parse);
3303 cparse_statistics(parse);
3305 return;
3308 #define LEN_STATES 300 /* length of state string */
3310 /*--------------------------------------------------
3311 * parse_control - set fudge factors, return statistics
3313 static void
3314 parse_control(
3315 int unit,
3316 struct refclockstat *in,
3317 struct refclockstat *out,
3318 struct peer *peer
3321 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
3322 parsectl_t tmpctl;
3324 static char outstatus[400]; /* status output buffer */
3326 if (out)
3328 out->lencode = 0;
3329 out->p_lastcode = 0;
3330 out->kv_list = (struct ctl_var *)0;
3333 if (!parse || !parse->peer)
3335 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3336 unit);
3337 return;
3340 unit = CLK_UNIT(parse->peer);
3343 * handle changes
3345 parse_ctl(parse, in);
3348 * supply data
3350 if (out)
3352 u_long sum = 0;
3353 char *tt, *start;
3354 int i;
3356 outstatus[0] = '\0';
3358 out->type = REFCLK_PARSE;
3361 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3363 parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3366 * figure out skew between PPS and RS232 - just for informational
3367 * purposes
3369 if (PARSE_SYNC(parse->timedata.parse_state))
3371 if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
3373 l_fp off;
3376 * we have a PPS and RS232 signal - calculate the skew
3377 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3379 off = parse->timedata.parse_stime.fp;
3380 L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
3381 tt = add_var(&out->kv_list, 80, RO);
3382 snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
3386 if (PARSE_PPS(parse->timedata.parse_state))
3388 tt = add_var(&out->kv_list, 80, RO|DEF);
3389 snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
3392 start = tt = add_var(&out->kv_list, 128, RO|DEF);
3393 snprintf(tt, 128, "refclock_time=\"");
3394 tt += strlen(tt);
3396 if (parse->timedata.parse_time.fp.l_ui == 0)
3398 strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128));
3400 else
3402 snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp));
3405 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3407 ERR(ERR_INTERNAL)
3408 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
3410 else
3412 start = tt = add_var(&out->kv_list, 512, RO|DEF);
3413 snprintf(tt, 512, "refclock_status=\"");
3414 tt += strlen(tt);
3417 * copy PPS flags from last read transaction (informational only)
3419 tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
3420 (PARSEB_PPS|PARSEB_S_PPS);
3422 (void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
3424 strncat(tt, "\"", BUFFER_SIZES(start, tt, 512));
3426 if (tmpctl.parsegettc.parse_count)
3427 mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3428 tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
3432 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3434 if (!PARSE_GETFMT(parse, &tmpctl))
3436 ERR(ERR_INTERNAL)
3437 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
3439 else
3441 tt = add_var(&out->kv_list, 80, RO|DEF);
3442 snprintf(tt, 80, "refclock_format=\"");
3444 strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
3445 strncat(tt,"\"", 80);
3449 * gather state statistics
3452 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3453 strncpy(tt, "refclock_states=\"", LEN_STATES);
3454 tt += strlen(tt);
3456 for (i = 0; i <= CEVNT_MAX; i++)
3458 u_long s_time;
3459 u_long d = current_time - parse->generic->timestarted;
3460 u_long percent;
3462 percent = s_time = PARSE_STATETIME(parse, i);
3464 while (((u_long)(~0) / 10000) < percent)
3466 percent /= 10;
3467 d /= 10;
3470 if (d)
3471 percent = (percent * 10000) / d;
3472 else
3473 percent = 10000;
3475 if (s_time)
3477 char item[80];
3478 int count;
3480 snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
3481 sum ? "; " : "",
3482 (parse->generic->currentstatus == i) ? "*" : "",
3483 clockstatus((unsigned int)i),
3484 l_mktime(s_time),
3485 (int)(percent / 100), (int)(percent % 100));
3486 if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3488 strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES));
3489 tt += count;
3491 sum += s_time;
3495 snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum));
3497 tt = add_var(&out->kv_list, 32, RO);
3498 snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id);
3500 tt = add_var(&out->kv_list, 80, RO);
3501 snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description);
3503 tt = add_var(&out->kv_list, 128, RO);
3504 snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3507 struct ctl_var *k;
3509 k = parse->kv;
3510 while (k && !(k->flags & EOV))
3512 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3513 k++;
3517 out->lencode = strlen(outstatus);
3518 out->p_lastcode = outstatus;
3522 /**===========================================================================
3523 ** processing routines
3526 /*--------------------------------------------------
3527 * event handling - note that nominal events will also be posted
3528 * keep track of state dwelling times
3530 static void
3531 parse_event(
3532 struct parseunit *parse,
3533 int event
3536 if (parse->generic->currentstatus != (u_char) event)
3538 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3539 parse->lastchange = current_time;
3541 if (parse->parse_type->cl_event)
3542 parse->parse_type->cl_event(parse, event);
3544 if (event == CEVNT_NOMINAL)
3546 NLOG(NLOG_CLOCKSTATUS)
3547 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3548 CLK_UNIT(parse->peer));
3551 refclock_report(parse->peer, event);
3555 /*--------------------------------------------------
3556 * process a PARSE time sample
3558 static void
3559 parse_process(
3560 struct parseunit *parse,
3561 parsetime_t *parsetime
3564 l_fp off, rectime, reftime;
3565 double fudge;
3568 * check for changes in conversion status
3569 * (only one for each new status !)
3571 if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3572 ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3573 (parse->timedata.parse_status != parsetime->parse_status))
3575 char buffer[400];
3577 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3578 msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3579 CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3581 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3584 * tell more about the story - list time code
3585 * there is a slight change for a race condition and
3586 * the time code might be overwritten by the next packet
3588 parsectl_t tmpctl;
3590 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3592 ERR(ERR_INTERNAL)
3593 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3595 else
3597 ERR(ERR_BADDATA)
3598 msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3599 CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
3605 * examine status and post appropriate events
3607 if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3610 * got bad data - tell the rest of the system
3612 switch (parsetime->parse_status & CVT_MASK)
3614 case CVT_NONE:
3615 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3616 parse->parse_type->cl_message)
3617 parse->parse_type->cl_message(parse, parsetime);
3619 * save PPS information that comes piggyback
3621 if (PARSE_PPS(parsetime->parse_state))
3623 parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3624 parse->timedata.parse_ptime = parsetime->parse_ptime;
3626 break; /* well, still waiting - timeout is handled at higher levels */
3628 case CVT_FAIL:
3629 if (parsetime->parse_status & CVT_BADFMT)
3631 parse_event(parse, CEVNT_BADREPLY);
3633 else
3634 if (parsetime->parse_status & CVT_BADDATE)
3636 parse_event(parse, CEVNT_BADDATE);
3638 else
3639 if (parsetime->parse_status & CVT_BADTIME)
3641 parse_event(parse, CEVNT_BADTIME);
3643 else
3645 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3648 return; /* skip the rest - useless */
3652 * check for format changes
3653 * (in case somebody has swapped clocks 8-)
3655 if (parse->lastformat != parsetime->parse_format)
3657 parsectl_t tmpctl;
3659 tmpctl.parseformat.parse_format = parsetime->parse_format;
3661 if (!PARSE_GETFMT(parse, &tmpctl))
3663 ERR(ERR_INTERNAL)
3664 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3666 else
3668 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3669 msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3670 CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3672 parse->lastformat = parsetime->parse_format;
3676 * now, any changes ?
3678 if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3679 ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
3681 char tmp1[200];
3682 char tmp2[200];
3684 * something happend - except for PPS events
3687 (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3688 (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3690 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3691 msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3692 CLK_UNIT(parse->peer), tmp2, tmp1);
3696 * carry on PPS information if still usable
3698 if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3700 parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3701 parsetime->parse_ptime = parse->timedata.parse_ptime;
3705 * remember for future
3707 parse->timedata = *parsetime;
3710 * check to see, whether the clock did a complete powerup or lost PZF signal
3711 * and post correct events for current condition
3713 if (PARSE_POWERUP(parsetime->parse_state))
3716 * this is bad, as we have completely lost synchronisation
3717 * well this is a problem with the receiver here
3718 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3719 * is true as it is the powerup state and the time is taken
3720 * from a crude real time clock chip
3721 * for the PZF series this is only partly true, as
3722 * PARSE_POWERUP only means that the pseudo random
3723 * phase shift sequence cannot be found. this is only
3724 * bad, if we have never seen the clock in the SYNC
3725 * state, where the PHASE and EPOCH are correct.
3726 * for reporting events the above business does not
3727 * really matter, but we can use the time code
3728 * even in the POWERUP state after having seen
3729 * the clock in the synchronized state (PZF class
3730 * receivers) unless we have had a telegram disruption
3731 * after having seen the clock in the SYNC state. we
3732 * thus require having seen the clock in SYNC state
3733 * *after* having missed telegrams (noresponse) from
3734 * the clock. one problem remains: we might use erroneously
3735 * POWERUP data if the disruption is shorter than 1 polling
3736 * interval. fortunately powerdowns last usually longer than 64
3737 * seconds and the receiver is at least 2 minutes in the
3738 * POWERUP or NOSYNC state before switching to SYNC
3740 parse_event(parse, CEVNT_FAULT);
3741 NLOG(NLOG_CLOCKSTATUS)
3742 ERR(ERR_BADSTATUS)
3743 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
3744 CLK_UNIT(parse->peer));
3746 else
3749 * we have two states left
3751 * SYNC:
3752 * this state means that the EPOCH (timecode) and PHASE
3753 * information has be read correctly (at least two
3754 * successive PARSE timecodes were received correctly)
3755 * this is the best possible state - full trust
3757 * NOSYNC:
3758 * The clock should be on phase with respect to the second
3759 * signal, but the timecode has not been received correctly within
3760 * at least the last two minutes. this is a sort of half baked state
3761 * for PARSE Meinberg DCF77 clocks this is bad news (clock running
3762 * without timecode confirmation)
3763 * PZF 535 has also no time confirmation, but the phase should be
3764 * very precise as the PZF signal can be decoded
3767 if (PARSE_SYNC(parsetime->parse_state))
3770 * currently completely synchronized - best possible state
3772 parse->lastsync = current_time;
3773 clear_err(parse, ERR_BADSTATUS);
3775 else
3778 * we have had some problems receiving the time code
3780 parse_event(parse, CEVNT_PROP);
3781 NLOG(NLOG_CLOCKSTATUS)
3782 ERR(ERR_BADSTATUS)
3783 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3784 CLK_UNIT(parse->peer));
3788 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3790 if (PARSE_TIMECODE(parsetime->parse_state))
3792 rectime = parsetime->parse_stime.fp;
3793 off = reftime = parsetime->parse_time.fp;
3795 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
3797 #ifdef DEBUG
3798 if (debug > 3)
3799 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3800 CLK_UNIT(parse->peer),
3801 prettydate(&reftime),
3802 prettydate(&rectime),
3803 lfptoa(&off,6));
3804 #endif
3807 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3809 l_fp offset;
3810 double ppsphaseadjust = parse->ppsphaseadjust;
3812 #ifdef HAVE_PPSAPI
3814 * set fudge = 0.0 if already included in PPS time stamps
3816 if (parse->ppsparams.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3818 ppsphaseadjust = 0.0;
3820 #endif
3823 * we have a PPS signal - much better than the RS232 stuff (we hope)
3825 offset = parsetime->parse_ptime.fp;
3827 #ifdef DEBUG
3828 if (debug > 3)
3829 printf("PARSE receiver #%d: PPStime %s\n",
3830 CLK_UNIT(parse->peer),
3831 prettydate(&offset));
3832 #endif
3833 if (PARSE_TIMECODE(parsetime->parse_state))
3835 if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
3836 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
3838 fudge = ppsphaseadjust; /* pick PPS fudge factor */
3841 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
3844 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
3846 reftime = off = offset;
3847 if (reftime.l_uf & (unsigned)0x80000000)
3848 reftime.l_ui++;
3849 reftime.l_uf = 0;
3853 * implied on second offset
3855 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3856 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3858 else
3861 * time code describes pulse
3863 reftime = off = parsetime->parse_time.fp;
3865 L_SUB(&off, &offset); /* true offset */
3869 * take RS232 offset when PPS when out of bounds
3872 else
3874 fudge = ppsphaseadjust; /* pick PPS fudge factor */
3876 * Well, no time code to guide us - assume on second pulse
3877 * and pray, that we are within [-0.5..0.5[
3879 off = offset;
3880 reftime = offset;
3881 if (reftime.l_uf & (unsigned)0x80000000)
3882 reftime.l_ui++;
3883 reftime.l_uf = 0;
3885 * implied on second offset
3887 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
3888 off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
3891 else
3893 if (!PARSE_TIMECODE(parsetime->parse_state))
3896 * Well, no PPS, no TIMECODE, no more work ...
3898 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3899 parse->parse_type->cl_message)
3900 parse->parse_type->cl_message(parse, parsetime);
3901 return;
3905 #ifdef DEBUG
3906 if (debug > 3)
3907 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
3908 CLK_UNIT(parse->peer),
3909 prettydate(&reftime),
3910 prettydate(&rectime),
3911 lfptoa(&off,6));
3912 #endif
3915 rectime = reftime;
3916 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */
3918 #ifdef DEBUG
3919 if (debug > 3)
3920 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
3921 CLK_UNIT(parse->peer),
3922 prettydate(&reftime),
3923 prettydate(&rectime));
3924 #endif
3926 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3927 parse->parse_type->cl_message)
3928 parse->parse_type->cl_message(parse, parsetime);
3930 if (PARSE_SYNC(parsetime->parse_state))
3933 * log OK status
3935 parse_event(parse, CEVNT_NOMINAL);
3938 clear_err(parse, ERR_BADIO);
3939 clear_err(parse, ERR_BADDATA);
3940 clear_err(parse, ERR_NODATA);
3941 clear_err(parse, ERR_INTERNAL);
3944 * and now stick it into the clock machine
3945 * samples are only valid iff lastsync is not too old and
3946 * we have seen the clock in sync at least once
3947 * after the last time we didn't see an expected data telegram
3948 * at startup being not in sync is also bad just like
3949 * POWERUP state
3950 * see the clock states section above for more reasoning
3952 if (((current_time - parse->lastsync) > parse->maxunsync) ||
3953 (parse->lastsync < parse->lastmissed) ||
3954 ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
3955 PARSE_POWERUP(parsetime->parse_state))
3957 parse->generic->leap = LEAP_NOTINSYNC;
3958 parse->lastsync = 0; /* wait for full sync again */
3960 else
3962 if (PARSE_LEAPADD(parsetime->parse_state))
3965 * we pick this state also for time code that pass leap warnings
3966 * without direction information (as earth is currently slowing
3967 * down).
3969 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
3971 else
3972 if (PARSE_LEAPDEL(parsetime->parse_state))
3974 parse->generic->leap = LEAP_DELSECOND;
3976 else
3978 parse->generic->leap = LEAP_NOWARNING;
3982 if (parse->generic->leap != LEAP_NOTINSYNC)
3985 * only good/trusted samples are interesting
3987 #ifdef DEBUG
3988 if (debug > 2)
3990 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
3991 CLK_UNIT(parse->peer),
3992 prettydate(&reftime),
3993 prettydate(&rectime),
3994 fudge);
3996 #endif
3997 parse->generic->lastref = reftime;
3999 refclock_process_offset(parse->generic, reftime, rectime, fudge);
4002 * pass PPS information on to PPS clock
4004 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4006 (void) pps_sample(&parse->timedata.parse_ptime.fp);
4007 parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4009 } else {
4010 parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4014 * ready, unless the machine wants a sample or
4015 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4017 if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
4018 return;
4020 parse->pollneeddata = 0;
4022 parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4024 refclock_receive(parse->peer);
4027 /**===========================================================================
4028 ** special code for special clocks
4031 static void
4032 mk_utcinfo(
4033 char *t,
4034 int wnt,
4035 int wnlsf,
4036 int dn,
4037 int dtls,
4038 int dtlsf,
4039 int size
4042 l_fp leapdate;
4043 char *start = t;
4045 snprintf(t, size, "current correction %d sec", dtls);
4046 t += strlen(t);
4048 if (wnlsf < 990)
4049 wnlsf += 1024;
4051 if (wnt < 990)
4052 wnt += 1024;
4054 gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
4056 if ((dtlsf != dtls) &&
4057 ((wnlsf - wnt) < 52))
4059 snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
4060 dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
4062 else
4064 snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
4065 gmprettydate(&leapdate));
4069 #ifdef CLOCK_MEINBERG
4070 /**===========================================================================
4071 ** Meinberg GPS166/GPS167 support
4074 /*------------------------------------------------------------
4075 * gps16x_message - process GPS16x messages
4077 static void
4078 gps16x_message(
4079 struct parseunit *parse,
4080 parsetime_t *parsetime
4083 if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
4085 GPS_MSG_HDR header;
4086 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4088 #ifdef DEBUG
4089 if (debug > 2)
4091 char msgbuffer[600];
4093 mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
4094 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4095 CLK_UNIT(parse->peer),
4096 parsetime->parse_msglen,
4097 msgbuffer);
4099 #endif
4100 get_mbg_header(&bufp, &header);
4101 if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4102 (header.gps_len == 0 ||
4103 (header.gps_len < sizeof(parsetime->parse_msg) &&
4104 header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
4107 * clean message
4109 switch (header.gps_cmd)
4111 case GPS_SW_REV:
4113 char buffer[64];
4114 SW_REV gps_sw_rev;
4116 get_mbg_sw_rev(&bufp, &gps_sw_rev);
4117 snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
4118 (gps_sw_rev.code >> 8) & 0xFF,
4119 gps_sw_rev.code & 0xFF,
4120 gps_sw_rev.name[0] ? " " : "",
4121 gps_sw_rev.name);
4122 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4124 break;
4126 case GPS_STAT:
4128 static struct state
4130 unsigned short flag; /* status flag */
4131 unsigned const char *string; /* bit name */
4132 } states[] =
4134 { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
4135 { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" },
4136 { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" },
4137 { TM_NO_POS, (const unsigned char *)"NO POSITION" },
4138 { 0, (const unsigned char *)"" }
4140 unsigned short status;
4141 struct state *s = states;
4142 char buffer[512];
4143 char *p, *b;
4145 status = get_lsb_short(&bufp);
4146 snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status);
4148 if (status)
4150 p = b = buffer + strlen(buffer);
4151 while (s->flag)
4153 if (status & s->flag)
4155 if (p != b)
4157 *p++ = ',';
4158 *p++ = ' ';
4161 strncat(p, (const char *)s->string, sizeof(buffer));
4163 s++;
4166 *p++ = '"';
4167 *p = '\0';
4169 else
4171 strncat(buffer, "<OK>\"", sizeof(buffer));
4174 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4176 break;
4178 case GPS_POS_XYZ:
4180 XYZ xyz;
4181 char buffer[256];
4183 get_mbg_xyz(&bufp, xyz);
4184 snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4185 mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
4186 mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
4187 mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4189 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4191 break;
4193 case GPS_POS_LLA:
4195 LLA lla;
4196 char buffer[256];
4198 get_mbg_lla(&bufp, lla);
4200 snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4201 mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4202 mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
4203 mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4205 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4207 break;
4209 case GPS_TZDL:
4210 break;
4212 case GPS_PORT_PARM:
4213 break;
4215 case GPS_SYNTH:
4216 break;
4218 case GPS_ANT_INFO:
4220 ANT_INFO antinfo;
4221 char buffer[512];
4222 char *p;
4224 get_mbg_antinfo(&bufp, &antinfo);
4225 snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\"");
4226 p = buffer + strlen(buffer);
4228 switch (antinfo.status)
4230 case ANT_INVALID:
4231 strncat(p, "<OK>", BUFFER_SIZE(buffer, p));
4232 p += strlen(p);
4233 break;
4235 case ANT_DISCONN:
4236 strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p));
4237 NLOG(NLOG_CLOCKSTATUS)
4238 ERR(ERR_BADSTATUS)
4239 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4240 CLK_UNIT(parse->peer), p);
4242 p += strlen(p);
4243 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4244 *p = '\0';
4245 break;
4247 case ANT_RECONN:
4248 strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p));
4249 p += strlen(p);
4250 mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4251 snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
4252 (antinfo.delta_t < 0) ? '-' : '+',
4253 ABS(antinfo.delta_t) / 10000,
4254 ABS(antinfo.delta_t) % 10000);
4255 p += strlen(p);
4256 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4257 *p = '\0';
4258 break;
4260 default:
4261 snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status);
4262 p += strlen(p);
4263 break;
4266 strncat(p, "\"", BUFFER_SIZE(buffer, p));
4268 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4270 break;
4272 case GPS_UCAP:
4273 break;
4275 case GPS_CFGH:
4277 CFGH cfgh;
4278 char buffer[512];
4279 char *p;
4281 get_mbg_cfgh(&bufp, &cfgh);
4282 if (cfgh.valid)
4284 int i;
4286 p = buffer;
4287 strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p));
4288 p += strlen(p);
4289 mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4290 strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4291 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4293 p = buffer;
4294 strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p));
4295 p += strlen(p);
4296 mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4297 strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4298 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4300 p = buffer;
4301 strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p));
4302 p += strlen(p);
4303 mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4304 strncpy(p, "\"", BUFFER_SIZE(buffer, p));
4305 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4307 for (i = MIN_SVNO; i < MAX_SVNO; i++)
4309 p = buffer;
4310 snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
4311 p += strlen(p);
4312 switch (cfgh.cfg[i] & 0x7)
4314 case 0:
4315 strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p));
4316 break;
4317 case 1:
4318 strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p));
4319 break;
4320 default:
4321 strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p));
4322 break;
4324 strncat(p, "\"", BUFFER_SIZE(buffer, p));
4325 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4327 p = buffer;
4328 snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
4329 p += strlen(p);
4330 switch ((cfgh.health[i] >> 5) & 0x7 )
4332 case 0:
4333 strncpy(p, "OK;", BUFFER_SIZE(buffer, p));
4334 break;
4335 case 1:
4336 strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p));
4337 break;
4338 case 2:
4339 strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p));
4340 break;
4341 case 3:
4342 strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p));
4343 break;
4344 case 4:
4345 strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p));
4346 break;
4347 case 5:
4348 strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p));
4349 break;
4350 case 6:
4351 strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p));
4352 break;
4353 case 7:
4354 strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p));
4355 break;
4358 p += strlen(p);
4360 switch (cfgh.health[i] & 0x1F)
4362 case 0:
4363 strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p));
4364 break;
4365 case 0x1C:
4366 strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p));
4367 break;
4368 case 0x1D:
4369 strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p));
4370 break;
4371 case 0x1E:
4372 break;
4373 case 0x1F:
4374 strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p));
4375 break;
4376 default:
4377 strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p));
4378 break;
4381 strncat(p, "\"", sizeof(buffer));
4382 set_var(&parse->kv, buffer, strlen(buffer)+1, RO);
4386 break;
4388 case GPS_ALM:
4389 break;
4391 case GPS_EPH:
4392 break;
4394 case GPS_UTC:
4396 UTC utc;
4397 char buffer[512];
4398 char *p;
4400 p = buffer;
4402 get_mbg_utc(&bufp, &utc);
4404 if (utc.valid)
4406 strncpy(p, "gps_utc_correction=\"", sizeof(buffer));
4407 p += strlen(p);
4408 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4409 strncat(p, "\"", BUFFER_SIZE(buffer, p));
4411 else
4413 strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p));
4415 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4417 break;
4419 case GPS_IONO:
4420 break;
4422 case GPS_ASCII_MSG:
4424 ASCII_MSG gps_ascii_msg;
4425 char buffer[128];
4427 get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4429 if (gps_ascii_msg.valid)
4431 char buffer1[128];
4432 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4434 snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
4436 else
4437 strncpy(buffer, "gps_message=<NONE>", sizeof(buffer));
4439 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4442 break;
4444 default:
4445 break;
4448 else
4450 msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)",
4451 CLK_UNIT(parse->peer),
4452 header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4453 header.gps_len,
4454 header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
4458 return;
4461 /*------------------------------------------------------------
4462 * gps16x_poll - query the reciver peridically
4464 static void
4465 gps16x_poll(
4466 struct peer *peer
4469 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4471 static GPS_MSG_HDR sequence[] =
4473 { GPS_SW_REV, 0, 0, 0 },
4474 { GPS_STAT, 0, 0, 0 },
4475 { GPS_UTC, 0, 0, 0 },
4476 { GPS_ASCII_MSG, 0, 0, 0 },
4477 { GPS_ANT_INFO, 0, 0, 0 },
4478 { GPS_CFGH, 0, 0, 0 },
4479 { GPS_POS_XYZ, 0, 0, 0 },
4480 { GPS_POS_LLA, 0, 0, 0 },
4481 { (unsigned short)~0, 0, 0, 0 }
4484 int rtc;
4485 unsigned char cmd_buffer[64];
4486 unsigned char *outp = cmd_buffer;
4487 GPS_MSG_HDR *header;
4489 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4491 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4494 if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
4495 parse->localstate = 0;
4497 header = sequence + parse->localstate++;
4499 *outp++ = SOH; /* start command */
4501 put_mbg_header(&outp, header);
4502 outp = cmd_buffer + 1;
4504 header->gps_hdr_csum = (short)mbg_csum(outp, 6);
4505 put_mbg_header(&outp, header);
4507 #ifdef DEBUG
4508 if (debug > 2)
4510 char buffer[128];
4512 mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4513 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4514 CLK_UNIT(parse->peer),
4515 parse->localstate - 1,
4516 (int)(outp - cmd_buffer),
4517 buffer);
4519 #endif
4521 rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4523 if (rtc < 0)
4525 ERR(ERR_BADIO)
4526 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4528 else
4529 if (rtc != outp - cmd_buffer)
4531 ERR(ERR_BADIO)
4532 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));
4535 clear_err(parse, ERR_BADIO);
4536 return;
4539 /*--------------------------------------------------
4540 * init routine - setup timer
4542 static int
4543 gps16x_poll_init(
4544 struct parseunit *parse
4547 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4549 parse->peer->action = gps16x_poll;
4550 gps16x_poll(parse->peer);
4553 return 0;
4556 #else
4557 static void
4558 gps16x_message(
4559 struct parseunit *parse,
4560 parsetime_t *parsetime
4563 static int
4564 gps16x_poll_init(
4565 struct parseunit *parse
4568 return 1;
4570 #endif /* CLOCK_MEINBERG */
4572 /**===========================================================================
4573 ** clock polling support
4576 /*--------------------------------------------------
4577 * direct poll routine
4579 static void
4580 poll_dpoll(
4581 struct parseunit *parse
4584 int rtc;
4585 const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4586 int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4588 rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
4589 if (rtc < 0)
4591 ERR(ERR_BADIO)
4592 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4594 else
4595 if (rtc != ct)
4597 ERR(ERR_BADIO)
4598 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4600 clear_err(parse, ERR_BADIO);
4603 /*--------------------------------------------------
4604 * periodic poll routine
4606 static void
4607 poll_poll(
4608 struct peer *peer
4611 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
4613 if (parse->parse_type->cl_poll)
4614 parse->parse_type->cl_poll(parse);
4616 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4618 parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4622 /*--------------------------------------------------
4623 * init routine - setup timer
4625 static int
4626 poll_init(
4627 struct parseunit *parse
4630 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4632 parse->peer->action = poll_poll;
4633 poll_poll(parse->peer);
4636 return 0;
4639 /**===========================================================================
4640 ** Trimble support
4643 /*-------------------------------------------------------------
4644 * trimble TAIP init routine - setup EOL and then do poll_init.
4646 static int
4647 trimbletaip_init(
4648 struct parseunit *parse
4651 #ifdef HAVE_TERMIOS
4652 struct termios tio;
4653 #endif
4654 #ifdef HAVE_SYSV_TTYS
4655 struct termio tio;
4656 #endif
4658 * configure terminal line for trimble receiver
4660 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4662 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4663 return 0;
4665 else
4667 tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4669 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4671 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4672 return 0;
4675 return poll_init(parse);
4678 /*--------------------------------------------------
4679 * trimble TAIP event routine - reset receiver upon data format trouble
4681 static const char *taipinit[] = {
4682 ">FPV00000000<",
4683 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4684 ">FTM00020001<",
4685 (char *)0
4688 static void
4689 trimbletaip_event(
4690 struct parseunit *parse,
4691 int event
4694 switch (event)
4696 case CEVNT_BADREPLY: /* reset on garbled input */
4697 case CEVNT_TIMEOUT: /* reset on no input */
4699 const char **iv;
4701 iv = taipinit;
4702 while (*iv)
4704 int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
4705 if (rtc < 0)
4707 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4708 return;
4710 else
4712 if (rtc != strlen(*iv))
4714 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4715 CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4716 return;
4719 iv++;
4722 NLOG(NLOG_CLOCKINFO)
4723 ERR(ERR_BADIO)
4724 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4725 CLK_UNIT(parse->peer));
4727 break;
4729 default: /* ignore */
4730 break;
4735 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4736 * It should support other Trimble receivers which use the Trimble Standard
4737 * Interface Protocol (see below).
4739 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4740 * output, about 1 microsecond wide. The leading edge of the pulse is
4741 * coincident with the change of the GPS second. This is the same as
4742 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4743 * specifically use a feature in the data message as a timing reference, but
4744 * the SVee Six Plus does not do this. In fact there is considerable jitter
4745 * on the timing of the messages, so this driver only supports the use
4746 * of the PPS pulse for accurate timing. Where it is determined that
4747 * the offset is way off, when first starting up ntpd for example,
4748 * the timing of the data stream is used until the offset becomes low enough
4749 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4751 * It can use either option for receiving PPS information - the 'ppsclock'
4752 * stream pushed onto the serial data interface to timestamp the Carrier
4753 * Detect interrupts, where the 1PPS connects to the CD line. This only
4754 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4755 * Config.local. The other option is to use a pulse-stretcher/level-converter
4756 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4757 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4758 * by whichever method, is handled in ntp_loopfilter.c
4760 * The receiver uses a serial message protocol called Trimble Standard
4761 * Interface Protocol (it can support others but this driver only supports
4762 * TSIP). Messages in this protocol have the following form:
4764 * <DLE><id> ... <data> ... <DLE><ETX>
4766 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4767 * on transmission and compressed back to one on reception. Otherwise
4768 * the values of data bytes can be anything. The serial interface is RS-422
4769 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4770 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4771 * and double datatypes. Integers are two bytes, sent most significant first.
4772 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4773 * sign & exponent first. Doubles are IEEE754 double precision floating point
4774 * numbers (8 byte) sent sign & exponent first.
4775 * The receiver supports a large set of messages, only a small subset of
4776 * which are used here. From driver to receiver the following are used:
4778 * ID Description
4780 * 21 Request current time
4781 * 22 Mode Select
4782 * 2C Set/Request operating parameters
4783 * 2F Request UTC info
4784 * 35 Set/Request I/O options
4786 * From receiver to driver the following are recognised:
4788 * ID Description
4790 * 41 GPS Time
4791 * 44 Satellite selection, PDOP, mode
4792 * 46 Receiver health
4793 * 4B Machine code/status
4794 * 4C Report operating parameters (debug only)
4795 * 4F UTC correction data (used to get leap second warnings)
4796 * 55 I/O options (debug only)
4798 * All others are accepted but ignored.
4802 #define PI 3.1415926535898 /* lots of sig figs */
4803 #define D2R PI/180.0
4805 /*-------------------------------------------------------------------
4806 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
4807 * interface to the receiver.
4809 * CAVEAT: the sendflt, sendint routines are byte order dependend and
4810 * float implementation dependend - these must be converted to portable
4811 * versions !
4813 * CURRENT LIMITATION: float implementation. This runs only on systems
4814 * with IEEE754 floats as native floats
4817 typedef struct trimble
4819 u_long last_msg; /* last message received */
4820 u_long last_reset; /* last time a reset was issued */
4821 u_char qtracking; /* query tracking status */
4822 u_long ctrack; /* current tracking set */
4823 u_long ltrack; /* last tracking set */
4824 } trimble_t;
4826 union uval {
4827 u_char bd[8];
4828 int iv;
4829 float fv;
4830 double dv;
4833 struct txbuf
4835 short idx; /* index to first unused byte */
4836 u_char *txt; /* pointer to actual data buffer */
4839 void sendcmd P((struct txbuf *buf, int c));
4840 void sendbyte P((struct txbuf *buf, int b));
4841 void sendetx P((struct txbuf *buf, struct parseunit *parse));
4842 void sendint P((struct txbuf *buf, int a));
4843 void sendflt P((struct txbuf *buf, double a));
4845 void
4846 sendcmd(
4847 struct txbuf *buf,
4848 int c
4851 buf->txt[0] = DLE;
4852 buf->txt[1] = (u_char)c;
4853 buf->idx = 2;
4856 void sendcmd P((struct txbuf *buf, int c));
4857 void sendbyte P((struct txbuf *buf, int b));
4858 void sendetx P((struct txbuf *buf, struct parseunit *parse));
4859 void sendint P((struct txbuf *buf, int a));
4860 void sendflt P((struct txbuf *buf, double a));
4862 void
4863 sendbyte(
4864 struct txbuf *buf,
4865 int b
4868 if (b == DLE)
4869 buf->txt[buf->idx++] = DLE;
4870 buf->txt[buf->idx++] = (u_char)b;
4873 void
4874 sendetx(
4875 struct txbuf *buf,
4876 struct parseunit *parse
4879 buf->txt[buf->idx++] = DLE;
4880 buf->txt[buf->idx++] = ETX;
4882 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
4884 ERR(ERR_BADIO)
4885 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4887 else
4889 #ifdef DEBUG
4890 if (debug > 2)
4892 char buffer[256];
4894 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
4895 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
4896 CLK_UNIT(parse->peer),
4897 buf->idx, buffer);
4899 #endif
4900 clear_err(parse, ERR_BADIO);
4904 void
4905 sendint(
4906 struct txbuf *buf,
4907 int a
4910 /* send 16bit int, msbyte first */
4911 sendbyte(buf, (u_char)((a>>8) & 0xff));
4912 sendbyte(buf, (u_char)(a & 0xff));
4915 void
4916 sendflt(
4917 struct txbuf *buf,
4918 double a
4921 int i;
4922 union uval uval;
4924 uval.fv = a;
4925 #ifdef WORDS_BIGENDIAN
4926 for (i=0; i<=3; i++)
4927 #else
4928 for (i=3; i>=0; i--)
4929 #endif
4930 sendbyte(buf, uval.bd[i]);
4933 #define TRIM_POS_OPT 0x13 /* output position with high precision */
4934 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */
4936 /*--------------------------------------------------
4937 * trimble TSIP setup routine
4939 static int
4940 trimbletsip_setup(
4941 struct parseunit *parse,
4942 const char *reason
4945 u_char buffer[256];
4946 struct txbuf buf;
4947 trimble_t *t = parse->localdata;
4949 if (t && t->last_reset &&
4950 ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
4951 return 1; /* not yet */
4954 if (t)
4955 t->last_reset = current_time;
4957 buf.txt = buffer;
4959 sendcmd(&buf, CMD_CVERSION); /* request software versions */
4960 sendetx(&buf, parse);
4962 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */
4963 sendbyte(&buf, 4); /* static */
4964 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
4965 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */
4966 sendflt(&buf, 12.0); /* PDOP mask = 12 */
4967 sendflt(&buf, 8.0); /* PDOP switch level = 8 */
4968 sendetx(&buf, parse);
4970 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */
4971 sendbyte(&buf, 1); /* time transfer mode */
4972 sendetx(&buf, parse);
4974 sendcmd(&buf, CMD_CMESSAGE); /* request system message */
4975 sendetx(&buf, parse);
4977 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */
4978 sendbyte(&buf, 0x2); /* binary mode */
4979 sendetx(&buf, parse);
4981 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */
4982 sendbyte(&buf, TRIM_POS_OPT); /* position output */
4983 sendbyte(&buf, 0x00); /* no velocity output */
4984 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */
4985 sendbyte(&buf, 0x00); /* no raw measurements */
4986 sendetx(&buf, parse);
4988 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */
4989 sendetx(&buf, parse);
4991 NLOG(NLOG_CLOCKINFO)
4992 ERR(ERR_BADIO)
4993 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
4995 return 0;
4998 /*--------------------------------------------------
4999 * TRIMBLE TSIP check routine
5001 static void
5002 trimble_check(
5003 struct peer *peer
5006 struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr;
5007 trimble_t *t = parse->localdata;
5008 u_char buffer[256];
5009 struct txbuf buf;
5010 buf.txt = buffer;
5012 if (t)
5014 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
5015 (void)trimbletsip_setup(parse, "message timeout");
5018 poll_poll(parse->peer); /* emit query string and re-arm timer */
5020 if (t && t->qtracking)
5022 u_long oldsats = t->ltrack & ~t->ctrack;
5024 t->qtracking = 0;
5025 t->ltrack = t->ctrack;
5027 if (oldsats)
5029 int i;
5031 for (i = 0; oldsats; i++) {
5032 if (oldsats & (1 << i))
5034 sendcmd(&buf, CMD_CSTATTRACK);
5035 sendbyte(&buf, i+1); /* old sat */
5036 sendetx(&buf, parse);
5038 oldsats &= ~(1 << i);
5042 sendcmd(&buf, CMD_CSTATTRACK);
5043 sendbyte(&buf, 0x00); /* current tracking set */
5044 sendetx(&buf, parse);
5048 /*--------------------------------------------------
5049 * TRIMBLE TSIP end routine
5051 static void
5052 trimbletsip_end(
5053 struct parseunit *parse
5055 { trimble_t *t = parse->localdata;
5057 if (t)
5059 free(t);
5060 parse->localdata = (void *)0;
5062 parse->peer->nextaction = 0;
5063 parse->peer->action = (void (*) P((struct peer *)))0;
5066 /*--------------------------------------------------
5067 * TRIMBLE TSIP init routine
5069 static int
5070 trimbletsip_init(
5071 struct parseunit *parse
5074 #if defined(VEOL) || defined(VEOL2)
5075 #ifdef HAVE_TERMIOS
5076 struct termios tio; /* NEEDED FOR A LONG TIME ! */
5077 #endif
5078 #ifdef HAVE_SYSV_TTYS
5079 struct termio tio; /* NEEDED FOR A LONG TIME ! */
5080 #endif
5082 * allocate local data area
5084 if (!parse->localdata)
5086 trimble_t *t;
5088 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5090 if (t)
5092 memset((char *)t, 0, sizeof(trimble_t));
5093 t->last_msg = current_time;
5097 parse->peer->action = trimble_check;
5098 parse->peer->nextaction = current_time;
5101 * configure terminal line for ICANON mode with VEOL characters
5103 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
5105 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5106 return 0;
5108 else
5110 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
5112 #ifdef VEOL
5113 tio.c_cc[VEOL] = ETX;
5114 #endif
5115 #ifdef VEOL2
5116 tio.c_cc[VEOL2] = DLE;
5117 #endif
5120 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
5122 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5123 return 0;
5126 #endif
5127 return trimbletsip_setup(parse, "initial startup");
5130 /*------------------------------------------------------------
5131 * trimbletsip_event - handle Trimble events
5132 * simple evente handler - attempt to re-initialize receiver
5134 static void
5135 trimbletsip_event(
5136 struct parseunit *parse,
5137 int event
5140 switch (event)
5142 case CEVNT_BADREPLY: /* reset on garbled input */
5143 case CEVNT_TIMEOUT: /* reset on no input */
5144 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
5145 break;
5147 default: /* ignore */
5148 break;
5153 * getflt, getint convert fields in the incoming data into the
5154 * appropriate type of item
5156 * CAVEAT: these routines are currently definitely byte order dependent
5157 * and assume Representation(float) == IEEE754
5158 * These functions MUST be converted to portable versions (especially
5159 * converting the float representation into ntp_fp formats in order
5160 * to avoid floating point operations at all!
5163 static float
5164 getflt(
5165 u_char *bp
5168 union uval uval;
5170 #ifdef WORDS_BIGENDIAN
5171 uval.bd[0] = *bp++;
5172 uval.bd[1] = *bp++;
5173 uval.bd[2] = *bp++;
5174 uval.bd[3] = *bp;
5175 #else /* ! WORDS_BIGENDIAN */
5176 uval.bd[3] = *bp++;
5177 uval.bd[2] = *bp++;
5178 uval.bd[1] = *bp++;
5179 uval.bd[0] = *bp;
5180 #endif /* ! WORDS_BIGENDIAN */
5181 return uval.fv;
5184 static double
5185 getdbl(
5186 u_char *bp
5189 union uval uval;
5191 #ifdef WORDS_BIGENDIAN
5192 uval.bd[0] = *bp++;
5193 uval.bd[1] = *bp++;
5194 uval.bd[2] = *bp++;
5195 uval.bd[3] = *bp++;
5196 uval.bd[4] = *bp++;
5197 uval.bd[5] = *bp++;
5198 uval.bd[6] = *bp++;
5199 uval.bd[7] = *bp;
5200 #else /* ! WORDS_BIGENDIAN */
5201 uval.bd[7] = *bp++;
5202 uval.bd[6] = *bp++;
5203 uval.bd[5] = *bp++;
5204 uval.bd[4] = *bp++;
5205 uval.bd[3] = *bp++;
5206 uval.bd[2] = *bp++;
5207 uval.bd[1] = *bp++;
5208 uval.bd[0] = *bp;
5209 #endif /* ! WORDS_BIGENDIAN */
5210 return uval.dv;
5213 static int
5214 getshort(
5215 unsigned char *p
5218 return get_msb_short(&p);
5221 /*--------------------------------------------------
5222 * trimbletsip_message - process trimble messages
5224 #define RTOD (180.0 / 3.1415926535898)
5225 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5227 static void
5228 trimbletsip_message(
5229 struct parseunit *parse,
5230 parsetime_t *parsetime
5233 unsigned char *buffer = parsetime->parse_msg;
5234 unsigned int size = parsetime->parse_msglen;
5236 if ((size < 4) ||
5237 (buffer[0] != DLE) ||
5238 (buffer[size-1] != ETX) ||
5239 (buffer[size-2] != DLE))
5241 #ifdef DEBUG
5242 if (debug > 2) {
5243 int i;
5245 printf("TRIMBLE BAD packet, size %d:\n ", size);
5246 for (i = 0; i < size; i++) {
5247 printf ("%2.2x, ", buffer[i]&0xff);
5248 if (i%16 == 15) printf("\n\t");
5250 printf("\n");
5252 #endif
5253 return;
5255 else
5257 int var_flag;
5258 trimble_t *tr = parse->localdata;
5259 unsigned int cmd = buffer[1];
5260 char pbuffer[200];
5261 char *t = pbuffer;
5262 cmd_info_t *s;
5264 #ifdef DEBUG
5265 if (debug > 3) {
5266 int i;
5268 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size);
5269 for (i = 0; i < size; i++) {
5270 printf ("%2.2x, ", buffer[i]&0xff);
5271 if (i%16 == 15) printf("\n\t");
5273 printf("\n");
5275 #endif
5277 if (tr)
5278 tr->last_msg = current_time;
5280 s = trimble_convert(cmd, trimble_rcmds);
5282 if (s)
5284 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname);
5286 else
5288 DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
5289 return;
5292 var_flag = s->varmode;
5294 t += strlen(t);
5296 switch(cmd)
5298 case CMD_RCURTIME:
5299 snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f",
5300 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5301 getflt((unsigned char *)&mb(6)));
5302 break;
5304 case CMD_RBEST4:
5305 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5306 t += strlen(t);
5307 switch (mb(0) & 0xF)
5309 default:
5310 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5311 break;
5313 case 1:
5314 strncpy(t, "0D", BUFFER_SIZE(pbuffer, t));
5315 break;
5317 case 3:
5318 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5319 break;
5321 case 4:
5322 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5323 break;
5325 t += strlen(t);
5326 if (mb(0) & 0x10)
5327 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5328 else
5329 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5330 t += strlen(t);
5332 snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5333 mb(1), mb(2), mb(3), mb(4),
5334 getflt((unsigned char *)&mb(5)),
5335 getflt((unsigned char *)&mb(9)),
5336 getflt((unsigned char *)&mb(13)),
5337 getflt((unsigned char *)&mb(17)));
5339 break;
5341 case CMD_RVERSION:
5342 snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)",
5343 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5344 break;
5346 case CMD_RRECVHEALTH:
5348 static const char *msgs[] =
5350 "Battery backup failed",
5351 "Signal processor error",
5352 "Alignment error, channel or chip 1",
5353 "Alignment error, channel or chip 2",
5354 "Antenna feed line fault",
5355 "Excessive ref freq. error",
5356 "<BIT 6>",
5357 "<BIT 7>"
5360 int i, bits;
5362 switch (mb(0) & 0xFF)
5364 default:
5365 snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF);
5366 break;
5367 case 0x00:
5368 strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t));
5369 break;
5370 case 0x01:
5371 strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t));
5372 break;
5373 case 0x03:
5374 strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t));
5375 break;
5376 case 0x08:
5377 strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t));
5378 break;
5379 case 0x09:
5380 strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t));
5381 break;
5382 case 0x0A:
5383 strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t));
5384 break;
5385 case 0x0B:
5386 strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t));
5387 break;
5388 case 0x0C:
5389 strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t));
5390 break;
5393 t += strlen(t);
5395 bits = mb(1) & 0xFF;
5397 for (i = 0; i < 8; i++)
5398 if (bits & (0x1<<i))
5400 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5401 t += strlen(t);
5404 break;
5406 case CMD_RMESSAGE:
5407 mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
5408 break;
5410 case CMD_RMACHSTAT:
5412 static const char *msgs[] =
5414 "Synthesizer Fault",
5415 "Battery Powered Time Clock Fault",
5416 "A-to-D Converter Fault",
5417 "The almanac stored in the receiver is not complete and current",
5418 "<BIT 4>",
5419 "<BIT 5",
5420 "<BIT 6>",
5421 "<BIT 7>"
5424 int i, bits;
5426 snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF);
5427 t += strlen(t);
5429 bits = mb(1) & 0xFF;
5431 for (i = 0; i < 8; i++)
5432 if (bits & (0x1<<i))
5434 snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]);
5435 t += strlen(t);
5438 snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5440 break;
5442 case CMD_ROPERPARAM:
5443 snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f",
5444 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5445 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5446 break;
5448 case CMD_RUTCPARAM:
5450 float t0t = getflt((unsigned char *)&mb(14));
5451 short wnt = getshort((unsigned char *)&mb(18));
5452 short dtls = getshort((unsigned char *)&mb(12));
5453 short wnlsf = getshort((unsigned char *)&mb(20));
5454 short dn = getshort((unsigned char *)&mb(22));
5455 short dtlsf = getshort((unsigned char *)&mb(24));
5457 if ((int)t0t != 0)
5459 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5461 else
5463 strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t));
5466 break;
5468 case CMD_RSAT1BIAS:
5469 snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs",
5470 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5471 break;
5473 case CMD_RIOOPTIONS:
5475 snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x",
5476 mb(0), mb(1), mb(2), mb(3));
5477 if (mb(0) != TRIM_POS_OPT ||
5478 mb(2) != TRIM_TIME_OPT)
5480 (void)trimbletsip_setup(parse, "bad io options");
5483 break;
5485 case CMD_RSPOSXYZ:
5487 double x = getflt((unsigned char *)&mb(0));
5488 double y = getflt((unsigned char *)&mb(4));
5489 double z = getflt((unsigned char *)&mb(8));
5490 double f = getflt((unsigned char *)&mb(12));
5492 if (f > 0.0)
5493 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5494 x, y, z,
5496 else
5497 return;
5499 break;
5501 case CMD_RSLLAPOS:
5503 double lat = getflt((unsigned char *)&mb(0));
5504 double lng = getflt((unsigned char *)&mb(4));
5505 double f = getflt((unsigned char *)&mb(12));
5507 if (f > 0.0)
5508 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm",
5509 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5510 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5511 getflt((unsigned char *)&mb(8)));
5512 else
5513 return;
5515 break;
5517 case CMD_RDOUBLEXYZ:
5519 double x = getdbl((unsigned char *)&mb(0));
5520 double y = getdbl((unsigned char *)&mb(8));
5521 double z = getdbl((unsigned char *)&mb(16));
5522 snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm",
5523 x, y, z);
5525 break;
5527 case CMD_RDOUBLELLA:
5529 double lat = getdbl((unsigned char *)&mb(0));
5530 double lng = getdbl((unsigned char *)&mb(8));
5531 snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm",
5532 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5533 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5534 getdbl((unsigned char *)&mb(16)));
5536 break;
5538 case CMD_RALLINVIEW:
5540 int i, sats;
5542 strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t));
5543 t += strlen(t);
5544 switch (mb(0) & 0x7)
5546 default:
5547 snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7);
5548 break;
5550 case 3:
5551 strncpy(t, "2D", BUFFER_SIZE(pbuffer, t));
5552 break;
5554 case 4:
5555 strncpy(t, "3D", BUFFER_SIZE(pbuffer, t));
5556 break;
5558 t += strlen(t);
5559 if (mb(0) & 0x8)
5560 strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t));
5561 else
5562 strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t));
5563 t += strlen(t);
5565 sats = (mb(0)>>4) & 0xF;
5567 snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5568 getflt((unsigned char *)&mb(1)),
5569 getflt((unsigned char *)&mb(5)),
5570 getflt((unsigned char *)&mb(9)),
5571 getflt((unsigned char *)&mb(13)),
5572 sats, (sats == 1) ? "" : "s");
5573 t += strlen(t);
5575 for (i=0; i < sats; i++)
5577 snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i));
5578 t += strlen(t);
5579 if (tr)
5580 tr->ctrack |= (1 << (mb(17+i)-1));
5583 if (tr)
5584 { /* mark for tracking status query */
5585 tr->qtracking = 1;
5588 break;
5590 case CMD_RSTATTRACK:
5592 snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */
5593 t += strlen(t);
5595 if (getflt((unsigned char *)&mb(4)) < 0.0)
5597 strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t));
5598 var_flag &= ~DEF;
5600 else
5602 snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5603 (mb(1) & 0xFF)>>3,
5604 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5605 mb(3),
5606 getflt((unsigned char *)&mb(4)),
5607 getflt((unsigned char *)&mb(12)) * RTOD,
5608 getflt((unsigned char *)&mb(16)) * RTOD);
5609 t += strlen(t);
5610 if (mb(20))
5612 var_flag &= ~DEF;
5613 strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t));
5615 t += strlen(t);
5616 if (mb(22))
5618 if (mb(22) == 1)
5619 strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t));
5620 else
5621 if (mb(22) == 2)
5622 strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t));
5624 t += strlen(t);
5625 if (mb(23))
5626 strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t));
5629 break;
5631 default:
5632 strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t));
5633 break;
5635 t += strlen(t);
5637 strncpy(t,"\"", BUFFER_SIZE(pbuffer, t));
5638 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5643 /**============================================================
5644 ** RAWDCF support
5647 /*--------------------------------------------------
5648 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5649 * SET DTR line
5651 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5652 static int
5653 rawdcf_init_1(
5654 struct parseunit *parse
5657 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5659 * You can use the RS232 to supply the power for a DCF77 receiver.
5660 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5661 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5663 int sl232;
5665 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5667 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5668 return 0;
5671 #ifdef TIOCM_DTR
5672 sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5673 #else
5674 sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5675 #endif
5677 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5679 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5681 return 0;
5683 #else
5684 static int
5685 rawdcfdtr_init_1(
5686 struct parseunit *parse
5689 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5690 return 0;
5692 #endif /* DTR initialisation type */
5694 /*--------------------------------------------------
5695 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5696 * CLR DTR line, SET RTS line
5698 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5699 static int
5700 rawdcf_init_2(
5701 struct parseunit *parse
5704 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */
5706 * You can use the RS232 to supply the power for a DCF77 receiver.
5707 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5708 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5710 int sl232;
5712 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5714 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5715 return 0;
5718 #ifdef TIOCM_RTS
5719 sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5720 #else
5721 sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5722 #endif
5724 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5726 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5728 return 0;
5730 #else
5731 static int
5732 rawdcf_init_2(
5733 struct parseunit *parse
5736 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5737 return 0;
5739 #endif /* DTR initialisation type */
5741 #else /* defined(REFCLOCK) && defined(PARSE) */
5742 int refclock_parse_bs;
5743 #endif /* defined(REFCLOCK) && defined(PARSE) */
5746 * History:
5748 * refclock_parse.c,v
5749 * Revision 4.80 2007/08/11 12:06:29 kardel
5750 * update comments wrt/ to PPS
5752 * Revision 4.79 2007/08/11 11:52:23 kardel
5753 * - terminate io bindings before io_closeclock() will close our file descriptor
5755 * Revision 4.78 2006/12/22 20:08:27 kardel
5756 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5758 * Revision 4.77 2006/08/05 07:44:49 kardel
5759 * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5761 * Revision 4.76 2006/06/22 18:40:47 kardel
5762 * clean up signedness (gcc 4)
5764 * Revision 4.75 2006/06/22 16:58:10 kardel
5765 * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5766 * the PPS offset. Fix sign of offset passed to kernel.
5768 * Revision 4.74 2006/06/18 21:18:37 kardel
5769 * NetBSD Coverity CID 3796: possible NULL deref
5771 * Revision 4.73 2006/05/26 14:23:46 kardel
5772 * cleanup of copyright info
5774 * Revision 4.72 2006/05/26 14:19:43 kardel
5775 * cleanup of ioctl cruft
5777 * Revision 4.71 2006/05/26 14:15:57 kardel
5778 * delay adding refclock to async refclock io after all initializations
5780 * Revision 4.70 2006/05/25 18:20:50 kardel
5781 * bug #619
5782 * terminate parse io engine after de-registering
5783 * from refclock io engine
5785 * Revision 4.69 2006/05/25 17:28:02 kardel
5786 * complete refclock io structure initialization *before* inserting it into the
5787 * refclock input machine (avoids null pointer deref) (bug #619)
5789 * Revision 4.68 2006/05/01 17:02:51 kardel
5790 * copy receiver method also for newlwy created receive buffers
5792 * Revision 4.67 2006/05/01 14:37:29 kardel
5793 * If an input buffer parses into more than one message do insert the
5794 * parsed message in a new input buffer instead of processing it
5795 * directly. This avoids deed complicated processing in signal
5796 * handling.
5798 * Revision 4.66 2006/03/18 00:45:30 kardel
5799 * coverity fixes found in NetBSD coverity scan
5801 * Revision 4.65 2006/01/26 06:08:33 kardel
5802 * output errno on PPS setup failure
5804 * Revision 4.64 2005/11/09 20:44:47 kardel
5805 * utilize full PPS timestamp resolution from PPS API
5807 * Revision 4.63 2005/10/07 22:10:25 kardel
5808 * bounded buffer implementation
5810 * Revision 4.62.2.2 2005/09/25 10:20:16 kardel
5811 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5812 * replace almost all str* and *printf functions be their buffer bounded
5813 * counterparts
5815 * Revision 4.62.2.1 2005/08/27 16:19:27 kardel
5816 * limit re-set rate of trimble clocks
5818 * Revision 4.62 2005/08/06 17:40:00 kardel
5819 * cleanup size handling wrt/ to buffer boundaries
5821 * Revision 4.61 2005/07/27 21:16:19 kardel
5822 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
5823 * default setup. CSTOPB was missing for the 7E2 default data format of
5824 * the DCF77 clocks.
5826 * Revision 4.60 2005/07/17 21:14:44 kardel
5827 * change contents of version string to include the RCS/CVS Id
5829 * Revision 4.59 2005/07/06 06:56:38 kardel
5830 * syntax error
5832 * Revision 4.58 2005/07/04 13:10:40 kardel
5833 * fix bug 455: tripping over NULL pointer on cleanup
5834 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
5835 * fix compiler warnings for some platforms wrt/ printf formatstrings and
5836 * varying structure element sizes
5837 * reorder assignment in binding to avoid tripping over NULL pointers
5839 * Revision 4.57 2005/06/25 09:25:19 kardel
5840 * sort out log output sequence
5842 * Revision 4.56 2005/06/14 21:47:27 kardel
5843 * collect samples only if samples are ok (sync or trusted flywheel)
5844 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
5845 * en- and dis-able HARDPPS in correlation to receiver sync state
5847 * Revision 4.55 2005/06/02 21:28:31 kardel
5848 * clarify trust logic
5850 * Revision 4.54 2005/06/02 17:06:49 kardel
5851 * change status reporting to use fixed refclock_report()
5853 * Revision 4.53 2005/06/02 16:33:31 kardel
5854 * fix acceptance of clocks unsync clocks right at start
5856 * Revision 4.52 2005/05/26 21:55:06 kardel
5857 * cleanup status reporting
5859 * Revision 4.51 2005/05/26 19:19:14 kardel
5860 * implement fast refclock startup
5862 * Revision 4.50 2005/04/16 20:51:35 kardel
5863 * set pps_enable = 1 when binding a kernel PPS source
5865 * Revision 4.49 2005/04/16 17:29:26 kardel
5866 * add non polling clock type 18 for just listenning to Meinberg clocks
5868 * Revision 4.48 2005/04/16 16:22:27 kardel
5869 * bk sync 20050415 ntp-dev
5871 * Revision 4.47 2004/11/29 10:42:48 kardel
5872 * bk sync ntp-dev 20041129
5874 * Revision 4.46 2004/11/29 10:26:29 kardel
5875 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
5877 * Revision 4.45 2004/11/14 20:53:20 kardel
5878 * clear PPS flags after using them
5880 * Revision 4.44 2004/11/14 15:29:41 kardel
5881 * support PPSAPI, upgrade Copyright to Berkeley style
5883 * Revision 4.43 2001/05/26 22:53:16 kardel
5884 * 20010526 reconcilation
5886 * Revision 4.42 2000/05/14 15:31:51 kardel
5887 * PPSAPI && RAWDCF modemline support
5889 * Revision 4.41 2000/04/09 19:50:45 kardel
5890 * fixed rawdcfdtr_init() -> rawdcf_init_1
5892 * Revision 4.40 2000/04/09 15:27:55 kardel
5893 * modem line fiddle in rawdcf_init_2
5895 * Revision 4.39 2000/03/18 09:16:55 kardel
5896 * PPSAPI integration
5898 * Revision 4.38 2000/03/05 20:25:06 kardel
5899 * support PPSAPI
5901 * Revision 4.37 2000/03/05 20:11:14 kardel
5902 * 4.0.99g reconcilation
5904 * Revision 4.36 1999/11/28 17:18:20 kardel
5905 * disabled burst mode
5907 * Revision 4.35 1999/11/28 09:14:14 kardel
5908 * RECON_4_0_98F
5910 * Revision 4.34 1999/05/14 06:08:05 kardel
5911 * store current_time in a suitable container (u_long)
5913 * Revision 4.33 1999/05/13 21:48:38 kardel
5914 * double the no response timeout interval
5916 * Revision 4.32 1999/05/13 20:09:13 kardel
5917 * complain only about missing polls after a full poll interval
5919 * Revision 4.31 1999/05/13 19:59:32 kardel
5920 * add clock type 16 for RTS set DTR clr in RAWDCF
5922 * Revision 4.30 1999/02/28 20:36:43 kardel
5923 * fixed printf fmt
5925 * Revision 4.29 1999/02/28 19:58:23 kardel
5926 * updated copyright information
5928 * Revision 4.28 1999/02/28 19:01:50 kardel
5929 * improved debug out on sent Meinberg messages
5931 * Revision 4.27 1999/02/28 18:05:55 kardel
5932 * no linux/ppsclock.h stuff
5934 * Revision 4.26 1999/02/28 15:27:27 kardel
5935 * wharton clock integration
5937 * Revision 4.25 1999/02/28 14:04:46 kardel
5938 * added missing double quotes to UTC information string
5940 * Revision 4.24 1999/02/28 12:06:50 kardel
5941 * (parse_control): using gmprettydate instead of prettydate()
5942 * (mk_utcinfo): new function for formatting GPS derived UTC information
5943 * (gps16x_message): changed to use mk_utcinfo()
5944 * (trimbletsip_message): changed to use mk_utcinfo()
5945 * ignoring position information in unsynchronized mode
5946 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
5948 * Revision 4.23 1999/02/23 19:47:53 kardel
5949 * fixed #endifs
5950 * (stream_receive): fixed formats
5952 * Revision 4.22 1999/02/22 06:21:02 kardel
5953 * use new autoconfig symbols
5955 * Revision 4.21 1999/02/21 12:18:13 kardel
5956 * 4.91f reconcilation
5958 * Revision 4.20 1999/02/21 10:53:36 kardel
5959 * initial Linux PPSkit version
5961 * Revision 4.19 1999/02/07 09:10:45 kardel
5962 * clarify STREAMS mitigation rules in comment
5964 * Revision 4.18 1998/12/20 23:45:34 kardel
5965 * fix types and warnings
5967 * Revision 4.17 1998/11/15 21:24:51 kardel
5968 * cannot access mbg_ routines when CLOCK_MEINBERG
5969 * is not defined
5971 * Revision 4.16 1998/11/15 20:28:17 kardel
5972 * Release 4.0.73e13 reconcilation
5974 * Revision 4.15 1998/08/22 21:56:08 kardel
5975 * fixed IO handling for non-STREAM IO
5977 * Revision 4.14 1998/08/16 19:00:48 kardel
5978 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
5979 * made uval a local variable (killed one of the last globals)
5980 * (sendetx): added logging of messages when in debug mode
5981 * (trimble_check): added periodic checks to facilitate re-initialization
5982 * (trimbletsip_init): made use of EOL character if in non-kernel operation
5983 * (trimbletsip_message): extended message interpretation
5984 * (getdbl): fixed data conversion
5986 * Revision 4.13 1998/08/09 22:29:13 kardel
5987 * Trimble TSIP support
5989 * Revision 4.12 1998/07/11 10:05:34 kardel
5990 * Release 4.0.73d reconcilation
5992 * Revision 4.11 1998/06/14 21:09:42 kardel
5993 * Sun acc cleanup
5995 * Revision 4.10 1998/06/13 12:36:45 kardel
5996 * signed/unsigned, name clashes
5998 * Revision 4.9 1998/06/12 15:30:00 kardel
5999 * prototype fixes
6001 * Revision 4.8 1998/06/12 11:19:42 kardel
6002 * added direct input processing routine for refclocks in
6003 * order to avaiod that single character io gobbles up all
6004 * receive buffers and drops input data. (Problem started
6005 * with fast machines so a character a buffer was possible
6006 * one of the few cases where faster machines break existing
6007 * allocation algorithms)
6009 * Revision 4.7 1998/06/06 18:35:20 kardel
6010 * (parse_start): added BURST mode initialisation
6012 * Revision 4.6 1998/05/27 06:12:46 kardel
6013 * RAWDCF_BASEDELAY default added
6014 * old comment removed
6015 * casts for ioctl()
6017 * Revision 4.5 1998/05/25 22:05:09 kardel
6018 * RAWDCF_SETDTR option removed
6019 * clock type 14 attempts to set DTR for
6020 * power supply of RAWDCF receivers
6022 * Revision 4.4 1998/05/24 16:20:47 kardel
6023 * updated comments referencing Meinberg clocks
6024 * added RAWDCF clock with DTR set option as type 14
6026 * Revision 4.3 1998/05/24 10:48:33 kardel
6027 * calibrated CONRAD RAWDCF default fudge factor
6029 * Revision 4.2 1998/05/24 09:59:35 kardel
6030 * corrected version information (ntpq support)
6032 * Revision 4.1 1998/05/24 09:52:31 kardel
6033 * use fixed format only (new IO model)
6034 * output debug to stdout instead of msyslog()
6035 * don't include >"< in ASCII output in order not to confuse
6036 * ntpq parsing
6038 * Revision 4.0 1998/04/10 19:52:11 kardel
6039 * Start 4.0 release version numbering
6041 * Revision 1.2 1998/04/10 19:28:04 kardel
6042 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6043 * derived from 3.105.1.2 from V3 tree
6045 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel