refclock_parse.c revision 1.9.2.1 1 /* $NetBSD: refclock_parse.c,v 1.9.2.1 2014/08/19 23:51:42 tls 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 size_t 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((unsigned char)*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 NULL,
1777 NULL,
1778 NULL,
1779 NULL,
1780 NULL,
1781 NULL,
1782 NULL,
1783 NULL,
1784 NULL,
1785 NULL,
1786 }
1787 };
1788
1789 #ifdef STREAM
1790
1791 /*--------------------------------------------------
1792 * ppsclock STREAM init
1793 */
1794 static int
1795 ppsclock_init(
1796 struct parseunit *parse
1797 )
1798 {
1799 static char m1[] = "ppsclocd";
1800 static char m2[] = "ppsclock";
1801
1802 /*
1803 * now push the parse streams module
1804 * it will ensure exclusive access to the device
1805 */
1806 if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 &&
1807 ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1)
1808 {
1809 if (errno != EINVAL)
1810 {
1811 msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
1812 CLK_UNIT(parse->peer));
1813 }
1814 return 0;
1815 }
1816 if (!local_init(parse))
1817 {
1818 (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0);
1819 return 0;
1820 }
1821
1822 parse->flags |= PARSE_PPSCLOCK;
1823 return 1;
1824 }
1825
1826 /*--------------------------------------------------
1827 * parse STREAM init
1828 */
1829 static int
1830 stream_init(
1831 struct parseunit *parse
1832 )
1833 {
1834 static char m1[] = "parse";
1835 /*
1836 * now push the parse streams module
1837 * to test whether it is there (neat interface 8-( )
1838 */
1839 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1840 {
1841 if (errno != EINVAL) /* accept non-existence */
1842 {
1843 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1844 }
1845 return 0;
1846 }
1847 else
1848 {
1849 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1850 /* empty loop */;
1851
1852 /*
1853 * now push it a second time after we have removed all
1854 * module garbage
1855 */
1856 if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1)
1857 {
1858 msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer));
1859 return 0;
1860 }
1861 else
1862 {
1863 return 1;
1864 }
1865 }
1866 }
1867
1868 /*--------------------------------------------------
1869 * parse STREAM end
1870 */
1871 static void
1872 stream_end(
1873 struct parseunit *parse
1874 )
1875 {
1876 while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0)
1877 /* empty loop */;
1878 }
1879
1880 /*--------------------------------------------------
1881 * STREAM setcs
1882 */
1883 static int
1884 stream_setcs(
1885 struct parseunit *parse,
1886 parsectl_t *tcl
1887 )
1888 {
1889 struct strioctl strioc;
1890
1891 strioc.ic_cmd = PARSEIOC_SETCS;
1892 strioc.ic_timout = 0;
1893 strioc.ic_dp = (char *)tcl;
1894 strioc.ic_len = sizeof (*tcl);
1895
1896 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1897 {
1898 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer));
1899 return 0;
1900 }
1901 return 1;
1902 }
1903
1904 /*--------------------------------------------------
1905 * STREAM enable
1906 */
1907 static int
1908 stream_enable(
1909 struct parseunit *parse
1910 )
1911 {
1912 struct strioctl strioc;
1913
1914 strioc.ic_cmd = PARSEIOC_ENABLE;
1915 strioc.ic_timout = 0;
1916 strioc.ic_dp = (char *)0;
1917 strioc.ic_len = 0;
1918
1919 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1920 {
1921 msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer));
1922 return 0;
1923 }
1924 parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */
1925 return 1;
1926 }
1927
1928 /*--------------------------------------------------
1929 * STREAM disable
1930 */
1931 static int
1932 stream_disable(
1933 struct parseunit *parse
1934 )
1935 {
1936 struct strioctl strioc;
1937
1938 strioc.ic_cmd = PARSEIOC_DISABLE;
1939 strioc.ic_timout = 0;
1940 strioc.ic_dp = (char *)0;
1941 strioc.ic_len = 0;
1942
1943 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1944 {
1945 msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer));
1946 return 0;
1947 }
1948 parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */
1949 return 1;
1950 }
1951
1952 /*--------------------------------------------------
1953 * STREAM getfmt
1954 */
1955 static int
1956 stream_getfmt(
1957 struct parseunit *parse,
1958 parsectl_t *tcl
1959 )
1960 {
1961 struct strioctl strioc;
1962
1963 strioc.ic_cmd = PARSEIOC_GETFMT;
1964 strioc.ic_timout = 0;
1965 strioc.ic_dp = (char *)tcl;
1966 strioc.ic_len = sizeof (*tcl);
1967 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1968 {
1969 msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer));
1970 return 0;
1971 }
1972 return 1;
1973 }
1974
1975 /*--------------------------------------------------
1976 * STREAM setfmt
1977 */
1978 static int
1979 stream_setfmt(
1980 struct parseunit *parse,
1981 parsectl_t *tcl
1982 )
1983 {
1984 struct strioctl strioc;
1985
1986 strioc.ic_cmd = PARSEIOC_SETFMT;
1987 strioc.ic_timout = 0;
1988 strioc.ic_dp = (char *)tcl;
1989 strioc.ic_len = sizeof (*tcl);
1990
1991 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
1992 {
1993 msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer));
1994 return 0;
1995 }
1996 return 1;
1997 }
1998
1999
2000 /*--------------------------------------------------
2001 * STREAM timecode
2002 */
2003 static int
2004 stream_timecode(
2005 struct parseunit *parse,
2006 parsectl_t *tcl
2007 )
2008 {
2009 struct strioctl strioc;
2010
2011 strioc.ic_cmd = PARSEIOC_TIMECODE;
2012 strioc.ic_timout = 0;
2013 strioc.ic_dp = (char *)tcl;
2014 strioc.ic_len = sizeof (*tcl);
2015
2016 if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1)
2017 {
2018 ERR(ERR_INTERNAL)
2019 msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer));
2020 return 0;
2021 }
2022 clear_err(parse, ERR_INTERNAL);
2023 return 1;
2024 }
2025
2026 /*--------------------------------------------------
2027 * STREAM receive
2028 */
2029 static void
2030 stream_receive(
2031 struct recvbuf *rbufp
2032 )
2033 {
2034 struct parseunit * parse;
2035 parsetime_t parsetime;
2036
2037 parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
2038 if (!parse->peer)
2039 return;
2040
2041 if (rbufp->recv_length != sizeof(parsetime_t))
2042 {
2043 ERR(ERR_BADIO)
2044 msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)",
2045 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2046 parse_event(parse, CEVNT_BADREPLY);
2047 return;
2048 }
2049 clear_err(parse, ERR_BADIO);
2050
2051 memmove((caddr_t)&parsetime,
2052 (caddr_t)rbufp->recv_buffer,
2053 sizeof(parsetime_t));
2054
2055 #ifdef DEBUG
2056 if (debug > 3)
2057 {
2058 printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n",
2059 CLK_UNIT(parse->peer),
2060 (unsigned int)parsetime.parse_status,
2061 (unsigned int)parsetime.parse_state,
2062 (unsigned long)parsetime.parse_time.tv.tv_sec,
2063 (unsigned long)parsetime.parse_time.tv.tv_usec,
2064 (unsigned long)parsetime.parse_stime.tv.tv_sec,
2065 (unsigned long)parsetime.parse_stime.tv.tv_usec,
2066 (unsigned long)parsetime.parse_ptime.tv.tv_sec,
2067 (unsigned long)parsetime.parse_ptime.tv.tv_usec);
2068 }
2069 #endif
2070
2071 /*
2072 * switch time stamp world - be sure to normalize small usec field
2073 * errors.
2074 */
2075
2076 parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv);
2077
2078 if (PARSE_TIMECODE(parsetime.parse_state))
2079 {
2080 parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv);
2081 }
2082
2083 if (PARSE_PPS(parsetime.parse_state))
2084 {
2085 parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv);
2086 }
2087
2088 parse_process(parse, &parsetime);
2089 }
2090 #endif
2091
2092 /*--------------------------------------------------
2093 * local init
2094 */
2095 static int
2096 local_init(
2097 struct parseunit *parse
2098 )
2099 {
2100 return parse_ioinit(&parse->parseio);
2101 }
2102
2103 /*--------------------------------------------------
2104 * local end
2105 */
2106 static void
2107 local_end(
2108 struct parseunit *parse
2109 )
2110 {
2111 parse_ioend(&parse->parseio);
2112 }
2113
2114
2115 /*--------------------------------------------------
2116 * local nop
2117 */
2118 static int
2119 local_nop(
2120 struct parseunit *parse
2121 )
2122 {
2123 return 1;
2124 }
2125
2126 /*--------------------------------------------------
2127 * local setcs
2128 */
2129 static int
2130 local_setcs(
2131 struct parseunit *parse,
2132 parsectl_t *tcl
2133 )
2134 {
2135 return parse_setcs(tcl, &parse->parseio);
2136 }
2137
2138 /*--------------------------------------------------
2139 * local getfmt
2140 */
2141 static int
2142 local_getfmt(
2143 struct parseunit *parse,
2144 parsectl_t *tcl
2145 )
2146 {
2147 return parse_getfmt(tcl, &parse->parseio);
2148 }
2149
2150 /*--------------------------------------------------
2151 * local setfmt
2152 */
2153 static int
2154 local_setfmt(
2155 struct parseunit *parse,
2156 parsectl_t *tcl
2157 )
2158 {
2159 return parse_setfmt(tcl, &parse->parseio);
2160 }
2161
2162 /*--------------------------------------------------
2163 * local timecode
2164 */
2165 static int
2166 local_timecode(
2167 struct parseunit *parse,
2168 parsectl_t *tcl
2169 )
2170 {
2171 return parse_timecode(tcl, &parse->parseio);
2172 }
2173
2174
2175 /*--------------------------------------------------
2176 * local input
2177 */
2178 static int
2179 local_input(
2180 struct recvbuf *rbufp
2181 )
2182 {
2183 struct parseunit * parse;
2184
2185 int count;
2186 unsigned char *s;
2187 timestamp_t ts;
2188
2189 parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
2190 if (!parse->peer)
2191 return 0;
2192
2193 /*
2194 * eat all characters, parsing then and feeding complete samples
2195 */
2196 count = rbufp->recv_length;
2197 s = (unsigned char *)rbufp->recv_buffer;
2198 ts.fp = rbufp->recv_time;
2199
2200 while (count--)
2201 {
2202 if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts))
2203 {
2204 struct recvbuf *buf;
2205
2206 /*
2207 * got something good to eat
2208 */
2209 if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state))
2210 {
2211 #ifdef HAVE_PPSAPI
2212 if (parse->flags & PARSE_PPSCLOCK)
2213 {
2214 struct timespec pps_timeout;
2215 pps_info_t pps_info;
2216
2217 pps_timeout.tv_sec = 0;
2218 pps_timeout.tv_nsec = 0;
2219
2220 if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info,
2221 &pps_timeout) == 0)
2222 {
2223 if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial)
2224 {
2225 double dtemp;
2226
2227 struct timespec pts;
2228 /*
2229 * add PPS time stamp if available via ppsclock module
2230 * and not supplied already.
2231 */
2232 if (parse->flags & PARSE_CLEAR)
2233 pts = pps_info.clear_timestamp;
2234 else
2235 pts = pps_info.assert_timestamp;
2236
2237 parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970;
2238
2239 dtemp = pts.tv_nsec / 1e9;
2240 if (dtemp < 0.) {
2241 dtemp += 1;
2242 parse->parseio.parse_dtime.parse_ptime.fp.l_ui--;
2243 }
2244 if (dtemp > 1.) {
2245 dtemp -= 1;
2246 parse->parseio.parse_dtime.parse_ptime.fp.l_ui++;
2247 }
2248 parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC;
2249
2250 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2251 #ifdef DEBUG
2252 if (debug > 3)
2253 {
2254 printf(
2255 "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n",
2256 rbufp->fd,
2257 (long)pps_info.assert_sequence + (long)pps_info.clear_sequence,
2258 lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6));
2259 }
2260 #endif
2261 }
2262 #ifdef DEBUG
2263 else
2264 {
2265 if (debug > 3)
2266 {
2267 printf(
2268 "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n",
2269 rbufp->fd,
2270 (long)pps_info.assert_sequence, (long)pps_info.clear_sequence);
2271 }
2272 }
2273 #endif
2274 parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence;
2275 }
2276 #ifdef DEBUG
2277 else
2278 {
2279 if (debug > 3)
2280 {
2281 printf(
2282 "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n",
2283 rbufp->fd,
2284 errno);
2285 }
2286 }
2287 #endif
2288 }
2289 #else
2290 #ifdef TIOCDCDTIMESTAMP
2291 struct timeval dcd_time;
2292
2293 if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1)
2294 {
2295 l_fp tstmp;
2296
2297 TVTOTS(&dcd_time, &tstmp);
2298 tstmp.l_ui += JAN_1970;
2299 L_SUB(&ts.fp, &tstmp);
2300 if (ts.fp.l_ui == 0)
2301 {
2302 #ifdef DEBUG
2303 if (debug)
2304 {
2305 printf(
2306 "parse: local_receive: fd %d DCDTIMESTAMP %s\n",
2307 parse->ppsfd,
2308 lfptoa(&tstmp, 6));
2309 printf(" sigio %s\n",
2310 lfptoa(&ts.fp, 6));
2311 }
2312 #endif
2313 parse->parseio.parse_dtime.parse_ptime.fp = tstmp;
2314 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2315 }
2316 }
2317 #else /* TIOCDCDTIMESTAMP */
2318 #if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV))
2319 if (parse->flags & PARSE_PPSCLOCK)
2320 {
2321 l_fp tts;
2322 struct ppsclockev ev;
2323
2324 #ifdef HAVE_CIOGETEV
2325 if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0)
2326 #endif
2327 #ifdef HAVE_TIOCGPPSEV
2328 if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0)
2329 #endif
2330 {
2331 if (ev.serial != parse->ppsserial)
2332 {
2333 /*
2334 * add PPS time stamp if available via ppsclock module
2335 * and not supplied already.
2336 */
2337 if (!buftvtots((const char *)&ev.tv, &tts))
2338 {
2339 ERR(ERR_BADDATA)
2340 msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
2341 }
2342 else
2343 {
2344 parse->parseio.parse_dtime.parse_ptime.fp = tts;
2345 parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
2346 }
2347 }
2348 parse->ppsserial = ev.serial;
2349 }
2350 }
2351 #endif
2352 #endif /* TIOCDCDTIMESTAMP */
2353 #endif /* !HAVE_PPSAPI */
2354 }
2355 if (count)
2356 { /* simulate receive */
2357 buf = get_free_recv_buffer();
2358 if (buf != NULL) {
2359 memmove((caddr_t)buf->recv_buffer,
2360 (caddr_t)&parse->parseio.parse_dtime,
2361 sizeof(parsetime_t));
2362 buf->recv_length = sizeof(parsetime_t);
2363 buf->recv_time = rbufp->recv_time;
2364 #ifndef HAVE_IO_COMPLETION_PORT
2365 buf->srcadr = rbufp->srcadr;
2366 #endif
2367 buf->dstadr = rbufp->dstadr;
2368 buf->receiver = rbufp->receiver;
2369 buf->fd = rbufp->fd;
2370 buf->X_from_where = rbufp->X_from_where;
2371 parse->generic->io.recvcount++;
2372 packets_received++;
2373 add_full_recv_buffer(buf);
2374 #ifdef HAVE_IO_COMPLETION_PORT
2375 SetEvent(WaitableIoEventHandle);
2376 #endif
2377 }
2378 parse_iodone(&parse->parseio);
2379 }
2380 else
2381 {
2382 memmove((caddr_t)rbufp->recv_buffer,
2383 (caddr_t)&parse->parseio.parse_dtime,
2384 sizeof(parsetime_t));
2385 parse_iodone(&parse->parseio);
2386 rbufp->recv_length = sizeof(parsetime_t);
2387 return 1; /* got something & in place return */
2388 }
2389 }
2390 }
2391 return 0; /* nothing to pass up */
2392 }
2393
2394 /*--------------------------------------------------
2395 * local receive
2396 */
2397 static void
2398 local_receive(
2399 struct recvbuf *rbufp
2400 )
2401 {
2402 struct parseunit * parse;
2403 parsetime_t parsetime;
2404
2405 parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr;
2406 if (!parse->peer)
2407 return;
2408
2409 if (rbufp->recv_length != sizeof(parsetime_t))
2410 {
2411 ERR(ERR_BADIO)
2412 msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)",
2413 CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t));
2414 parse_event(parse, CEVNT_BADREPLY);
2415 return;
2416 }
2417 clear_err(parse, ERR_BADIO);
2418
2419 memmove((caddr_t)&parsetime,
2420 (caddr_t)rbufp->recv_buffer,
2421 sizeof(parsetime_t));
2422
2423 #ifdef DEBUG
2424 if (debug > 3)
2425 {
2426 printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n",
2427 CLK_UNIT(parse->peer),
2428 (unsigned int)parsetime.parse_status,
2429 (unsigned int)parsetime.parse_state,
2430 (unsigned long)parsetime.parse_time.fp.l_ui,
2431 (unsigned long)parsetime.parse_time.fp.l_uf,
2432 (unsigned long)parsetime.parse_stime.fp.l_ui,
2433 (unsigned long)parsetime.parse_stime.fp.l_uf,
2434 (unsigned long)parsetime.parse_ptime.fp.l_ui,
2435 (unsigned long)parsetime.parse_ptime.fp.l_uf);
2436 }
2437 #endif
2438
2439 parse_process(parse, &parsetime);
2440 }
2441
2442 /*--------------------------------------------------
2443 * init_iobinding - find and initialize lower layers
2444 */
2445 static bind_t *
2446 init_iobinding(
2447 struct parseunit *parse
2448 )
2449 {
2450 bind_t *b = io_bindings;
2451
2452 while (b->bd_description != (char *)0)
2453 {
2454 if ((*b->bd_init)(parse))
2455 {
2456 return b;
2457 }
2458 b++;
2459 }
2460 return (bind_t *)0;
2461 }
2462
2463 /**===========================================================================
2464 ** support routines
2465 **/
2466
2467 static __printflike(4, 5) char *
2468 ap(char *buffer, size_t len, char *pos, const char *fmt, ...)
2469 {
2470 va_list va;
2471 int l;
2472 size_t rem = len - (pos - buffer);
2473
2474 if (rem == 0)
2475 return pos;
2476
2477 va_start(va, fmt);
2478 l = vsnprintf(pos, rem, fmt, va);
2479 va_end(va);
2480
2481 if (l != -1) {
2482 rem--;
2483 if (rem >= (size_t)l)
2484 pos += l;
2485 else
2486 pos += rem;
2487 }
2488
2489 return pos;
2490 }
2491
2492 /*--------------------------------------------------
2493 * convert a flag field to a string
2494 */
2495 static char *
2496 parsestate(
2497 u_long lstate,
2498 char *buffer,
2499 int size
2500 )
2501 {
2502 static struct bits
2503 {
2504 u_long bit;
2505 const char *name;
2506 } flagstrings[] =
2507 {
2508 { PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
2509 { PARSEB_POWERUP, "NOT SYNCHRONIZED" },
2510 { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
2511 { PARSEB_DST, "DST" },
2512 { PARSEB_UTC, "UTC DISPLAY" },
2513 { PARSEB_LEAPADD, "LEAP ADD WARNING" },
2514 { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
2515 { PARSEB_LEAPSECOND, "LEAP SECOND" },
2516 { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" },
2517 { PARSEB_TIMECODE, "TIME CODE" },
2518 { PARSEB_PPS, "PPS" },
2519 { PARSEB_POSITION, "POSITION" },
2520 { 0, NULL }
2521 };
2522
2523 static struct sbits
2524 {
2525 u_long bit;
2526 const char *name;
2527 } sflagstrings[] =
2528 {
2529 { PARSEB_S_LEAP, "LEAP INDICATION" },
2530 { PARSEB_S_PPS, "PPS SIGNAL" },
2531 { PARSEB_S_ANTENNA, "ANTENNA" },
2532 { PARSEB_S_POSITION, "POSITION" },
2533 { 0, NULL }
2534 };
2535 int i;
2536 char *s, *t;
2537
2538 s = t = buffer;
2539
2540 i = 0;
2541 while (flagstrings[i].bit)
2542 {
2543 if (flagstrings[i].bit & lstate)
2544 {
2545 if (s != t)
2546 t = ap(buffer, size, t, "; ");
2547 t = ap(buffer, size, t, "%s", flagstrings[i].name);
2548 }
2549 i++;
2550 }
2551
2552 if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
2553 {
2554 if (s != t)
2555 t = ap(buffer, size, t, "; ");
2556
2557 t = ap(buffer, size, t, "(");
2558
2559 s = t;
2560
2561 i = 0;
2562 while (sflagstrings[i].bit)
2563 {
2564 if (sflagstrings[i].bit & lstate)
2565 {
2566 if (t != s)
2567 {
2568 t = ap(buffer, size, t, "; ");
2569 }
2570
2571 t = ap(buffer, size, t, "%s",
2572 sflagstrings[i].name);
2573 }
2574 i++;
2575 }
2576 t = ap(buffer, size, t, ")");
2577 }
2578 return buffer;
2579 }
2580
2581 /*--------------------------------------------------
2582 * convert a status flag field to a string
2583 */
2584 static char *
2585 parsestatus(
2586 u_long lstate,
2587 char *buffer,
2588 int size
2589 )
2590 {
2591 static struct bits
2592 {
2593 u_long bit;
2594 const char *name;
2595 } flagstrings[] =
2596 {
2597 { CVT_OK, "CONVERSION SUCCESSFUL" },
2598 { CVT_NONE, "NO CONVERSION" },
2599 { CVT_FAIL, "CONVERSION FAILED" },
2600 { CVT_BADFMT, "ILLEGAL FORMAT" },
2601 { CVT_BADDATE, "DATE ILLEGAL" },
2602 { CVT_BADTIME, "TIME ILLEGAL" },
2603 { CVT_ADDITIONAL, "ADDITIONAL DATA" },
2604 { 0, NULL }
2605 };
2606 int i;
2607 char *t;
2608
2609 t = buffer;
2610 *buffer = '\0';
2611
2612 i = 0;
2613 while (flagstrings[i].bit)
2614 {
2615 if (flagstrings[i].bit & lstate)
2616 {
2617 if (t == buffer)
2618 t = ap(buffer, size, t, "; ");
2619 t = ap(buffer, size, t, "%s", flagstrings[i].name);
2620 }
2621 i++;
2622 }
2623
2624 return buffer;
2625 }
2626
2627 /*--------------------------------------------------
2628 * convert a clock status flag field to a string
2629 */
2630 static const char *
2631 clockstatus(
2632 u_long lstate
2633 )
2634 {
2635 static char buffer[20];
2636 static struct status
2637 {
2638 u_long value;
2639 const char *name;
2640 } flagstrings[] =
2641 {
2642 { CEVNT_NOMINAL, "NOMINAL" },
2643 { CEVNT_TIMEOUT, "NO RESPONSE" },
2644 { CEVNT_BADREPLY,"BAD FORMAT" },
2645 { CEVNT_FAULT, "FAULT" },
2646 { CEVNT_PROP, "PROPAGATION DELAY" },
2647 { CEVNT_BADDATE, "ILLEGAL DATE" },
2648 { CEVNT_BADTIME, "ILLEGAL TIME" },
2649 { (unsigned)~0L, NULL }
2650 };
2651 int i;
2652
2653 i = 0;
2654 while (flagstrings[i].value != (u_int)~0)
2655 {
2656 if (flagstrings[i].value == lstate)
2657 {
2658 return flagstrings[i].name;
2659 }
2660 i++;
2661 }
2662
2663 snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate);
2664
2665 return buffer;
2666 }
2667
2668
2669 /*--------------------------------------------------
2670 * l_mktime - make representation of a relative time
2671 */
2672 static char *
2673 l_mktime(
2674 u_long delta
2675 )
2676 {
2677 u_long tmp, m, s;
2678 static char buffer[40];
2679 char *t;
2680
2681 buffer[0] = '\0';
2682 t = buffer;
2683
2684 if ((tmp = delta / (60*60*24)) != 0)
2685 {
2686 t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp);
2687 delta -= tmp * 60*60*24;
2688 }
2689
2690 s = delta % 60;
2691 delta /= 60;
2692 m = delta % 60;
2693 delta /= 60;
2694
2695 t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d",
2696 (int)delta, (int)m, (int)s);
2697
2698 return buffer;
2699 }
2700
2701
2702 /*--------------------------------------------------
2703 * parse_statistics - list summary of clock states
2704 */
2705 static void
2706 parse_statistics(
2707 struct parseunit *parse
2708 )
2709 {
2710 int i;
2711
2712 NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */
2713 {
2714 msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
2715 CLK_UNIT(parse->peer),
2716 l_mktime(current_time - parse->generic->timestarted));
2717
2718 msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
2719 CLK_UNIT(parse->peer),
2720 clockstatus(parse->generic->currentstatus));
2721
2722 for (i = 0; i <= CEVNT_MAX; i++)
2723 {
2724 u_long s_time;
2725 u_long percent, d = current_time - parse->generic->timestarted;
2726
2727 percent = s_time = PARSE_STATETIME(parse, i);
2728
2729 while (((u_long)(~0) / 10000) < percent)
2730 {
2731 percent /= 10;
2732 d /= 10;
2733 }
2734
2735 if (d)
2736 percent = (percent * 10000) / d;
2737 else
2738 percent = 10000;
2739
2740 if (s_time)
2741 msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)",
2742 CLK_UNIT(parse->peer),
2743 clockstatus((unsigned int)i),
2744 l_mktime(s_time),
2745 percent / 100, percent % 100);
2746 }
2747 }
2748 }
2749
2750 /*--------------------------------------------------
2751 * cparse_statistics - wrapper for statistics call
2752 */
2753 static void
2754 cparse_statistics(
2755 struct parseunit *parse
2756 )
2757 {
2758 if (parse->laststatistic + PARSESTATISTICS < current_time)
2759 parse_statistics(parse);
2760 parse->laststatistic = current_time;
2761 }
2762
2763 /**===========================================================================
2764 ** ntp interface routines
2765 **/
2766
2767 /*--------------------------------------------------
2768 * parse_shutdown - shut down a PARSE clock
2769 */
2770 static void
2771 parse_shutdown(
2772 int unit,
2773 struct peer *peer
2774 )
2775 {
2776 struct parseunit *parse = NULL;
2777
2778 if (peer && peer->procptr)
2779 parse = peer->procptr->unitptr;
2780
2781 if (!parse)
2782 {
2783 /* nothing to clean up */
2784 return;
2785 }
2786
2787 if (!parse->peer)
2788 {
2789 msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit);
2790 return;
2791 }
2792
2793 #ifdef HAVE_PPSAPI
2794 if (parse->flags & PARSE_PPSCLOCK)
2795 {
2796 (void)time_pps_destroy(parse->atom.handle);
2797 }
2798 #endif
2799 if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1)
2800 (void)closeserial(parse->ppsfd); /* close separate PPS source */
2801
2802 /*
2803 * print statistics a last time and
2804 * stop statistics machine
2805 */
2806 parse_statistics(parse);
2807
2808 if (parse->parse_type->cl_end)
2809 {
2810 parse->parse_type->cl_end(parse);
2811 }
2812
2813 /*
2814 * cleanup before leaving this world
2815 */
2816 if (parse->binding)
2817 PARSE_END(parse);
2818
2819 /*
2820 * Tell the I/O module to turn us off. We're history.
2821 */
2822 io_closeclock(&parse->generic->io);
2823
2824 free_varlist(parse->kv);
2825
2826 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2827 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
2828 CLK_UNIT(parse->peer), parse->parse_type->cl_description);
2829
2830 parse->peer = (struct peer *)0; /* unused now */
2831 peer->procptr->unitptr = (caddr_t)0;
2832 free(parse);
2833 }
2834
2835 #ifdef HAVE_PPSAPI
2836 /*----------------------------------------
2837 * set up HARDPPS via PPSAPI
2838 */
2839 static void
2840 parse_hardpps(
2841 struct parseunit *parse,
2842 int mode
2843 )
2844 {
2845 if (parse->hardppsstate == mode)
2846 return;
2847
2848 if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) {
2849 int i = 0;
2850
2851 if (mode == PARSE_HARDPPS_ENABLE)
2852 {
2853 if (parse->flags & PARSE_CLEAR)
2854 i = PPS_CAPTURECLEAR;
2855 else
2856 i = PPS_CAPTUREASSERT;
2857 }
2858
2859 if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i,
2860 PPS_TSFMT_TSPEC) < 0) {
2861 msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m",
2862 CLK_UNIT(parse->peer));
2863 } else {
2864 NLOG(NLOG_CLOCKINFO)
2865 msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled",
2866 CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis");
2867 /*
2868 * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS
2869 */
2870 if (mode == PARSE_HARDPPS_ENABLE)
2871 pps_enable = 1;
2872 }
2873 }
2874
2875 parse->hardppsstate = mode;
2876 }
2877
2878 /*----------------------------------------
2879 * set up PPS via PPSAPI
2880 */
2881 static int
2882 parse_ppsapi(
2883 struct parseunit *parse
2884 )
2885 {
2886 int cap, mode_ppsoffset;
2887 const char *cp;
2888
2889 parse->flags &= ~PARSE_PPSCLOCK;
2890
2891 /*
2892 * collect PPSAPI offset capability - should move into generic handling
2893 */
2894 if (time_pps_getcap(parse->atom.handle, &cap) < 0) {
2895 msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m",
2896 CLK_UNIT(parse->peer));
2897
2898 return 0;
2899 }
2900
2901 /*
2902 * initialize generic PPSAPI interface
2903 *
2904 * we leave out CLK_FLAG3 as time_pps_kcbind()
2905 * is handled here for now. Ideally this should also
2906 * be part of the generic PPSAPI interface
2907 */
2908 if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom))
2909 return 0;
2910
2911 /* nb. only turn things on, if someone else has turned something
2912 * on before we get here, leave it alone!
2913 */
2914
2915 if (parse->flags & PARSE_CLEAR) {
2916 cp = "CLEAR";
2917 mode_ppsoffset = PPS_OFFSETCLEAR;
2918 } else {
2919 cp = "ASSERT";
2920 mode_ppsoffset = PPS_OFFSETASSERT;
2921 }
2922
2923 msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s",
2924 CLK_UNIT(parse->peer), cp);
2925
2926 if (!(mode_ppsoffset & cap)) {
2927 msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)",
2928 CLK_UNIT(parse->peer), cp, cap);
2929 mode_ppsoffset = 0;
2930 } else {
2931 if (mode_ppsoffset == PPS_OFFSETCLEAR)
2932 {
2933 parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust;
2934 parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2935 }
2936
2937 if (mode_ppsoffset == PPS_OFFSETASSERT)
2938 {
2939 parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust;
2940 parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust);
2941 }
2942 }
2943
2944 parse->atom.pps_params.mode |= mode_ppsoffset;
2945
2946 if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) {
2947 msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m",
2948 CLK_UNIT(parse->peer));
2949 return 0;
2950 }
2951
2952 parse->flags |= PARSE_PPSCLOCK;
2953 return 1;
2954 }
2955 #else
2956 #define parse_hardpps(_PARSE_, _MODE_) /* empty */
2957 #endif
2958
2959 /*--------------------------------------------------
2960 * parse_start - open the PARSE devices and initialize data for processing
2961 */
2962 static int
2963 parse_start(
2964 int sysunit,
2965 struct peer *peer
2966 )
2967 {
2968 u_int unit;
2969 int fd232;
2970 #ifdef HAVE_TERMIOS
2971 struct termios tio; /* NEEDED FOR A LONG TIME ! */
2972 #endif
2973 #ifdef HAVE_SYSV_TTYS
2974 struct termio tio; /* NEEDED FOR A LONG TIME ! */
2975 #endif
2976 struct parseunit * parse;
2977 char parsedev[sizeof(PARSEDEVICE)+20];
2978 char parseppsdev[sizeof(PARSEPPSDEVICE)+20];
2979 parsectl_t tmp_ctl;
2980 u_int type;
2981
2982 /*
2983 * get out Copyright information once
2984 */
2985 if (!notice)
2986 {
2987 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
2988 msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel");
2989 notice = 1;
2990 }
2991
2992 type = CLK_TYPE(peer);
2993 unit = CLK_UNIT(peer);
2994
2995 if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0))
2996 {
2997 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
2998 unit, CLK_REALTYPE(peer), ncltypes-1);
2999 return 0;
3000 }
3001
3002 /*
3003 * Unit okay, attempt to open the device.
3004 */
3005 (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit);
3006 (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit);
3007
3008 #ifndef O_NOCTTY
3009 #define O_NOCTTY 0
3010 #endif
3011 #ifndef O_NONBLOCK
3012 #define O_NONBLOCK 0
3013 #endif
3014
3015 fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3016
3017 if (fd232 == -1)
3018 {
3019 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
3020 return 0;
3021 }
3022
3023 parse = emalloc_zero(sizeof(*parse));
3024
3025 parse->generic = peer->procptr; /* link up */
3026 parse->generic->unitptr = (caddr_t)parse; /* link down */
3027
3028 /*
3029 * Set up the structures
3030 */
3031 parse->generic->timestarted = current_time;
3032 parse->lastchange = current_time;
3033
3034 parse->flags = 0;
3035 parse->pollneeddata = 0;
3036 parse->laststatistic = current_time;
3037 parse->lastformat = (unsigned short)~0; /* assume no format known */
3038 parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */
3039 parse->lastmissed = 0; /* assume got everything */
3040 parse->ppsserial = 0;
3041 parse->ppsfd = -1;
3042 parse->localdata = (void *)0;
3043 parse->localstate = 0;
3044 parse->kv = (struct ctl_var *)0;
3045
3046 clear_err(parse, ERR_ALL);
3047
3048 parse->parse_type = &parse_clockinfo[type];
3049
3050 parse->maxunsync = parse->parse_type->cl_maxunsync;
3051
3052 parse->generic->fudgetime1 = parse->parse_type->cl_basedelay;
3053
3054 parse->generic->fudgetime2 = 0.0;
3055 parse->ppsphaseadjust = parse->generic->fudgetime2;
3056
3057 parse->generic->clockdesc = parse->parse_type->cl_description;
3058
3059 peer->rootdelay = parse->parse_type->cl_rootdelay;
3060 peer->sstclktype = parse->parse_type->cl_type;
3061 peer->precision = sys_precision;
3062
3063 peer->stratum = STRATUM_REFCLOCK;
3064
3065 if (peer->stratum <= 1)
3066 memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4);
3067 else
3068 parse->generic->refid = htonl(PARSEHSREFID);
3069
3070 parse->generic->io.fd = fd232;
3071
3072 parse->peer = peer; /* marks it also as busy */
3073
3074 /*
3075 * configure terminal line
3076 */
3077 if (TTY_GETATTR(fd232, &tio) == -1)
3078 {
3079 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232);
3080 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3081 return 0;
3082 }
3083 else
3084 {
3085 #ifndef _PC_VDISABLE
3086 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc));
3087 #else
3088 int disablec;
3089 errno = 0; /* pathconf can deliver -1 without changing errno ! */
3090
3091 disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE);
3092 if (disablec == -1 && errno)
3093 {
3094 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer));
3095 memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */
3096 }
3097 else
3098 if (disablec != -1)
3099 memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc));
3100 #endif
3101
3102 #if defined (VMIN) || defined(VTIME)
3103 if ((parse_clockinfo[type].cl_lflag & ICANON) == 0)
3104 {
3105 #ifdef VMIN
3106 tio.c_cc[VMIN] = 1;
3107 #endif
3108 #ifdef VTIME
3109 tio.c_cc[VTIME] = 0;
3110 #endif
3111 }
3112 #endif
3113
3114 tio.c_cflag = parse_clockinfo[type].cl_cflag;
3115 tio.c_iflag = parse_clockinfo[type].cl_iflag;
3116 tio.c_oflag = parse_clockinfo[type].cl_oflag;
3117 tio.c_lflag = parse_clockinfo[type].cl_lflag;
3118
3119
3120 #ifdef HAVE_TERMIOS
3121 if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) ||
3122 (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1))
3123 {
3124 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit);
3125 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3126 return 0;
3127 }
3128 #else
3129 tio.c_cflag |= parse_clockinfo[type].cl_speed;
3130 #endif
3131
3132 /*
3133 * set up pps device
3134 * if the PARSEPPSDEVICE can be opened that will be used
3135 * for PPS else PARSEDEVICE will be used
3136 */
3137 parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777);
3138
3139 if (parse->ppsfd == -1)
3140 {
3141 parse->ppsfd = fd232;
3142 }
3143
3144 /*
3145 * Linux PPS - the old way
3146 */
3147 #if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */
3148 {
3149 struct serial_struct ss;
3150 if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 ||
3151 (
3152 #ifdef ASYNC_LOW_LATENCY
3153 ss.flags |= ASYNC_LOW_LATENCY,
3154 #endif
3155 #ifndef HAVE_PPSAPI
3156 #ifdef ASYNC_PPS_CD_NEG
3157 ss.flags |= ASYNC_PPS_CD_NEG,
3158 #endif
3159 #endif
3160 ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) {
3161 msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd);
3162 msyslog(LOG_NOTICE,
3163 "refclock_parse: optional PPS processing not available");
3164 } else {
3165 parse->flags |= PARSE_PPSCLOCK;
3166 #ifdef ASYNC_PPS_CD_NEG
3167 NLOG(NLOG_CLOCKINFO)
3168 msyslog(LOG_INFO,
3169 "refclock_parse: PPS detection on");
3170 #endif
3171 }
3172 }
3173 #endif
3174
3175 /*
3176 * SUN the Solaris way
3177 */
3178 #ifdef HAVE_TIOCSPPS /* SUN PPS support */
3179 if (CLK_PPS(parse->peer))
3180 {
3181 int i = 1;
3182
3183 if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0)
3184 {
3185 parse->flags |= PARSE_PPSCLOCK;
3186 }
3187 }
3188 #endif
3189
3190 /*
3191 * PPS via PPSAPI
3192 */
3193 #if defined(HAVE_PPSAPI)
3194 parse->hardppsstate = PARSE_HARDPPS_DISABLE;
3195 if (CLK_PPS(parse->peer))
3196 {
3197 if (!refclock_ppsapi(parse->ppsfd, &parse->atom))
3198 {
3199 msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer));
3200 }
3201 else
3202 {
3203 parse_ppsapi(parse);
3204 }
3205 }
3206 #endif
3207
3208 if (TTY_SETATTR(fd232, &tio) == -1)
3209 {
3210 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232);
3211 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3212 return 0;
3213 }
3214 }
3215
3216 /*
3217 * pick correct input machine
3218 */
3219 parse->generic->io.srcclock = peer;
3220 parse->generic->io.datalen = 0;
3221
3222 parse->binding = init_iobinding(parse);
3223
3224 if (parse->binding == (bind_t *)0)
3225 {
3226 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer));
3227 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3228 return 0; /* well, ok - special initialisation broke */
3229 }
3230
3231 parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
3232 parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */
3233
3234 /*
3235 * as we always(?) get 8 bit chars we want to be
3236 * sure, that the upper bits are zero for less
3237 * than 8 bit I/O - so we pass that information on.
3238 * note that there can be only one bit count format
3239 * per file descriptor
3240 */
3241
3242 switch (tio.c_cflag & CSIZE)
3243 {
3244 case CS5:
3245 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
3246 break;
3247
3248 case CS6:
3249 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
3250 break;
3251
3252 case CS7:
3253 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
3254 break;
3255
3256 case CS8:
3257 tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
3258 break;
3259 }
3260
3261 if (!PARSE_SETCS(parse, &tmp_ctl))
3262 {
3263 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
3264 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3265 return 0; /* well, ok - special initialisation broke */
3266 }
3267
3268 strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer));
3269 tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
3270
3271 if (!PARSE_SETFMT(parse, &tmp_ctl))
3272 {
3273 msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
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 * get rid of all IO accumulated so far
3280 */
3281 #ifdef HAVE_TERMIOS
3282 (void) tcflush(parse->generic->io.fd, TCIOFLUSH);
3283 #else
3284 #if defined(TCFLSH) && defined(TCIOFLUSH)
3285 {
3286 int flshcmd = TCIOFLUSH;
3287
3288 (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd);
3289 }
3290 #endif
3291 #endif
3292
3293 /*
3294 * try to do any special initializations
3295 */
3296 if (parse->parse_type->cl_init)
3297 {
3298 if (parse->parse_type->cl_init(parse))
3299 {
3300 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3301 return 0; /* well, ok - special initialisation broke */
3302 }
3303 }
3304
3305 /*
3306 * Insert in async io device list.
3307 */
3308 if (!io_addclock(&parse->generic->io))
3309 {
3310 msyslog(LOG_ERR,
3311 "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev);
3312 parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */
3313 return 0;
3314 }
3315
3316 /*
3317 * print out configuration
3318 */
3319 NLOG(NLOG_CLOCKINFO)
3320 {
3321 /* conditional if clause for conditional syslog */
3322 msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added",
3323 CLK_UNIT(parse->peer),
3324 parse->parse_type->cl_description, parsedev,
3325 (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev);
3326
3327 msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d",
3328 CLK_UNIT(parse->peer),
3329 parse->peer->stratum,
3330 l_mktime(parse->maxunsync), parse->peer->precision);
3331
3332 msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling",
3333 CLK_UNIT(parse->peer),
3334 parse->parse_type->cl_rootdelay,
3335 parse->generic->fudgetime1,
3336 parse->ppsphaseadjust,
3337 parse->binding->bd_description);
3338
3339 msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer),
3340 parse->parse_type->cl_format);
3341 msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer),
3342 CLK_PPS(parse->peer) ? "" : "NO ",
3343 CLK_PPS(parse->peer) ?
3344 #ifdef PPS_METHOD
3345 " (implementation " PPS_METHOD ")"
3346 #else
3347 ""
3348 #endif
3349 : ""
3350 );
3351 }
3352
3353 return 1;
3354 }
3355
3356 /*--------------------------------------------------
3357 * parse_ctl - process changes on flags/time values
3358 */
3359 static void
3360 parse_ctl(
3361 struct parseunit *parse,
3362 const struct refclockstat *in
3363 )
3364 {
3365 if (in)
3366 {
3367 if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
3368 {
3369 parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
3370 (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4));
3371 #if defined(HAVE_PPSAPI)
3372 if (CLK_PPS(parse->peer))
3373 {
3374 parse_ppsapi(parse);
3375 }
3376 #endif
3377 }
3378
3379 if (in->haveflags & CLK_HAVETIME1)
3380 {
3381 parse->generic->fudgetime1 = in->fudgetime1;
3382 msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s",
3383 CLK_UNIT(parse->peer),
3384 parse->generic->fudgetime1);
3385 }
3386
3387 if (in->haveflags & CLK_HAVETIME2)
3388 {
3389 parse->generic->fudgetime2 = in->fudgetime2;
3390 if (parse->flags & PARSE_TRUSTTIME)
3391 {
3392 parse->maxunsync = (u_long)ABS(in->fudgetime2);
3393 msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s",
3394 CLK_UNIT(parse->peer),
3395 l_mktime(parse->maxunsync));
3396 }
3397 else
3398 {
3399 parse->ppsphaseadjust = in->fudgetime2;
3400 msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s",
3401 CLK_UNIT(parse->peer),
3402 parse->ppsphaseadjust);
3403 #if defined(HAVE_PPSAPI)
3404 if (CLK_PPS(parse->peer))
3405 {
3406 parse_ppsapi(parse);
3407 }
3408 #endif
3409 }
3410 }
3411 }
3412 }
3413
3414 /*--------------------------------------------------
3415 * parse_poll - called by the transmit procedure
3416 */
3417 static void
3418 parse_poll(
3419 int unit,
3420 struct peer *peer
3421 )
3422 {
3423 struct parseunit *parse = peer->procptr->unitptr;
3424
3425 if (peer != parse->peer)
3426 {
3427 msyslog(LOG_ERR,
3428 "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
3429 unit);
3430 return;
3431 }
3432
3433 /*
3434 * Update clock stat counters
3435 */
3436 parse->generic->polls++;
3437
3438 if (parse->pollneeddata &&
3439 ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll)))))
3440 {
3441 /*
3442 * start worrying when exceeding a poll inteval
3443 * bad news - didn't get a response last time
3444 */
3445 parse->lastmissed = current_time;
3446 parse_event(parse, CEVNT_TIMEOUT);
3447
3448 ERR(ERR_NODATA)
3449 msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer));
3450 }
3451
3452 /*
3453 * we just mark that we want the next sample for the clock filter
3454 */
3455 parse->pollneeddata = current_time;
3456
3457 if (parse->parse_type->cl_poll)
3458 {
3459 parse->parse_type->cl_poll(parse);
3460 }
3461
3462 cparse_statistics(parse);
3463
3464 return;
3465 }
3466
3467 #define LEN_STATES 300 /* length of state string */
3468
3469 /*--------------------------------------------------
3470 * parse_control - set fudge factors, return statistics
3471 */
3472 static void
3473 parse_control(
3474 int unit,
3475 const struct refclockstat *in,
3476 struct refclockstat *out,
3477 struct peer *peer
3478 )
3479 {
3480 struct parseunit *parse = peer->procptr->unitptr;
3481 parsectl_t tmpctl;
3482
3483 static char outstatus[400]; /* status output buffer */
3484
3485 if (out)
3486 {
3487 out->lencode = 0;
3488 out->p_lastcode = 0;
3489 out->kv_list = (struct ctl_var *)0;
3490 }
3491
3492 if (!parse || !parse->peer)
3493 {
3494 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
3495 unit);
3496 return;
3497 }
3498
3499 unit = CLK_UNIT(parse->peer);
3500
3501 /*
3502 * handle changes
3503 */
3504 parse_ctl(parse, in);
3505
3506 /*
3507 * supply data
3508 */
3509 if (out)
3510 {
3511 u_long sum = 0;
3512 char *tt, *start;
3513 int i;
3514
3515 outstatus[0] = '\0';
3516
3517 out->type = REFCLK_PARSE;
3518
3519 /*
3520 * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1
3521 */
3522 parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust;
3523
3524 /*
3525 * figure out skew between PPS and RS232 - just for informational
3526 * purposes
3527 */
3528 if (PARSE_SYNC(parse->timedata.parse_state))
3529 {
3530 if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state))
3531 {
3532 l_fp off;
3533
3534 /*
3535 * we have a PPS and RS232 signal - calculate the skew
3536 * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
3537 */
3538 off = parse->timedata.parse_stime.fp;
3539 L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */
3540 tt = add_var(&out->kv_list, 80, RO);
3541 snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6));
3542 }
3543 }
3544
3545 if (PARSE_PPS(parse->timedata.parse_state))
3546 {
3547 tt = add_var(&out->kv_list, 80, RO|DEF);
3548 snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp));
3549 }
3550
3551 start = tt = add_var(&out->kv_list, 128, RO|DEF);
3552 tt = ap(start, 128, tt, "refclock_time=\"");
3553
3554 if (parse->timedata.parse_time.fp.l_ui == 0)
3555 {
3556 tt = ap(start, 128, tt, "<UNDEFINED>\"");
3557 }
3558 else
3559 {
3560 tt = ap(start, 128, tt, "%s\"",
3561 gmprettydate(&parse->timedata.parse_time.fp));
3562 }
3563
3564 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3565 {
3566 ERR(ERR_INTERNAL)
3567 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
3568 }
3569 else
3570 {
3571 start = tt = add_var(&out->kv_list, 512, RO|DEF);
3572 tt = ap(start, 512, tt, "refclock_status=\"");
3573
3574 /*
3575 * copy PPS flags from last read transaction (informational only)
3576 */
3577 tmpctl.parsegettc.parse_state |= parse->timedata.parse_state &
3578 (PARSEB_PPS|PARSEB_S_PPS);
3579
3580 (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512));
3581
3582 tt += strlen(tt);
3583
3584 tt = ap(start, 512, tt, "\"");
3585
3586 if (tmpctl.parsegettc.parse_count)
3587 mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1),
3588 tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count));
3589
3590 }
3591
3592 tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
3593
3594 if (!PARSE_GETFMT(parse, &tmpctl))
3595 {
3596 ERR(ERR_INTERNAL)
3597 msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
3598 }
3599 else
3600 {
3601 int count = tmpctl.parseformat.parse_count - 1;
3602
3603 start = tt = add_var(&out->kv_list, 80, RO|DEF);
3604 tt = ap(start, 80, tt, "refclock_format=\"");
3605
3606 if (count > 0) {
3607 tt = ap(start, 80, tt, "%*.*s",
3608 count,
3609 count,
3610 tmpctl.parseformat.parse_buffer);
3611 }
3612
3613 tt = ap(start, 80, tt, "\"");
3614 }
3615
3616 /*
3617 * gather state statistics
3618 */
3619
3620 start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF);
3621 tt = ap(start, LEN_STATES, tt, "refclock_states=\"");
3622
3623 for (i = 0; i <= CEVNT_MAX; i++)
3624 {
3625 u_long s_time;
3626 u_long d = current_time - parse->generic->timestarted;
3627 u_long percent;
3628
3629 percent = s_time = PARSE_STATETIME(parse, i);
3630
3631 while (((u_long)(~0) / 10000) < percent)
3632 {
3633 percent /= 10;
3634 d /= 10;
3635 }
3636
3637 if (d)
3638 percent = (percent * 10000) / d;
3639 else
3640 percent = 10000;
3641
3642 if (s_time)
3643 {
3644 char item[80];
3645 int count;
3646
3647 snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)",
3648 sum ? "; " : "",
3649 (parse->generic->currentstatus == i) ? "*" : "",
3650 clockstatus((unsigned int)i),
3651 l_mktime(s_time),
3652 (int)(percent / 100), (int)(percent % 100));
3653 if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start)))
3654 {
3655 tt = ap(start, LEN_STATES, tt,
3656 "%s", item);
3657 }
3658 sum += s_time;
3659 }
3660 }
3661
3662 tt = ap(start, LEN_STATES, tt,
3663 "; running time: %s\"", l_mktime(sum));
3664
3665 tt = add_var(&out->kv_list, 32, RO);
3666 snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id);
3667
3668 tt = add_var(&out->kv_list, 80, RO);
3669 snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description);
3670
3671 tt = add_var(&out->kv_list, 128, RO);
3672 snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid);
3673
3674 {
3675 struct ctl_var *k;
3676
3677 k = parse->kv;
3678 while (k && !(k->flags & EOV))
3679 {
3680 set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags);
3681 k++;
3682 }
3683 }
3684
3685 out->lencode = strlen(outstatus);
3686 out->p_lastcode = outstatus;
3687 }
3688 }
3689
3690 /**===========================================================================
3691 ** processing routines
3692 **/
3693
3694 /*--------------------------------------------------
3695 * event handling - note that nominal events will also be posted
3696 * keep track of state dwelling times
3697 */
3698 static void
3699 parse_event(
3700 struct parseunit *parse,
3701 int event
3702 )
3703 {
3704 if (parse->generic->currentstatus != (u_char) event)
3705 {
3706 parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange;
3707 parse->lastchange = current_time;
3708
3709 if (parse->parse_type->cl_event)
3710 parse->parse_type->cl_event(parse, event);
3711
3712 if (event == CEVNT_NOMINAL)
3713 {
3714 NLOG(NLOG_CLOCKSTATUS)
3715 msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED",
3716 CLK_UNIT(parse->peer));
3717 }
3718
3719 refclock_report(parse->peer, event);
3720 }
3721 }
3722
3723 /*--------------------------------------------------
3724 * process a PARSE time sample
3725 */
3726 static void
3727 parse_process(
3728 struct parseunit *parse,
3729 parsetime_t *parsetime
3730 )
3731 {
3732 l_fp off, rectime, reftime;
3733 double fudge;
3734
3735 /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */
3736 ZERO(off);
3737
3738 /*
3739 * check for changes in conversion status
3740 * (only one for each new status !)
3741 */
3742 if (((parsetime->parse_status & CVT_MASK) != CVT_OK) &&
3743 ((parsetime->parse_status & CVT_MASK) != CVT_NONE) &&
3744 (parse->timedata.parse_status != parsetime->parse_status))
3745 {
3746 char buffer[400];
3747
3748 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3749 msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
3750 CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer)));
3751
3752 if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
3753 {
3754 /*
3755 * tell more about the story - list time code
3756 * there is a slight change for a race condition and
3757 * the time code might be overwritten by the next packet
3758 */
3759 parsectl_t tmpctl;
3760
3761 if (!PARSE_GETTIMECODE(parse, &tmpctl))
3762 {
3763 ERR(ERR_INTERNAL)
3764 msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer));
3765 }
3766 else
3767 {
3768 ERR(ERR_BADDATA)
3769 msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)",
3770 CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1)));
3771 }
3772 }
3773 }
3774
3775 /*
3776 * examine status and post appropriate events
3777 */
3778 if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
3779 {
3780 /*
3781 * got bad data - tell the rest of the system
3782 */
3783 switch (parsetime->parse_status & CVT_MASK)
3784 {
3785 case CVT_NONE:
3786 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
3787 parse->parse_type->cl_message)
3788 parse->parse_type->cl_message(parse, parsetime);
3789 /*
3790 * save PPS information that comes piggyback
3791 */
3792 if (PARSE_PPS(parsetime->parse_state))
3793 {
3794 parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3795 parse->timedata.parse_ptime = parsetime->parse_ptime;
3796 }
3797 break; /* well, still waiting - timeout is handled at higher levels */
3798
3799 case CVT_FAIL:
3800 if (parsetime->parse_status & CVT_BADFMT)
3801 {
3802 parse_event(parse, CEVNT_BADREPLY);
3803 }
3804 else
3805 if (parsetime->parse_status & CVT_BADDATE)
3806 {
3807 parse_event(parse, CEVNT_BADDATE);
3808 }
3809 else
3810 if (parsetime->parse_status & CVT_BADTIME)
3811 {
3812 parse_event(parse, CEVNT_BADTIME);
3813 }
3814 else
3815 {
3816 parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
3817 }
3818 }
3819 return; /* skip the rest - useless */
3820 }
3821
3822 /*
3823 * check for format changes
3824 * (in case somebody has swapped clocks 8-)
3825 */
3826 if (parse->lastformat != parsetime->parse_format)
3827 {
3828 parsectl_t tmpctl;
3829
3830 tmpctl.parseformat.parse_format = parsetime->parse_format;
3831
3832 if (!PARSE_GETFMT(parse, &tmpctl))
3833 {
3834 ERR(ERR_INTERNAL)
3835 msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer));
3836 }
3837 else
3838 {
3839 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3840 msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"",
3841 CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer);
3842 }
3843 parse->lastformat = parsetime->parse_format;
3844 }
3845
3846 /*
3847 * now, any changes ?
3848 */
3849 if ((parse->timedata.parse_state ^ parsetime->parse_state) &
3850 ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS))
3851 {
3852 char tmp1[200];
3853 char tmp2[200];
3854 /*
3855 * something happend - except for PPS events
3856 */
3857
3858 (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1));
3859 (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2));
3860
3861 NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
3862 msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
3863 CLK_UNIT(parse->peer), tmp2, tmp1);
3864 }
3865
3866 /*
3867 * carry on PPS information if still usable
3868 */
3869 if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state))
3870 {
3871 parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS;
3872 parsetime->parse_ptime = parse->timedata.parse_ptime;
3873 }
3874
3875 /*
3876 * remember for future
3877 */
3878 parse->timedata = *parsetime;
3879
3880 /*
3881 * check to see, whether the clock did a complete powerup or lost PZF signal
3882 * and post correct events for current condition
3883 */
3884 if (PARSE_POWERUP(parsetime->parse_state))
3885 {
3886 /*
3887 * this is bad, as we have completely lost synchronisation
3888 * well this is a problem with the receiver here
3889 * for PARSE Meinberg DCF77 receivers the lost synchronisation
3890 * is true as it is the powerup state and the time is taken
3891 * from a crude real time clock chip
3892 * for the PZF/GPS series this is only partly true, as
3893 * PARSE_POWERUP only means that the pseudo random
3894 * phase shift sequence cannot be found. this is only
3895 * bad, if we have never seen the clock in the SYNC
3896 * state, where the PHASE and EPOCH are correct.
3897 * for reporting events the above business does not
3898 * really matter, but we can use the time code
3899 * even in the POWERUP state after having seen
3900 * the clock in the synchronized state (PZF class
3901 * receivers) unless we have had a telegram disruption
3902 * after having seen the clock in the SYNC state. we
3903 * thus require having seen the clock in SYNC state
3904 * *after* having missed telegrams (noresponse) from
3905 * the clock. one problem remains: we might use erroneously
3906 * POWERUP data if the disruption is shorter than 1 polling
3907 * interval. fortunately powerdowns last usually longer than 64
3908 * seconds and the receiver is at least 2 minutes in the
3909 * POWERUP or NOSYNC state before switching to SYNC
3910 * for GPS receivers this can mean antenna problems and other causes.
3911 * the additional grace period can be enables by a clock
3912 * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set.
3913 */
3914 parse_event(parse, CEVNT_FAULT);
3915 NLOG(NLOG_CLOCKSTATUS)
3916 ERR(ERR_BADSTATUS)
3917 msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS",
3918 CLK_UNIT(parse->peer));
3919 }
3920 else
3921 {
3922 /*
3923 * we have two states left
3924 *
3925 * SYNC:
3926 * this state means that the EPOCH (timecode) and PHASE
3927 * information has be read correctly (at least two
3928 * successive PARSE timecodes were received correctly)
3929 * this is the best possible state - full trust
3930 *
3931 * NOSYNC:
3932 * The clock should be on phase with respect to the second
3933 * signal, but the timecode has not been received correctly within
3934 * at least the last two minutes. this is a sort of half baked state
3935 * for PARSE Meinberg DCF77 clocks this is bad news (clock running
3936 * without timecode confirmation)
3937 * PZF 535 has also no time confirmation, but the phase should be
3938 * very precise as the PZF signal can be decoded
3939 */
3940
3941 if (PARSE_SYNC(parsetime->parse_state))
3942 {
3943 /*
3944 * currently completely synchronized - best possible state
3945 */
3946 parse->lastsync = current_time;
3947 clear_err(parse, ERR_BADSTATUS);
3948 }
3949 else
3950 {
3951 /*
3952 * we have had some problems receiving the time code
3953 */
3954 parse_event(parse, CEVNT_PROP);
3955 NLOG(NLOG_CLOCKSTATUS)
3956 ERR(ERR_BADSTATUS)
3957 msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED",
3958 CLK_UNIT(parse->peer));
3959 }
3960 }
3961
3962 fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */
3963
3964 if (PARSE_TIMECODE(parsetime->parse_state))
3965 {
3966 rectime = parsetime->parse_stime.fp;
3967 off = reftime = parsetime->parse_time.fp;
3968
3969 L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */
3970
3971 #ifdef DEBUG
3972 if (debug > 3)
3973 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n",
3974 CLK_UNIT(parse->peer),
3975 prettydate(&reftime),
3976 prettydate(&rectime),
3977 lfptoa(&off,6));
3978 #endif
3979 }
3980
3981 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
3982 {
3983 l_fp offset;
3984 double ppsphaseadjust = parse->ppsphaseadjust;
3985
3986 #ifdef HAVE_PPSAPI
3987 /*
3988 * set fudge = 0.0 if already included in PPS time stamps
3989 */
3990 if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT))
3991 {
3992 ppsphaseadjust = 0.0;
3993 }
3994 #endif
3995
3996 /*
3997 * we have a PPS signal - much better than the RS232 stuff (we hope)
3998 */
3999 offset = parsetime->parse_ptime.fp;
4000
4001 #ifdef DEBUG
4002 if (debug > 3)
4003 printf("PARSE receiver #%d: PPStime %s\n",
4004 CLK_UNIT(parse->peer),
4005 prettydate(&offset));
4006 #endif
4007 if (PARSE_TIMECODE(parsetime->parse_state))
4008 {
4009 if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) &&
4010 M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf))
4011 {
4012 fudge = ppsphaseadjust; /* pick PPS fudge factor */
4013
4014 /*
4015 * RS232 offsets within [-0.5..0.5[ - take PPS offsets
4016 */
4017
4018 if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
4019 {
4020 reftime = off = offset;
4021 if (reftime.l_uf & 0x80000000)
4022 reftime.l_ui++;
4023 reftime.l_uf = 0;
4024
4025
4026 /*
4027 * implied on second offset
4028 */
4029 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4030 off.l_i = (off.l_uf & 0x8000000) ? -1 : 0; /* sign extend */
4031 }
4032 else
4033 {
4034 /*
4035 * time code describes pulse
4036 */
4037 reftime = off = parsetime->parse_time.fp;
4038
4039 L_SUB(&off, &offset); /* true offset */
4040 }
4041 }
4042 /*
4043 * take RS232 offset when PPS when out of bounds
4044 */
4045 }
4046 else
4047 {
4048 fudge = ppsphaseadjust; /* pick PPS fudge factor */
4049 /*
4050 * Well, no time code to guide us - assume on second pulse
4051 * and pray, that we are within [-0.5..0.5[
4052 */
4053 off = offset;
4054 reftime = offset;
4055 if (reftime.l_uf & 0x80000000)
4056 reftime.l_ui++;
4057 reftime.l_uf = 0;
4058 /*
4059 * implied on second offset
4060 */
4061 off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
4062 off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */
4063 }
4064 }
4065 else
4066 {
4067 if (!PARSE_TIMECODE(parsetime->parse_state))
4068 {
4069 /*
4070 * Well, no PPS, no TIMECODE, no more work ...
4071 */
4072 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
4073 parse->parse_type->cl_message)
4074 parse->parse_type->cl_message(parse, parsetime);
4075 return;
4076 }
4077 }
4078
4079 #ifdef DEBUG
4080 if (debug > 3)
4081 printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n",
4082 CLK_UNIT(parse->peer),
4083 prettydate(&reftime),
4084 prettydate(&rectime),
4085 lfptoa(&off,6));
4086 #endif
4087
4088
4089 rectime = reftime;
4090 L_SUB(&rectime, &off); /* just to keep the ntp interface happy */
4091
4092 #ifdef DEBUG
4093 if (debug > 3)
4094 printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n",
4095 CLK_UNIT(parse->peer),
4096 prettydate(&reftime),
4097 prettydate(&rectime));
4098 #endif
4099
4100 if ((parsetime->parse_status & CVT_ADDITIONAL) &&
4101 parse->parse_type->cl_message)
4102 parse->parse_type->cl_message(parse, parsetime);
4103
4104 if (PARSE_SYNC(parsetime->parse_state))
4105 {
4106 /*
4107 * log OK status
4108 */
4109 parse_event(parse, CEVNT_NOMINAL);
4110 }
4111
4112 clear_err(parse, ERR_BADIO);
4113 clear_err(parse, ERR_BADDATA);
4114 clear_err(parse, ERR_NODATA);
4115 clear_err(parse, ERR_INTERNAL);
4116
4117 /*
4118 * and now stick it into the clock machine
4119 * samples are only valid iff lastsync is not too old and
4120 * we have seen the clock in sync at least once
4121 * after the last time we didn't see an expected data telegram
4122 * at startup being not in sync is also bad just like
4123 * POWERUP state unless PARSE_F_POWERUPTRUST is set
4124 * see the clock states section above for more reasoning
4125 */
4126 if (((current_time - parse->lastsync) > parse->maxunsync) ||
4127 (parse->lastsync < parse->lastmissed) ||
4128 ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) ||
4129 (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) &&
4130 PARSE_POWERUP(parsetime->parse_state)))
4131 {
4132 parse->generic->leap = LEAP_NOTINSYNC;
4133 parse->lastsync = 0; /* wait for full sync again */
4134 }
4135 else
4136 {
4137 if (PARSE_LEAPADD(parsetime->parse_state))
4138 {
4139 /*
4140 * we pick this state also for time code that pass leap warnings
4141 * without direction information (as earth is currently slowing
4142 * down).
4143 */
4144 parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
4145 }
4146 else
4147 if (PARSE_LEAPDEL(parsetime->parse_state))
4148 {
4149 parse->generic->leap = LEAP_DELSECOND;
4150 }
4151 else
4152 {
4153 parse->generic->leap = LEAP_NOWARNING;
4154 }
4155 }
4156
4157 if (parse->generic->leap != LEAP_NOTINSYNC)
4158 {
4159 /*
4160 * only good/trusted samples are interesting
4161 */
4162 #ifdef DEBUG
4163 if (debug > 2)
4164 {
4165 printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n",
4166 CLK_UNIT(parse->peer),
4167 prettydate(&reftime),
4168 prettydate(&rectime),
4169 fudge);
4170 }
4171 #endif
4172 parse->generic->lastref = reftime;
4173
4174 refclock_process_offset(parse->generic, reftime, rectime, fudge);
4175
4176 #ifdef HAVE_PPSAPI
4177 /*
4178 * pass PPS information on to PPS clock
4179 */
4180 if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer))
4181 {
4182 /* refclock_pps includes fudgetime1 - we keep the RS232 offset in there :-( */
4183 double savedtime1 = parse->generic->fudgetime1;
4184
4185 parse->generic->fudgetime1 = fudge;
4186
4187 if (refclock_pps(parse->peer, &parse->atom,
4188 parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4))) {
4189 parse->peer->flags |= FLAG_PPS;
4190 } else {
4191 parse->peer->flags &= ~FLAG_PPS;
4192 }
4193
4194 parse->generic->fudgetime1 = savedtime1;
4195
4196 parse_hardpps(parse, PARSE_HARDPPS_ENABLE);
4197 }
4198 #endif
4199 } else {
4200 parse_hardpps(parse, PARSE_HARDPPS_DISABLE);
4201 parse->peer->flags &= ~FLAG_PPS;
4202 }
4203
4204 /*
4205 * ready, unless the machine wants a sample or
4206 * we are in fast startup mode (peer->dist > MAXDISTANCE)
4207 */
4208 if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE)
4209 return;
4210
4211 parse->pollneeddata = 0;
4212
4213 parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS);
4214
4215 refclock_receive(parse->peer);
4216 }
4217
4218 /**===========================================================================
4220 ** special code for special clocks
4221 **/
4222
4223 static void
4224 mk_utcinfo(
4225 char *t,
4226 int wnt,
4227 int wnlsf,
4228 int dn,
4229 int dtls,
4230 int dtlsf,
4231 int size
4232 )
4233 {
4234 l_fp leapdate;
4235 char *start = t;
4236
4237 snprintf(t, size, "current correction %d sec", dtls);
4238 t += strlen(t);
4239
4240 if (wnlsf < 990)
4241 wnlsf += 1024;
4242
4243 if (wnt < 990)
4244 wnt += 1024;
4245
4246 gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate);
4247
4248 if ((dtlsf != dtls) &&
4249 ((wnlsf - wnt) < 52))
4250 {
4251 snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d",
4252 dtlsf - dtls, gmprettydate(&leapdate), dtlsf);
4253 }
4254 else
4255 {
4256 snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s",
4257 gmprettydate(&leapdate));
4258 }
4259 }
4260
4261 #ifdef CLOCK_MEINBERG
4262 /**===========================================================================
4263 ** Meinberg GPS166/GPS167 support
4264 **/
4265
4266 /*------------------------------------------------------------
4267 * gps16x_message - process GPS16x messages
4268 */
4269 static void
4270 gps16x_message(
4271 struct parseunit *parse,
4272 parsetime_t *parsetime
4273 )
4274 {
4275 if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH)
4276 {
4277 GPS_MSG_HDR header;
4278 unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1;
4279
4280 #ifdef DEBUG
4281 if (debug > 2)
4282 {
4283 char msgbuffer[600];
4284
4285 mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1);
4286 printf("PARSE receiver #%d: received message (%d bytes) >%s<\n",
4287 CLK_UNIT(parse->peer),
4288 parsetime->parse_msglen,
4289 msgbuffer);
4290 }
4291 #endif
4292 get_mbg_header(&bufp, &header);
4293 if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) &&
4294 (header.gps_len == 0 ||
4295 (header.gps_len < sizeof(parsetime->parse_msg) &&
4296 header.gps_data_csum == mbg_csum(bufp, header.gps_len))))
4297 {
4298 /*
4299 * clean message
4300 */
4301 switch (header.gps_cmd)
4302 {
4303 case GPS_SW_REV:
4304 {
4305 char buffer[64];
4306 SW_REV gps_sw_rev;
4307
4308 get_mbg_sw_rev(&bufp, &gps_sw_rev);
4309 snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"",
4310 (gps_sw_rev.code >> 8) & 0xFF,
4311 gps_sw_rev.code & 0xFF,
4312 gps_sw_rev.name[0] ? " " : "",
4313 gps_sw_rev.name);
4314 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4315 }
4316 break;
4317
4318 case GPS_STAT:
4319 {
4320 static struct state
4321 {
4322 unsigned short flag; /* status flag */
4323 unsigned const char *string; /* bit name */
4324 } states[] =
4325 {
4326 { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" },
4327 { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" },
4328 { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" },
4329 { TM_NO_POS, (const unsigned char *)"NO POSITION" },
4330 { 0, (const unsigned char *)"" }
4331 };
4332 unsigned short status;
4333 struct state *s = states;
4334 char buffer[512];
4335 char *p, *b;
4336
4337 status = get_lsb_short(&bufp);
4338 p = b = buffer;
4339 p = ap(buffer, sizeof(buffer), p,
4340 "meinberg_gps_status=\"[0x%04x] ",
4341 status);
4342
4343 if (status)
4344 {
4345 b = p;
4346 while (s->flag)
4347 {
4348 if (status & s->flag)
4349 {
4350 if (p != b)
4351 {
4352 p = ap(buffer, sizeof(buffer), p, ", ");
4353 }
4354
4355 p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string);
4356 }
4357 s++;
4358 }
4359 p = ap(buffer, sizeof(buffer), p, "\"");
4360 }
4361 else
4362 {
4363 p = ap(buffer, sizeof(buffer), p, "<OK>\"");
4364 }
4365
4366 set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF);
4367 }
4368 break;
4369
4370 case GPS_POS_XYZ:
4371 {
4372 XYZ xyz;
4373 char buffer[256];
4374
4375 get_mbg_xyz(&bufp, xyz);
4376 snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"",
4377 mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1),
4378 mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1),
4379 mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1));
4380
4381 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4382 }
4383 break;
4384
4385 case GPS_POS_LLA:
4386 {
4387 LLA lla;
4388 char buffer[256];
4389
4390 get_mbg_lla(&bufp, lla);
4391
4392 snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"",
4393 mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4),
4394 mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4),
4395 mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1));
4396
4397 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4398 }
4399 break;
4400
4401 case GPS_TZDL:
4402 break;
4403
4404 case GPS_PORT_PARM:
4405 break;
4406
4407 case GPS_SYNTH:
4408 break;
4409
4410 case GPS_ANT_INFO:
4411 {
4412 ANT_INFO antinfo;
4413 char buffer[512];
4414 char *p, *q;
4415
4416 get_mbg_antinfo(&bufp, &antinfo);
4417 p = buffer;
4418 p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\"");
4419 switch (antinfo.status)
4420 {
4421 case ANT_INVALID:
4422 p = ap(buffer, sizeof(buffer),
4423 p, "<OK>");
4424 break;
4425
4426 case ANT_DISCONN:
4427 q = ap(buffer, sizeof(buffer),
4428 p, "DISCONNECTED since ");
4429 NLOG(NLOG_CLOCKSTATUS)
4430 ERR(ERR_BADSTATUS)
4431 msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s",
4432 CLK_UNIT(parse->peer), p);
4433
4434 p = q;
4435 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4436 *p = '\0';
4437 break;
4438
4439 case ANT_RECONN:
4440 p = ap(buffer, sizeof(buffer),
4441 p, "RECONNECTED on ");
4442 mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p));
4443 p = ap(buffer, sizeof(buffer),
4444 p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ",
4445 (antinfo.delta_t < 0) ? '-' : '+',
4446 ABS(antinfo.delta_t) / 10000,
4447 ABS(antinfo.delta_t) % 10000);
4448 mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p));
4449 *p = '\0';
4450 break;
4451
4452 default:
4453 p = ap(buffer, sizeof(buffer),
4454 p, "bad status 0x%04x",
4455 antinfo.status);
4456 break;
4457 }
4458
4459 p = ap(buffer, sizeof(buffer), p, "\"");
4460
4461 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4462 }
4463 break;
4464
4465 case GPS_UCAP:
4466 break;
4467
4468 case GPS_CFGH:
4469 {
4470 CFGH cfgh;
4471 char buffer[512];
4472 char *p;
4473
4474 get_mbg_cfgh(&bufp, &cfgh);
4475 if (cfgh.valid)
4476 {
4477 int i;
4478
4479 p = buffer;
4480 p = ap(buffer, sizeof(buffer),
4481 p, "gps_tot_51=\"");
4482 mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p));
4483 p = ap(buffer, sizeof(buffer),
4484 p, "\"");
4485 set_var(&parse->kv, buffer, sizeof(buffer), RO);
4486
4487 p = buffer;
4488 p = ap(buffer, sizeof(buffer),
4489 p, "gps_tot_63=\"");
4490 mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p));
4491 p = ap(buffer, sizeof(buffer),
4492 p, "\"");
4493 set_var(&parse->kv, buffer, sizeof(buffer), RO);
4494
4495 p = buffer;
4496 p = ap(buffer, sizeof(buffer),
4497 p, "gps_t0a=\"");
4498 mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p));
4499 p = ap(buffer, sizeof(buffer),
4500 p, "\"");
4501 set_var(&parse->kv, buffer, sizeof(buffer), RO);
4502
4503 for (i = MIN_SVNO; i < MAX_SVNO; i++)
4504 {
4505 p = buffer;
4506 p = ap(buffer, sizeof(buffer), p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]);
4507 switch (cfgh.cfg[i] & 0x7)
4508 {
4509 case 0:
4510 p = ap(buffer, sizeof(buffer), p, "BLOCK I");
4511 break;
4512 case 1:
4513 p = ap(buffer, sizeof(buffer), p, "BLOCK II");
4514 break;
4515 default:
4516 p = ap(buffer, sizeof(buffer), p, "bad CFG");
4517 break;
4518 }
4519 p = ap(buffer, sizeof(buffer), p, "\"");
4520 set_var(&parse->kv, buffer, sizeof(buffer), RO);
4521
4522 p = buffer;
4523 p = ap(buffer, sizeof(buffer), p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]);
4524 switch ((cfgh.health[i] >> 5) & 0x7 )
4525 {
4526 case 0:
4527 p = ap(buffer, sizeof(buffer), p, "OK;");
4528 break;
4529 case 1:
4530 p = ap(buffer, sizeof(buffer), p, "PARITY;");
4531 break;
4532 case 2:
4533 p = ap(buffer, sizeof(buffer), p, "TLM/HOW;");
4534 break;
4535 case 3:
4536 p = ap(buffer, sizeof(buffer), p, "Z-COUNT;");
4537 break;
4538 case 4:
4539 p = ap(buffer, sizeof(buffer), p, "SUBFRAME 1,2,3;");
4540 break;
4541 case 5:
4542 p = ap(buffer, sizeof(buffer), p, "SUBFRAME 4,5;");
4543 break;
4544 case 6:
4545 p = ap(buffer, sizeof(buffer), p, "UPLOAD BAD;");
4546 break;
4547 case 7:
4548 p = ap(buffer, sizeof(buffer), p, "DATA BAD;");
4549 break;
4550 }
4551
4552 switch (cfgh.health[i] & 0x1F)
4553 {
4554 case 0:
4555 p = ap(buffer, sizeof(buffer), p, "SIGNAL OK");
4556 break;
4557 case 0x1C:
4558 p = ap(buffer, sizeof(buffer), p, "SV TEMP OUT");
4559 break;
4560 case 0x1D:
4561 p = ap(buffer, sizeof(buffer), p, "SV WILL BE TEMP OUT");
4562 break;
4563 case 0x1E:
4564 break;
4565 case 0x1F:
4566 p = ap(buffer, sizeof(buffer), p, "MULTIPLE ERRS");
4567 break;
4568 default:
4569 p = ap(buffer, sizeof(buffer), p, "TRANSMISSION PROBLEMS");
4570 break;
4571 }
4572
4573 p = ap(buffer, sizeof(buffer), p, "\"");
4574 set_var(&parse->kv, buffer, sizeof(buffer), RO);
4575 }
4576 }
4577 }
4578 break;
4579
4580 case GPS_ALM:
4581 break;
4582
4583 case GPS_EPH:
4584 break;
4585
4586 case GPS_UTC:
4587 {
4588 UTC utc;
4589 char buffer[512];
4590 char *p;
4591
4592 p = buffer;
4593
4594 get_mbg_utc(&bufp, &utc);
4595
4596 if (utc.valid)
4597 {
4598 p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"");
4599 mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p));
4600 p += strlen(p);
4601 p = ap(buffer, sizeof(buffer), p, "\"");
4602 }
4603 else
4604 {
4605 p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\"");
4606 }
4607 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4608 }
4609 break;
4610
4611 case GPS_IONO:
4612 break;
4613
4614 case GPS_ASCII_MSG:
4615 {
4616 ASCII_MSG gps_ascii_msg;
4617 char buffer[128];
4618
4619 get_mbg_ascii_msg(&bufp, &gps_ascii_msg);
4620
4621 if (gps_ascii_msg.valid)
4622 {
4623 char buffer1[128];
4624 mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0);
4625
4626 snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1);
4627 }
4628 else
4629 snprintf(buffer, sizeof(buffer), "gps_message=<NONE>");
4630
4631 set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF);
4632 }
4633
4634 break;
4635
4636 default:
4637 break;
4638 }
4639 }
4640 else
4641 {
4642 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)",
4643 CLK_UNIT(parse->peer),
4644 header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6),
4645 header.gps_len,
4646 header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0)));
4647 }
4648 }
4649
4650 return;
4651 }
4652
4653 /*------------------------------------------------------------
4654 * gps16x_poll - query the reciver peridically
4655 */
4656 static void
4657 gps16x_poll(
4658 struct peer *peer
4659 )
4660 {
4661 struct parseunit *parse = peer->procptr->unitptr;
4662
4663 static GPS_MSG_HDR sequence[] =
4664 {
4665 { GPS_SW_REV, 0, 0, 0 },
4666 { GPS_STAT, 0, 0, 0 },
4667 { GPS_UTC, 0, 0, 0 },
4668 { GPS_ASCII_MSG, 0, 0, 0 },
4669 { GPS_ANT_INFO, 0, 0, 0 },
4670 { GPS_CFGH, 0, 0, 0 },
4671 { GPS_POS_XYZ, 0, 0, 0 },
4672 { GPS_POS_LLA, 0, 0, 0 },
4673 { (unsigned short)~0, 0, 0, 0 }
4674 };
4675
4676 int rtc;
4677 unsigned char cmd_buffer[64];
4678 unsigned char *outp = cmd_buffer;
4679 GPS_MSG_HDR *header;
4680
4681 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4682 {
4683 parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4684 }
4685
4686 if (sequence[parse->localstate].gps_cmd == (unsigned short)~0)
4687 parse->localstate = 0;
4688
4689 header = sequence + parse->localstate++;
4690
4691 *outp++ = SOH; /* start command */
4692
4693 put_mbg_header(&outp, header);
4694 outp = cmd_buffer + 1;
4695
4696 header->gps_hdr_csum = (short)mbg_csum(outp, 6);
4697 put_mbg_header(&outp, header);
4698
4699 #ifdef DEBUG
4700 if (debug > 2)
4701 {
4702 char buffer[128];
4703
4704 mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1);
4705 printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n",
4706 CLK_UNIT(parse->peer),
4707 parse->localstate - 1,
4708 (int)(outp - cmd_buffer),
4709 buffer);
4710 }
4711 #endif
4712
4713 rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer));
4714
4715 if (rtc < 0)
4716 {
4717 ERR(ERR_BADIO)
4718 msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4719 }
4720 else
4721 if (rtc != outp - cmd_buffer)
4722 {
4723 ERR(ERR_BADIO)
4724 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));
4725 }
4726
4727 clear_err(parse, ERR_BADIO);
4728 return;
4729 }
4730
4731 /*--------------------------------------------------
4732 * init routine - setup timer
4733 */
4734 static int
4735 gps16x_poll_init(
4736 struct parseunit *parse
4737 )
4738 {
4739 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4740 {
4741 parse->peer->procptr->action = gps16x_poll;
4742 gps16x_poll(parse->peer);
4743 }
4744
4745 return 0;
4746 }
4747
4748 #else
4749 static void
4750 gps16x_message(
4751 struct parseunit *parse,
4752 parsetime_t *parsetime
4753 )
4754 {}
4755 static int
4756 gps16x_poll_init(
4757 struct parseunit *parse
4758 )
4759 {
4760 return 1;
4761 }
4762 #endif /* CLOCK_MEINBERG */
4763
4764 /**===========================================================================
4766 ** clock polling support
4767 **/
4768
4769 /*--------------------------------------------------
4770 * direct poll routine
4771 */
4772 static void
4773 poll_dpoll(
4774 struct parseunit *parse
4775 )
4776 {
4777 int rtc;
4778 const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
4779 int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
4780
4781 rtc = write(parse->generic->io.fd, ps, (unsigned long)ct);
4782 if (rtc < 0)
4783 {
4784 ERR(ERR_BADIO)
4785 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4786 }
4787 else
4788 if (rtc != ct)
4789 {
4790 ERR(ERR_BADIO)
4791 msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct);
4792 }
4793 clear_err(parse, ERR_BADIO);
4794 }
4795
4796 /*--------------------------------------------------
4797 * periodic poll routine
4798 */
4799 static void
4800 poll_poll(
4801 struct peer *peer
4802 )
4803 {
4804 struct parseunit *parse = peer->procptr->unitptr;
4805
4806 if (parse->parse_type->cl_poll)
4807 parse->parse_type->cl_poll(parse);
4808
4809 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4810 {
4811 parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
4812 }
4813 }
4814
4815 /*--------------------------------------------------
4816 * init routine - setup timer
4817 */
4818 static int
4819 poll_init(
4820 struct parseunit *parse
4821 )
4822 {
4823 if (((poll_info_t *)parse->parse_type->cl_data)->rate)
4824 {
4825 parse->peer->procptr->action = poll_poll;
4826 poll_poll(parse->peer);
4827 }
4828
4829 return 0;
4830 }
4831
4832 /**===========================================================================
4834 ** Trimble support
4835 **/
4836
4837 /*-------------------------------------------------------------
4838 * trimble TAIP init routine - setup EOL and then do poll_init.
4839 */
4840 static int
4841 trimbletaip_init(
4842 struct parseunit *parse
4843 )
4844 {
4845 #ifdef HAVE_TERMIOS
4846 struct termios tio;
4847 #endif
4848 #ifdef HAVE_SYSV_TTYS
4849 struct termio tio;
4850 #endif
4851 /*
4852 * configure terminal line for trimble receiver
4853 */
4854 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
4855 {
4856 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4857 return 0;
4858 }
4859 else
4860 {
4861 tio.c_cc[VEOL] = TRIMBLETAIP_EOL;
4862
4863 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
4864 {
4865 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer));
4866 return 0;
4867 }
4868 }
4869 return poll_init(parse);
4870 }
4871
4872 /*--------------------------------------------------
4873 * trimble TAIP event routine - reset receiver upon data format trouble
4874 */
4875 static const char *taipinit[] = {
4876 ">FPV00000000<",
4877 ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<",
4878 ">FTM00020001<",
4879 (char *)0
4880 };
4881
4882 static void
4883 trimbletaip_event(
4884 struct parseunit *parse,
4885 int event
4886 )
4887 {
4888 switch (event)
4889 {
4890 case CEVNT_BADREPLY: /* reset on garbled input */
4891 case CEVNT_TIMEOUT: /* reset on no input */
4892 {
4893 const char **iv;
4894
4895 iv = taipinit;
4896 while (*iv)
4897 {
4898 int rtc = write(parse->generic->io.fd, *iv, strlen(*iv));
4899 if (rtc < 0)
4900 {
4901 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
4902 return;
4903 }
4904 else
4905 {
4906 if (rtc != (int)strlen(*iv))
4907 {
4908 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)",
4909 CLK_UNIT(parse->peer), rtc, (int)strlen(*iv));
4910 return;
4911 }
4912 }
4913 iv++;
4914 }
4915
4916 NLOG(NLOG_CLOCKINFO)
4917 ERR(ERR_BADIO)
4918 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED",
4919 CLK_UNIT(parse->peer));
4920 }
4921 break;
4922
4923 default: /* ignore */
4924 break;
4925 }
4926 }
4927
4928 /*
4929 * This driver supports the Trimble SVee Six Plus GPS receiver module.
4930 * It should support other Trimble receivers which use the Trimble Standard
4931 * Interface Protocol (see below).
4932 *
4933 * The module has a serial I/O port for command/data and a 1 pulse-per-second
4934 * output, about 1 microsecond wide. The leading edge of the pulse is
4935 * coincident with the change of the GPS second. This is the same as
4936 * the change of the UTC second +/- ~1 microsecond. Some other clocks
4937 * specifically use a feature in the data message as a timing reference, but
4938 * the SVee Six Plus does not do this. In fact there is considerable jitter
4939 * on the timing of the messages, so this driver only supports the use
4940 * of the PPS pulse for accurate timing. Where it is determined that
4941 * the offset is way off, when first starting up ntpd for example,
4942 * the timing of the data stream is used until the offset becomes low enough
4943 * (|offset| < CLOCK_MAX), at which point the pps offset is used.
4944 *
4945 * It can use either option for receiving PPS information - the 'ppsclock'
4946 * stream pushed onto the serial data interface to timestamp the Carrier
4947 * Detect interrupts, where the 1PPS connects to the CD line. This only
4948 * works on SunOS 4.1.x currently. To select this, define PPSPPS in
4949 * Config.local. The other option is to use a pulse-stretcher/level-converter
4950 * to convert the PPS pulse into a RS232 start pulse & feed this into another
4951 * tty port. To use this option, define PPSCLK in Config.local. The pps input,
4952 * by whichever method, is handled in ntp_loopfilter.c
4953 *
4954 * The receiver uses a serial message protocol called Trimble Standard
4955 * Interface Protocol (it can support others but this driver only supports
4956 * TSIP). Messages in this protocol have the following form:
4957 *
4958 * <DLE><id> ... <data> ... <DLE><ETX>
4959 *
4960 * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
4961 * on transmission and compressed back to one on reception. Otherwise
4962 * the values of data bytes can be anything. The serial interface is RS-422
4963 * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
4964 * in total!), and 1 stop bit. The protocol supports byte, integer, single,
4965 * and double datatypes. Integers are two bytes, sent most significant first.
4966 * Singles are IEEE754 single precision floating point numbers (4 byte) sent
4967 * sign & exponent first. Doubles are IEEE754 double precision floating point
4968 * numbers (8 byte) sent sign & exponent first.
4969 * The receiver supports a large set of messages, only a small subset of
4970 * which are used here. From driver to receiver the following are used:
4971 *
4972 * ID Description
4973 *
4974 * 21 Request current time
4975 * 22 Mode Select
4976 * 2C Set/Request operating parameters
4977 * 2F Request UTC info
4978 * 35 Set/Request I/O options
4979
4980 * From receiver to driver the following are recognised:
4981 *
4982 * ID Description
4983 *
4984 * 41 GPS Time
4985 * 44 Satellite selection, PDOP, mode
4986 * 46 Receiver health
4987 * 4B Machine code/status
4988 * 4C Report operating parameters (debug only)
4989 * 4F UTC correction data (used to get leap second warnings)
4990 * 55 I/O options (debug only)
4991 *
4992 * All others are accepted but ignored.
4993 *
4994 */
4995
4996 #define PI 3.1415926535898 /* lots of sig figs */
4997 #define D2R PI/180.0
4998
4999 /*-------------------------------------------------------------------
5000 * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
5001 * interface to the receiver.
5002 *
5003 * CAVEAT: the sendflt, sendint routines are byte order dependend and
5004 * float implementation dependend - these must be converted to portable
5005 * versions !
5006 *
5007 * CURRENT LIMITATION: float implementation. This runs only on systems
5008 * with IEEE754 floats as native floats
5009 */
5010
5011 typedef struct trimble
5012 {
5013 u_long last_msg; /* last message received */
5014 u_long last_reset; /* last time a reset was issued */
5015 u_char qtracking; /* query tracking status */
5016 u_long ctrack; /* current tracking set */
5017 u_long ltrack; /* last tracking set */
5018 } trimble_t;
5019
5020 union uval {
5021 u_char bd[8];
5022 int iv;
5023 float fv;
5024 double dv;
5025 };
5026
5027 struct txbuf
5028 {
5029 short idx; /* index to first unused byte */
5030 u_char *txt; /* pointer to actual data buffer */
5031 };
5032
5033 void sendcmd (struct txbuf *buf, int c);
5034 void sendbyte (struct txbuf *buf, int b);
5035 void sendetx (struct txbuf *buf, struct parseunit *parse);
5036 void sendint (struct txbuf *buf, int a);
5037 void sendflt (struct txbuf *buf, double a);
5038
5039 void
5040 sendcmd(
5041 struct txbuf *buf,
5042 int c
5043 )
5044 {
5045 buf->txt[0] = DLE;
5046 buf->txt[1] = (u_char)c;
5047 buf->idx = 2;
5048 }
5049
5050 void sendcmd (struct txbuf *buf, int c);
5051 void sendbyte (struct txbuf *buf, int b);
5052 void sendetx (struct txbuf *buf, struct parseunit *parse);
5053 void sendint (struct txbuf *buf, int a);
5054 void sendflt (struct txbuf *buf, double a);
5055
5056 void
5057 sendbyte(
5058 struct txbuf *buf,
5059 int b
5060 )
5061 {
5062 if (b == DLE)
5063 buf->txt[buf->idx++] = DLE;
5064 buf->txt[buf->idx++] = (u_char)b;
5065 }
5066
5067 void
5068 sendetx(
5069 struct txbuf *buf,
5070 struct parseunit *parse
5071 )
5072 {
5073 buf->txt[buf->idx++] = DLE;
5074 buf->txt[buf->idx++] = ETX;
5075
5076 if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx)
5077 {
5078 ERR(ERR_BADIO)
5079 msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer));
5080 }
5081 else
5082 {
5083 #ifdef DEBUG
5084 if (debug > 2)
5085 {
5086 char buffer[256];
5087
5088 mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1);
5089 printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n",
5090 CLK_UNIT(parse->peer),
5091 buf->idx, buffer);
5092 }
5093 #endif
5094 clear_err(parse, ERR_BADIO);
5095 }
5096 }
5097
5098 void
5099 sendint(
5100 struct txbuf *buf,
5101 int a
5102 )
5103 {
5104 /* send 16bit int, msbyte first */
5105 sendbyte(buf, (u_char)((a>>8) & 0xff));
5106 sendbyte(buf, (u_char)(a & 0xff));
5107 }
5108
5109 void
5110 sendflt(
5111 struct txbuf *buf,
5112 double a
5113 )
5114 {
5115 int i;
5116 union uval uval;
5117
5118 uval.fv = a;
5119 #ifdef WORDS_BIGENDIAN
5120 for (i=0; i<=3; i++)
5121 #else
5122 for (i=3; i>=0; i--)
5123 #endif
5124 sendbyte(buf, uval.bd[i]);
5125 }
5126
5127 #define TRIM_POS_OPT 0x13 /* output position with high precision */
5128 #define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */
5129
5130 /*--------------------------------------------------
5131 * trimble TSIP setup routine
5132 */
5133 static int
5134 trimbletsip_setup(
5135 struct parseunit *parse,
5136 const char *reason
5137 )
5138 {
5139 u_char buffer[256];
5140 struct txbuf buf;
5141 trimble_t *t = parse->localdata;
5142
5143 if (t && t->last_reset &&
5144 ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) {
5145 return 1; /* not yet */
5146 }
5147
5148 if (t)
5149 t->last_reset = current_time;
5150
5151 buf.txt = buffer;
5152
5153 sendcmd(&buf, CMD_CVERSION); /* request software versions */
5154 sendetx(&buf, parse);
5155
5156 sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */
5157 sendbyte(&buf, 4); /* static */
5158 sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
5159 sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */
5160 sendflt(&buf, 12.0); /* PDOP mask = 12 */
5161 sendflt(&buf, 8.0); /* PDOP switch level = 8 */
5162 sendetx(&buf, parse);
5163
5164 sendcmd(&buf, CMD_CMODESEL); /* fix mode select */
5165 sendbyte(&buf, 1); /* time transfer mode */
5166 sendetx(&buf, parse);
5167
5168 sendcmd(&buf, CMD_CMESSAGE); /* request system message */
5169 sendetx(&buf, parse);
5170
5171 sendcmd(&buf, CMD_CSUPER); /* superpacket fix */
5172 sendbyte(&buf, 0x2); /* binary mode */
5173 sendetx(&buf, parse);
5174
5175 sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */
5176 sendbyte(&buf, TRIM_POS_OPT); /* position output */
5177 sendbyte(&buf, 0x00); /* no velocity output */
5178 sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */
5179 sendbyte(&buf, 0x00); /* no raw measurements */
5180 sendetx(&buf, parse);
5181
5182 sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */
5183 sendetx(&buf, parse);
5184
5185 NLOG(NLOG_CLOCKINFO)
5186 ERR(ERR_BADIO)
5187 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason);
5188
5189 return 0;
5190 }
5191
5192 /*--------------------------------------------------
5193 * TRIMBLE TSIP check routine
5194 */
5195 static void
5196 trimble_check(
5197 struct peer *peer
5198 )
5199 {
5200 struct parseunit *parse = peer->procptr->unitptr;
5201 trimble_t *t = parse->localdata;
5202 u_char buffer[256];
5203 struct txbuf buf;
5204 buf.txt = buffer;
5205
5206 if (t)
5207 {
5208 if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME)
5209 (void)trimbletsip_setup(parse, "message timeout");
5210 }
5211
5212 poll_poll(parse->peer); /* emit query string and re-arm timer */
5213
5214 if (t && t->qtracking)
5215 {
5216 u_long oldsats = t->ltrack & ~t->ctrack;
5217
5218 t->qtracking = 0;
5219 t->ltrack = t->ctrack;
5220
5221 if (oldsats)
5222 {
5223 int i;
5224
5225 for (i = 0; oldsats; i++) {
5226 if (oldsats & (1 << i))
5227 {
5228 sendcmd(&buf, CMD_CSTATTRACK);
5229 sendbyte(&buf, i+1); /* old sat */
5230 sendetx(&buf, parse);
5231 }
5232 oldsats &= ~(1 << i);
5233 }
5234 }
5235
5236 sendcmd(&buf, CMD_CSTATTRACK);
5237 sendbyte(&buf, 0x00); /* current tracking set */
5238 sendetx(&buf, parse);
5239 }
5240 }
5241
5242 /*--------------------------------------------------
5243 * TRIMBLE TSIP end routine
5244 */
5245 static void
5246 trimbletsip_end(
5247 struct parseunit *parse
5248 )
5249 { trimble_t *t = parse->localdata;
5250
5251 if (t)
5252 {
5253 free(t);
5254 parse->localdata = NULL;
5255 }
5256 parse->peer->procptr->nextaction = 0;
5257 parse->peer->procptr->action = NULL;
5258 }
5259
5260 /*--------------------------------------------------
5261 * TRIMBLE TSIP init routine
5262 */
5263 static int
5264 trimbletsip_init(
5265 struct parseunit *parse
5266 )
5267 {
5268 #if defined(VEOL) || defined(VEOL2)
5269 #ifdef HAVE_TERMIOS
5270 struct termios tio; /* NEEDED FOR A LONG TIME ! */
5271 #endif
5272 #ifdef HAVE_SYSV_TTYS
5273 struct termio tio; /* NEEDED FOR A LONG TIME ! */
5274 #endif
5275 /*
5276 * allocate local data area
5277 */
5278 if (!parse->localdata)
5279 {
5280 trimble_t *t;
5281
5282 t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t)));
5283
5284 if (t)
5285 {
5286 memset((char *)t, 0, sizeof(trimble_t));
5287 t->last_msg = current_time;
5288 }
5289 }
5290
5291 parse->peer->procptr->action = trimble_check;
5292 parse->peer->procptr->nextaction = current_time;
5293
5294 /*
5295 * configure terminal line for ICANON mode with VEOL characters
5296 */
5297 if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1)
5298 {
5299 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5300 return 0;
5301 }
5302 else
5303 {
5304 if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON))
5305 {
5306 #ifdef VEOL
5307 tio.c_cc[VEOL] = ETX;
5308 #endif
5309 #ifdef VEOL2
5310 tio.c_cc[VEOL2] = DLE;
5311 #endif
5312 }
5313
5314 if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1)
5315 {
5316 msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd);
5317 return 0;
5318 }
5319 }
5320 #endif
5321 return trimbletsip_setup(parse, "initial startup");
5322 }
5323
5324 /*------------------------------------------------------------
5325 * trimbletsip_event - handle Trimble events
5326 * simple evente handler - attempt to re-initialize receiver
5327 */
5328 static void
5329 trimbletsip_event(
5330 struct parseunit *parse,
5331 int event
5332 )
5333 {
5334 switch (event)
5335 {
5336 case CEVNT_BADREPLY: /* reset on garbled input */
5337 case CEVNT_TIMEOUT: /* reset on no input */
5338 (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT");
5339 break;
5340
5341 default: /* ignore */
5342 break;
5343 }
5344 }
5345
5346 /*
5347 * getflt, getint convert fields in the incoming data into the
5348 * appropriate type of item
5349 *
5350 * CAVEAT: these routines are currently definitely byte order dependent
5351 * and assume Representation(float) == IEEE754
5352 * These functions MUST be converted to portable versions (especially
5353 * converting the float representation into ntp_fp formats in order
5354 * to avoid floating point operations at all!
5355 */
5356
5357 static float
5358 getflt(
5359 u_char *bp
5360 )
5361 {
5362 union uval uval;
5363
5364 #ifdef WORDS_BIGENDIAN
5365 uval.bd[0] = *bp++;
5366 uval.bd[1] = *bp++;
5367 uval.bd[2] = *bp++;
5368 uval.bd[3] = *bp;
5369 #else /* ! WORDS_BIGENDIAN */
5370 uval.bd[3] = *bp++;
5371 uval.bd[2] = *bp++;
5372 uval.bd[1] = *bp++;
5373 uval.bd[0] = *bp;
5374 #endif /* ! WORDS_BIGENDIAN */
5375 return uval.fv;
5376 }
5377
5378 static double
5379 getdbl(
5380 u_char *bp
5381 )
5382 {
5383 union uval uval;
5384
5385 #ifdef WORDS_BIGENDIAN
5386 uval.bd[0] = *bp++;
5387 uval.bd[1] = *bp++;
5388 uval.bd[2] = *bp++;
5389 uval.bd[3] = *bp++;
5390 uval.bd[4] = *bp++;
5391 uval.bd[5] = *bp++;
5392 uval.bd[6] = *bp++;
5393 uval.bd[7] = *bp;
5394 #else /* ! WORDS_BIGENDIAN */
5395 uval.bd[7] = *bp++;
5396 uval.bd[6] = *bp++;
5397 uval.bd[5] = *bp++;
5398 uval.bd[4] = *bp++;
5399 uval.bd[3] = *bp++;
5400 uval.bd[2] = *bp++;
5401 uval.bd[1] = *bp++;
5402 uval.bd[0] = *bp;
5403 #endif /* ! WORDS_BIGENDIAN */
5404 return uval.dv;
5405 }
5406
5407 static int
5408 getshort(
5409 unsigned char *p
5410 )
5411 {
5412 return get_msb_short(&p);
5413 }
5414
5415 /*--------------------------------------------------
5416 * trimbletsip_message - process trimble messages
5417 */
5418 #define RTOD (180.0 / 3.1415926535898)
5419 #define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */
5420
5421 static void
5422 trimbletsip_message(
5423 struct parseunit *parse,
5424 parsetime_t *parsetime
5425 )
5426 {
5427 unsigned char *buffer = parsetime->parse_msg;
5428 unsigned int size = parsetime->parse_msglen;
5429
5430 if ((size < 4) ||
5431 (buffer[0] != DLE) ||
5432 (buffer[size-1] != ETX) ||
5433 (buffer[size-2] != DLE))
5434 {
5435 #ifdef DEBUG
5436 if (debug > 2) {
5437 size_t i;
5438
5439 printf("TRIMBLE BAD packet, size %d:\n ", size);
5440 for (i = 0; i < size; i++) {
5441 printf ("%2.2x, ", buffer[i]&0xff);
5442 if (i%16 == 15) printf("\n\t");
5443 }
5444 printf("\n");
5445 }
5446 #endif
5447 return;
5448 }
5449 else
5450 {
5451 int var_flag;
5452 trimble_t *tr = parse->localdata;
5453 unsigned int cmd = buffer[1];
5454 char pbuffer[200];
5455 char *t = pbuffer;
5456 cmd_info_t *s;
5457
5458 #ifdef DEBUG
5459 if (debug > 3) {
5460 size_t i;
5461
5462 printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size);
5463 for (i = 0; i < size; i++) {
5464 printf ("%2.2x, ", buffer[i]&0xff);
5465 if (i%16 == 15) printf("\n\t");
5466 }
5467 printf("\n");
5468 }
5469 #endif
5470
5471 if (tr)
5472 tr->last_msg = current_time;
5473
5474 s = trimble_convert(cmd, trimble_rcmds);
5475
5476 if (s)
5477 {
5478 t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname);
5479 }
5480 else
5481 {
5482 DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd));
5483 return;
5484 }
5485
5486 var_flag = s->varmode;
5487
5488 switch(cmd)
5489 {
5490 case CMD_RCURTIME:
5491 t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f",
5492 getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)),
5493 getflt((unsigned char *)&mb(6)));
5494 break;
5495
5496 case CMD_RBEST4:
5497 t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
5498 switch (mb(0) & 0xF)
5499 {
5500 default:
5501 t = ap(pbuffer, sizeof(pbuffer), t,
5502 "0x%x", mb(0) & 0x7);
5503 break;
5504
5505 case 1:
5506 t = ap(pbuffer, sizeof(pbuffer), t, "0D");
5507 break;
5508
5509 case 3:
5510 t = ap(pbuffer, sizeof(pbuffer), t, "2D");
5511 break;
5512
5513 case 4:
5514 t = ap(pbuffer, sizeof(pbuffer), t, "3D");
5515 break;
5516 }
5517 if (mb(0) & 0x10)
5518 t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
5519 else
5520 t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5521
5522 t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f",
5523 mb(1), mb(2), mb(3), mb(4),
5524 getflt((unsigned char *)&mb(5)),
5525 getflt((unsigned char *)&mb(9)),
5526 getflt((unsigned char *)&mb(13)),
5527 getflt((unsigned char *)&mb(17)));
5528
5529 break;
5530
5531 case CMD_RVERSION:
5532 t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)",
5533 mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff);
5534 break;
5535
5536 case CMD_RRECVHEALTH:
5537 {
5538 static const char *msgs[] =
5539 {
5540 "Battery backup failed",
5541 "Signal processor error",
5542 "Alignment error, channel or chip 1",
5543 "Alignment error, channel or chip 2",
5544 "Antenna feed line fault",
5545 "Excessive ref freq. error",
5546 "<BIT 6>",
5547 "<BIT 7>"
5548 };
5549
5550 int i, bits;
5551
5552 switch (mb(0) & 0xFF)
5553 {
5554 default:
5555 t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF);
5556 break;
5557 case 0x00:
5558 t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes");
5559 break;
5560 case 0x01:
5561 t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet");
5562 break;
5563 case 0x03:
5564 t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high");
5565 break;
5566 case 0x08:
5567 t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites");
5568 break;
5569 case 0x09:
5570 t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite");
5571 break;
5572 case 0x0A:
5573 t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites");
5574 break;
5575 case 0x0B:
5576 t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites");
5577 break;
5578 case 0x0C:
5579 t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable");
5580 break;
5581 }
5582
5583 bits = mb(1) & 0xFF;
5584
5585 for (i = 0; i < 8; i++)
5586 if (bits & (0x1<<i))
5587 {
5588 t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
5589 }
5590 }
5591 break;
5592
5593 case CMD_RMESSAGE:
5594 mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0);
5595 break;
5596
5597 case CMD_RMACHSTAT:
5598 {
5599 static const char *msgs[] =
5600 {
5601 "Synthesizer Fault",
5602 "Battery Powered Time Clock Fault",
5603 "A-to-D Converter Fault",
5604 "The almanac stored in the receiver is not complete and current",
5605 "<BIT 4>",
5606 "<BIT 5",
5607 "<BIT 6>",
5608 "<BIT 7>"
5609 };
5610
5611 int i, bits;
5612
5613 t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF);
5614 bits = mb(1) & 0xFF;
5615
5616 for (i = 0; i < 8; i++)
5617 if (bits & (0x1<<i))
5618 {
5619 t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]);
5620 }
5621
5622 t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" );
5623 }
5624 break;
5625
5626 case CMD_ROPERPARAM:
5627 t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f",
5628 mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)),
5629 getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13)));
5630 break;
5631
5632 case CMD_RUTCPARAM:
5633 {
5634 float t0t = getflt((unsigned char *)&mb(14));
5635 short wnt = getshort((unsigned char *)&mb(18));
5636 short dtls = getshort((unsigned char *)&mb(12));
5637 short wnlsf = getshort((unsigned char *)&mb(20));
5638 short dn = getshort((unsigned char *)&mb(22));
5639 short dtlsf = getshort((unsigned char *)&mb(24));
5640
5641 if ((int)t0t != 0)
5642 {
5643 mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t));
5644 }
5645 else
5646 {
5647 t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>");
5648 }
5649 }
5650 break;
5651
5652 case CMD_RSAT1BIAS:
5653 t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs",
5654 getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8)));
5655 break;
5656
5657 case CMD_RIOOPTIONS:
5658 {
5659 t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x",
5660 mb(0), mb(1), mb(2), mb(3));
5661 if (mb(0) != TRIM_POS_OPT ||
5662 mb(2) != TRIM_TIME_OPT)
5663 {
5664 (void)trimbletsip_setup(parse, "bad io options");
5665 }
5666 }
5667 break;
5668
5669 case CMD_RSPOSXYZ:
5670 {
5671 double x = getflt((unsigned char *)&mb(0));
5672 double y = getflt((unsigned char *)&mb(4));
5673 double z = getflt((unsigned char *)&mb(8));
5674 double f = getflt((unsigned char *)&mb(12));
5675
5676 if (f > 0.0)
5677 t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec",
5678 x, y, z,
5679 f);
5680 else
5681 return;
5682 }
5683 break;
5684
5685 case CMD_RSLLAPOS:
5686 {
5687 double lat = getflt((unsigned char *)&mb(0));
5688 double lng = getflt((unsigned char *)&mb(4));
5689 double f = getflt((unsigned char *)&mb(12));
5690
5691 if (f > 0.0)
5692 t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm",
5693 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5694 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5695 getflt((unsigned char *)&mb(8)));
5696 else
5697 return;
5698 }
5699 break;
5700
5701 case CMD_RDOUBLEXYZ:
5702 {
5703 double x = getdbl((unsigned char *)&mb(0));
5704 double y = getdbl((unsigned char *)&mb(8));
5705 double z = getdbl((unsigned char *)&mb(16));
5706 t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm",
5707 x, y, z);
5708 }
5709 break;
5710
5711 case CMD_RDOUBLELLA:
5712 {
5713 double lat = getdbl((unsigned char *)&mb(0));
5714 double lng = getdbl((unsigned char *)&mb(8));
5715 t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm",
5716 ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'),
5717 ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'),
5718 getdbl((unsigned char *)&mb(16)));
5719 }
5720 break;
5721
5722 case CMD_RALLINVIEW:
5723 {
5724 int i, sats;
5725
5726 t = ap(pbuffer, sizeof(pbuffer), t, "mode: ");
5727 switch (mb(0) & 0x7)
5728 {
5729 default:
5730 t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7);
5731 break;
5732
5733 case 3:
5734 t = ap(pbuffer, sizeof(pbuffer), t, "2D");
5735 break;
5736
5737 case 4:
5738 t = ap(pbuffer, sizeof(pbuffer), t, "3D");
5739 break;
5740 }
5741 if (mb(0) & 0x8)
5742 t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, ");
5743 else
5744 t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, ");
5745
5746 sats = (mb(0)>>4) & 0xF;
5747
5748 t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ",
5749 getflt((unsigned char *)&mb(1)),
5750 getflt((unsigned char *)&mb(5)),
5751 getflt((unsigned char *)&mb(9)),
5752 getflt((unsigned char *)&mb(13)),
5753 sats, (sats == 1) ? "" : "s");
5754
5755 for (i=0; i < sats; i++)
5756 {
5757 t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i));
5758 if (tr)
5759 tr->ctrack |= (1 << (mb(17+i)-1));
5760 }
5761
5762 if (tr)
5763 { /* mark for tracking status query */
5764 tr->qtracking = 1;
5765 }
5766 }
5767 break;
5768
5769 case CMD_RSTATTRACK:
5770 {
5771 t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */
5772 if (getflt((unsigned char *)&mb(4)) < 0.0)
5773 {
5774 t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>");
5775 var_flag &= ~DEF;
5776 }
5777 else
5778 {
5779 t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f",
5780 (mb(1) & 0xFF)>>3,
5781 mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER",
5782 mb(3),
5783 getflt((unsigned char *)&mb(4)),
5784 getflt((unsigned char *)&mb(12)) * RTOD,
5785 getflt((unsigned char *)&mb(16)) * RTOD);
5786 if (mb(20))
5787 {
5788 var_flag &= ~DEF;
5789 t = ap(pbuffer, sizeof(pbuffer), t, ", OLD");
5790 }
5791 if (mb(22))
5792 {
5793 if (mb(22) == 1)
5794 t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY");
5795 else
5796 if (mb(22) == 2)
5797 t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH");
5798 }
5799 if (mb(23))
5800 t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data");
5801 }
5802 }
5803 break;
5804
5805 default:
5806 t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>");
5807 break;
5808 }
5809
5810 t = ap(pbuffer, sizeof(pbuffer), t,"\"");
5811 set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag);
5812 }
5813 }
5814
5815
5816 /**============================================================
5818 ** RAWDCF support
5819 **/
5820
5821 /*--------------------------------------------------
5822 * rawdcf_init_1 - set up modem lines for RAWDCF receivers
5823 * SET DTR line
5824 */
5825 #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
5826 static int
5827 rawdcf_init_1(
5828 struct parseunit *parse
5829 )
5830 {
5831 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp (at) bszh.de> */
5832 /*
5833 * You can use the RS232 to supply the power for a DCF77 receiver.
5834 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5835 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5836 */
5837 int sl232;
5838
5839 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5840 {
5841 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5842 return 0;
5843 }
5844
5845 #ifdef TIOCM_DTR
5846 sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5847 #else
5848 sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */
5849 #endif
5850
5851 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5852 {
5853 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer));
5854 }
5855 return 0;
5856 }
5857 #else
5858 static int
5859 rawdcfdtr_init_1(
5860 struct parseunit *parse
5861 )
5862 {
5863 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer));
5864 return 0;
5865 }
5866 #endif /* DTR initialisation type */
5867
5868 /*--------------------------------------------------
5869 * rawdcf_init_2 - set up modem lines for RAWDCF receivers
5870 * CLR DTR line, SET RTS line
5871 */
5872 #if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
5873 static int
5874 rawdcf_init_2(
5875 struct parseunit *parse
5876 )
5877 {
5878 /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp (at) bszh.de> */
5879 /*
5880 * You can use the RS232 to supply the power for a DCF77 receiver.
5881 * Here a voltage between the DTR and the RTS line is used. Unfortunately
5882 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
5883 */
5884 int sl232;
5885
5886 if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)
5887 {
5888 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5889 return 0;
5890 }
5891
5892 #ifdef TIOCM_RTS
5893 sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5894 #else
5895 sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */
5896 #endif
5897
5898 if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)
5899 {
5900 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer));
5901 }
5902 return 0;
5903 }
5904 #else
5905 static int
5906 rawdcf_init_2(
5907 struct parseunit *parse
5908 )
5909 {
5910 msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer));
5911 return 0;
5912 }
5913 #endif /* DTR initialisation type */
5914
5915 #else /* defined(REFCLOCK) && defined(PARSE) */
5916 NONEMPTY_TRANSLATION_UNIT
5917 #endif /* defined(REFCLOCK) && defined(PARSE) */
5918
5919 /*
5920 * History:
5921 *
5922 * refclock_parse.c,v
5923 * Revision 4.81 2009/05/01 10:15:29 kardel
5924 * use new refclock_ppsapi interface
5925 *
5926 * Revision 4.80 2007/08/11 12:06:29 kardel
5927 * update comments wrt/ to PPS
5928 *
5929 * Revision 4.79 2007/08/11 11:52:23 kardel
5930 * - terminate io bindings before io_closeclock() will close our file descriptor
5931 *
5932 * Revision 4.78 2006/12/22 20:08:27 kardel
5933 * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19
5934 *
5935 * Revision 4.77 2006/08/05 07:44:49 kardel
5936 * support optionally separate PPS devices via /dev/refclockpps-{0..3}
5937 *
5938 * Revision 4.76 2006/06/22 18:40:47 kardel
5939 * clean up signedness (gcc 4)
5940 *
5941 * Revision 4.75 2006/06/22 16:58:10 kardel
5942 * Bug #632: call parse_ppsapi() in parse_ctl() when updating
5943 * the PPS offset. Fix sign of offset passed to kernel.
5944 *
5945 * Revision 4.74 2006/06/18 21:18:37 kardel
5946 * NetBSD Coverity CID 3796: possible NULL deref
5947 *
5948 * Revision 4.73 2006/05/26 14:23:46 kardel
5949 * cleanup of copyright info
5950 *
5951 * Revision 4.72 2006/05/26 14:19:43 kardel
5952 * cleanup of ioctl cruft
5953 *
5954 * Revision 4.71 2006/05/26 14:15:57 kardel
5955 * delay adding refclock to async refclock io after all initializations
5956 *
5957 * Revision 4.70 2006/05/25 18:20:50 kardel
5958 * bug #619
5959 * terminate parse io engine after de-registering
5960 * from refclock io engine
5961 *
5962 * Revision 4.69 2006/05/25 17:28:02 kardel
5963 * complete refclock io structure initialization *before* inserting it into the
5964 * refclock input machine (avoids null pointer deref) (bug #619)
5965 *
5966 * Revision 4.68 2006/05/01 17:02:51 kardel
5967 * copy receiver method also for newlwy created receive buffers
5968 *
5969 * Revision 4.67 2006/05/01 14:37:29 kardel
5970 * If an input buffer parses into more than one message do insert the
5971 * parsed message in a new input buffer instead of processing it
5972 * directly. This avoids deed complicated processing in signal
5973 * handling.
5974 *
5975 * Revision 4.66 2006/03/18 00:45:30 kardel
5976 * coverity fixes found in NetBSD coverity scan
5977 *
5978 * Revision 4.65 2006/01/26 06:08:33 kardel
5979 * output errno on PPS setup failure
5980 *
5981 * Revision 4.64 2005/11/09 20:44:47 kardel
5982 * utilize full PPS timestamp resolution from PPS API
5983 *
5984 * Revision 4.63 2005/10/07 22:10:25 kardel
5985 * bounded buffer implementation
5986 *
5987 * Revision 4.62.2.2 2005/09/25 10:20:16 kardel
5988 * avoid unexpected buffer overflows due to sprintf("%f") on strange floats:
5989 * replace almost all str* and *printf functions be their buffer bounded
5990 * counterparts
5991 *
5992 * Revision 4.62.2.1 2005/08/27 16:19:27 kardel
5993 * limit re-set rate of trimble clocks
5994 *
5995 * Revision 4.62 2005/08/06 17:40:00 kardel
5996 * cleanup size handling wrt/ to buffer boundaries
5997 *
5998 * Revision 4.61 2005/07/27 21:16:19 kardel
5999 * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory
6000 * default setup. CSTOPB was missing for the 7E2 default data format of
6001 * the DCF77 clocks.
6002 *
6003 * Revision 4.60 2005/07/17 21:14:44 kardel
6004 * change contents of version string to include the RCS/CVS Id
6005 *
6006 * Revision 4.59 2005/07/06 06:56:38 kardel
6007 * syntax error
6008 *
6009 * Revision 4.58 2005/07/04 13:10:40 kardel
6010 * fix bug 455: tripping over NULL pointer on cleanup
6011 * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2
6012 * fix compiler warnings for some platforms wrt/ printf formatstrings and
6013 * varying structure element sizes
6014 * reorder assignment in binding to avoid tripping over NULL pointers
6015 *
6016 * Revision 4.57 2005/06/25 09:25:19 kardel
6017 * sort out log output sequence
6018 *
6019 * Revision 4.56 2005/06/14 21:47:27 kardel
6020 * collect samples only if samples are ok (sync or trusted flywheel)
6021 * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS
6022 * en- and dis-able HARDPPS in correlation to receiver sync state
6023 *
6024 * Revision 4.55 2005/06/02 21:28:31 kardel
6025 * clarify trust logic
6026 *
6027 * Revision 4.54 2005/06/02 17:06:49 kardel
6028 * change status reporting to use fixed refclock_report()
6029 *
6030 * Revision 4.53 2005/06/02 16:33:31 kardel
6031 * fix acceptance of clocks unsync clocks right at start
6032 *
6033 * Revision 4.52 2005/05/26 21:55:06 kardel
6034 * cleanup status reporting
6035 *
6036 * Revision 4.51 2005/05/26 19:19:14 kardel
6037 * implement fast refclock startup
6038 *
6039 * Revision 4.50 2005/04/16 20:51:35 kardel
6040 * set pps_enable = 1 when binding a kernel PPS source
6041 *
6042 * Revision 4.49 2005/04/16 17:29:26 kardel
6043 * add non polling clock type 18 for just listenning to Meinberg clocks
6044 *
6045 * Revision 4.48 2005/04/16 16:22:27 kardel
6046 * bk sync 20050415 ntp-dev
6047 *
6048 * Revision 4.47 2004/11/29 10:42:48 kardel
6049 * bk sync ntp-dev 20041129
6050 *
6051 * Revision 4.46 2004/11/29 10:26:29 kardel
6052 * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1
6053 *
6054 * Revision 4.45 2004/11/14 20:53:20 kardel
6055 * clear PPS flags after using them
6056 *
6057 * Revision 4.44 2004/11/14 15:29:41 kardel
6058 * support PPSAPI, upgrade Copyright to Berkeley style
6059 *
6060 * Revision 4.43 2001/05/26 22:53:16 kardel
6061 * 20010526 reconcilation
6062 *
6063 * Revision 4.42 2000/05/14 15:31:51 kardel
6064 * PPSAPI && RAWDCF modemline support
6065 *
6066 * Revision 4.41 2000/04/09 19:50:45 kardel
6067 * fixed rawdcfdtr_init() -> rawdcf_init_1
6068 *
6069 * Revision 4.40 2000/04/09 15:27:55 kardel
6070 * modem line fiddle in rawdcf_init_2
6071 *
6072 * Revision 4.39 2000/03/18 09:16:55 kardel
6073 * PPSAPI integration
6074 *
6075 * Revision 4.38 2000/03/05 20:25:06 kardel
6076 * support PPSAPI
6077 *
6078 * Revision 4.37 2000/03/05 20:11:14 kardel
6079 * 4.0.99g reconcilation
6080 *
6081 * Revision 4.36 1999/11/28 17:18:20 kardel
6082 * disabled burst mode
6083 *
6084 * Revision 4.35 1999/11/28 09:14:14 kardel
6085 * RECON_4_0_98F
6086 *
6087 * Revision 4.34 1999/05/14 06:08:05 kardel
6088 * store current_time in a suitable container (u_long)
6089 *
6090 * Revision 4.33 1999/05/13 21:48:38 kardel
6091 * double the no response timeout interval
6092 *
6093 * Revision 4.32 1999/05/13 20:09:13 kardel
6094 * complain only about missing polls after a full poll interval
6095 *
6096 * Revision 4.31 1999/05/13 19:59:32 kardel
6097 * add clock type 16 for RTS set DTR clr in RAWDCF
6098 *
6099 * Revision 4.30 1999/02/28 20:36:43 kardel
6100 * fixed printf fmt
6101 *
6102 * Revision 4.29 1999/02/28 19:58:23 kardel
6103 * updated copyright information
6104 *
6105 * Revision 4.28 1999/02/28 19:01:50 kardel
6106 * improved debug out on sent Meinberg messages
6107 *
6108 * Revision 4.27 1999/02/28 18:05:55 kardel
6109 * no linux/ppsclock.h stuff
6110 *
6111 * Revision 4.26 1999/02/28 15:27:27 kardel
6112 * wharton clock integration
6113 *
6114 * Revision 4.25 1999/02/28 14:04:46 kardel
6115 * added missing double quotes to UTC information string
6116 *
6117 * Revision 4.24 1999/02/28 12:06:50 kardel
6118 * (parse_control): using gmprettydate instead of prettydate()
6119 * (mk_utcinfo): new function for formatting GPS derived UTC information
6120 * (gps16x_message): changed to use mk_utcinfo()
6121 * (trimbletsip_message): changed to use mk_utcinfo()
6122 * ignoring position information in unsynchronized mode
6123 * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY
6124 *
6125 * Revision 4.23 1999/02/23 19:47:53 kardel
6126 * fixed #endifs
6127 * (stream_receive): fixed formats
6128 *
6129 * Revision 4.22 1999/02/22 06:21:02 kardel
6130 * use new autoconfig symbols
6131 *
6132 * Revision 4.21 1999/02/21 12:18:13 kardel
6133 * 4.91f reconcilation
6134 *
6135 * Revision 4.20 1999/02/21 10:53:36 kardel
6136 * initial Linux PPSkit version
6137 *
6138 * Revision 4.19 1999/02/07 09:10:45 kardel
6139 * clarify STREAMS mitigation rules in comment
6140 *
6141 * Revision 4.18 1998/12/20 23:45:34 kardel
6142 * fix types and warnings
6143 *
6144 * Revision 4.17 1998/11/15 21:24:51 kardel
6145 * cannot access mbg_ routines when CLOCK_MEINBERG
6146 * is not defined
6147 *
6148 * Revision 4.16 1998/11/15 20:28:17 kardel
6149 * Release 4.0.73e13 reconcilation
6150 *
6151 * Revision 4.15 1998/08/22 21:56:08 kardel
6152 * fixed IO handling for non-STREAM IO
6153 *
6154 * Revision 4.14 1998/08/16 19:00:48 kardel
6155 * (gps16x_message): reduced UTC parameter information (dropped A0,A1)
6156 * made uval a local variable (killed one of the last globals)
6157 * (sendetx): added logging of messages when in debug mode
6158 * (trimble_check): added periodic checks to facilitate re-initialization
6159 * (trimbletsip_init): made use of EOL character if in non-kernel operation
6160 * (trimbletsip_message): extended message interpretation
6161 * (getdbl): fixed data conversion
6162 *
6163 * Revision 4.13 1998/08/09 22:29:13 kardel
6164 * Trimble TSIP support
6165 *
6166 * Revision 4.12 1998/07/11 10:05:34 kardel
6167 * Release 4.0.73d reconcilation
6168 *
6169 * Revision 4.11 1998/06/14 21:09:42 kardel
6170 * Sun acc cleanup
6171 *
6172 * Revision 4.10 1998/06/13 12:36:45 kardel
6173 * signed/unsigned, name clashes
6174 *
6175 * Revision 4.9 1998/06/12 15:30:00 kardel
6176 * prototype fixes
6177 *
6178 * Revision 4.8 1998/06/12 11:19:42 kardel
6179 * added direct input processing routine for refclocks in
6180 * order to avaiod that single character io gobbles up all
6181 * receive buffers and drops input data. (Problem started
6182 * with fast machines so a character a buffer was possible
6183 * one of the few cases where faster machines break existing
6184 * allocation algorithms)
6185 *
6186 * Revision 4.7 1998/06/06 18:35:20 kardel
6187 * (parse_start): added BURST mode initialisation
6188 *
6189 * Revision 4.6 1998/05/27 06:12:46 kardel
6190 * RAWDCF_BASEDELAY default added
6191 * old comment removed
6192 * casts for ioctl()
6193 *
6194 * Revision 4.5 1998/05/25 22:05:09 kardel
6195 * RAWDCF_SETDTR option removed
6196 * clock type 14 attempts to set DTR for
6197 * power supply of RAWDCF receivers
6198 *
6199 * Revision 4.4 1998/05/24 16:20:47 kardel
6200 * updated comments referencing Meinberg clocks
6201 * added RAWDCF clock with DTR set option as type 14
6202 *
6203 * Revision 4.3 1998/05/24 10:48:33 kardel
6204 * calibrated CONRAD RAWDCF default fudge factor
6205 *
6206 * Revision 4.2 1998/05/24 09:59:35 kardel
6207 * corrected version information (ntpq support)
6208 *
6209 * Revision 4.1 1998/05/24 09:52:31 kardel
6210 * use fixed format only (new IO model)
6211 * output debug to stdout instead of msyslog()
6212 * don't include >"< in ASCII output in order not to confuse
6213 * ntpq parsing
6214 *
6215 * Revision 4.0 1998/04/10 19:52:11 kardel
6216 * Start 4.0 release version numbering
6217 *
6218 * Revision 1.2 1998/04/10 19:28:04 kardel
6219 * initial NTP VERSION 4 integration of PARSE with GPS166 binary support
6220 * derived from 3.105.1.2 from V3 tree
6221 *
6222 * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel
6223 *
6224 */
6225