Annotation of embedaddon/ntp/ntpd/refclock_parse.c, revision 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>