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