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