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