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