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