154359Sroberto/* 2285612Sdelphij * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 354359Sroberto * 4285612Sdelphij * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 554359Sroberto * 6182007Sroberto * generic reference clock driver for several DCF/GPS/MSF/... receivers 754359Sroberto * 8182007Sroberto * PPS notes: 9182007Sroberto * On systems that support PPSAPI (RFC2783) PPSAPI is the 10182007Sroberto * preferred interface. 1154359Sroberto * 12182007Sroberto * Optionally make use of a STREAMS module for input processing where 13182007Sroberto * available and configured. This STREAMS module reduces the time 14182007Sroberto * stamp latency for serial and PPS events. 15182007Sroberto * Currently the STREAMS module is only available for Suns running 16182007Sroberto * SunOS 4.x and SunOS5.x. 1754359Sroberto * 18285612Sdelphij * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org> 19285612Sdelphij * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany 2054359Sroberto * 21182007Sroberto * Redistribution and use in source and binary forms, with or without 22182007Sroberto * modification, are permitted provided that the following conditions 23182007Sroberto * are met: 24182007Sroberto * 1. Redistributions of source code must retain the above copyright 25182007Sroberto * notice, this list of conditions and the following disclaimer. 26182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright 27182007Sroberto * notice, this list of conditions and the following disclaimer in the 28182007Sroberto * documentation and/or other materials provided with the distribution. 29182007Sroberto * 3. Neither the name of the author nor the names of its contributors 30182007Sroberto * may be used to endorse or promote products derived from this software 31182007Sroberto * without specific prior written permission. 3254359Sroberto * 33182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 34182007Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35182007Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36182007Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 37182007Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38182007Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39182007Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40182007Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41182007Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42182007Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43182007Sroberto * SUCH DAMAGE. 4454359Sroberto * 4554359Sroberto */ 4654359Sroberto 4754359Sroberto#ifdef HAVE_CONFIG_H 48182007Sroberto# include "config.h" 4954359Sroberto#endif 5054359Sroberto 51285612Sdelphij#include "ntp_types.h" 52285612Sdelphij 5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) 5454359Sroberto 5554359Sroberto/* 5654359Sroberto * This driver currently provides the support for 57285612Sdelphij * - Meinberg receiver DCF77 PZF535 (TCXO version) (DCF) 58285612Sdelphij * - Meinberg receiver DCF77 PZF535 (OCXO version) (DCF) 59285612Sdelphij * - Meinberg receiver DCF77 PZF509 (DCF) 6054359Sroberto * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) 6154359Sroberto * - IGEL CLOCK (DCF) 6254359Sroberto * - ELV DCF7000 (DCF) 6354359Sroberto * - Schmid clock (DCF) 6454359Sroberto * - Conrad DCF77 receiver module (DCF) 6554359Sroberto * - FAU DCF77 NTP receiver (TimeBrick) (DCF) 66285612Sdelphij * - WHARTON 400A Series clock (DCF) 6754359Sroberto * 68285612Sdelphij * - Meinberg GPS receivers (GPS) 6954359Sroberto * - Trimble (TSIP and TAIP protocol) (GPS) 7054359Sroberto * 7154359Sroberto * - RCC8000 MSF Receiver (MSF) 72285612Sdelphij * - VARITEXT clock (MSF) 7354359Sroberto */ 7454359Sroberto 7554359Sroberto/* 7654359Sroberto * Meinberg receivers are usually connected via a 77285612Sdelphij * 9600/7E1 or 19200/8N1 serial line. 7854359Sroberto * 7954359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp 8054359Sroberto * format. The firmware release is Uni-Erlangen. 8154359Sroberto * 8254359Sroberto * Meinberg generic receiver setup: 83285612Sdelphij * output time code every second 84285612Sdelphij * Baud rate 9600 7E2S 8554359Sroberto * 86285612Sdelphij * Meinberg GPS receiver setup: 8754359Sroberto * output time code every second 8854359Sroberto * Baudrate 19200 8N1 8954359Sroberto * 9054359Sroberto * This software supports the standard data formats used 9154359Sroberto * in Meinberg receivers. 9254359Sroberto * 9354359Sroberto * Special software versions are only sensible for the 94285612Sdelphij * oldest GPS receiver, GPS16x. For newer receiver types 95285612Sdelphij * the output string format can be configured at the device, 96285612Sdelphij * and the device name is generally GPSxxx instead of GPS16x. 9754359Sroberto * 9854359Sroberto * Meinberg can be reached via: http://www.meinberg.de/ 9954359Sroberto */ 10054359Sroberto 10154359Sroberto#include "ntpd.h" 10254359Sroberto#include "ntp_refclock.h" 103285612Sdelphij#include "timevalops.h" /* includes <sys/time.h> */ 10454359Sroberto#include "ntp_control.h" 105182007Sroberto#include "ntp_string.h" 10654359Sroberto 10754359Sroberto#include <stdio.h> 10854359Sroberto#include <ctype.h> 10954359Sroberto#ifndef TM_IN_SYS_TIME 11054359Sroberto# include <time.h> 11154359Sroberto#endif 11254359Sroberto 113182007Sroberto#ifdef HAVE_UNISTD_H 114182007Sroberto# include <unistd.h> 115182007Sroberto#endif 116182007Sroberto 11754359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) 11854359Sroberto# include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" 11954359Sroberto#endif 12054359Sroberto 12154359Sroberto#ifdef STREAM 12254359Sroberto# include <sys/stream.h> 12354359Sroberto# include <sys/stropts.h> 12454359Sroberto#endif 12554359Sroberto 12654359Sroberto#ifdef HAVE_TERMIOS 127285612Sdelphij# include <termios.h> 12854359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 12954359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 13054359Sroberto# undef HAVE_SYSV_TTYS 13154359Sroberto#endif 13254359Sroberto 13354359Sroberto#ifdef HAVE_SYSV_TTYS 13454359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) 13554359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) 13654359Sroberto#endif 13754359Sroberto 13854359Sroberto#ifdef HAVE_BSD_TTYS 13954359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */ 14054359Sroberto# include "Bletch: BSD TTY not currently supported" 14154359Sroberto#endif 14254359Sroberto 14354359Sroberto#ifdef HAVE_SYS_IOCTL_H 14454359Sroberto# include <sys/ioctl.h> 14554359Sroberto#endif 14654359Sroberto 147182007Sroberto#ifdef HAVE_PPSAPI 148182007Sroberto# include "ppsapi_timepps.h" 149285612Sdelphij# include "refclock_atom.h" 150182007Sroberto#endif 151182007Sroberto 15254359Sroberto#ifdef PPS 153182007Sroberto# ifdef HAVE_SYS_PPSCLOCK_H 154182007Sroberto# include <sys/ppsclock.h> 155182007Sroberto# endif 156182007Sroberto# ifdef HAVE_TIO_SERIAL_STUFF 157182007Sroberto# include <linux/serial.h> 158182007Sroberto# endif 15954359Sroberto#endif 160182007Sroberto 161285612Sdelphij# define BUFFER_SIZE(_BUF, _PTR) ((int)((_BUF) + sizeof(_BUF) - (_PTR))) 162285612Sdelphij# define BUFFER_SIZES(_BUF, _PTR, _SZ) ((int)((_BUF) + (_SZ) - (_PTR))) 163182007Sroberto 164182007Sroberto/* 165182007Sroberto * document type of PPS interfacing - copy of ifdef mechanism in local_input() 166182007Sroberto */ 167285612Sdelphij#undef PPS_METHOD 168182007Sroberto 169182007Sroberto#ifdef HAVE_PPSAPI 170182007Sroberto#define PPS_METHOD "PPS API" 171182007Sroberto#else 172182007Sroberto#ifdef TIOCDCDTIMESTAMP 173182007Sroberto#define PPS_METHOD "TIOCDCDTIMESTAMP" 174182007Sroberto#else /* TIOCDCDTIMESTAMP */ 175182007Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 176182007Sroberto#ifdef HAVE_CIOGETEV 177182007Sroberto#define PPS_METHOD "CIOGETEV" 17854359Sroberto#endif 179182007Sroberto#ifdef HAVE_TIOCGPPSEV 180182007Sroberto#define PPS_METHOD "TIOCGPPSEV" 18154359Sroberto#endif 182182007Sroberto#endif 183182007Sroberto#endif /* TIOCDCDTIMESTAMP */ 184182007Sroberto#endif /* HAVE_PPSAPI */ 18554359Sroberto 186285612Sdelphij/* 187285612Sdelphij * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF 188285612Sdelphij * then some more parse-specific variables are flagged to be printed with 189285612Sdelphij * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF 190285612Sdelphij * should be defined as 0. 191285612Sdelphij */ 192285612Sdelphij#if 0 193285612Sdelphij# define COND_DEF DEF // enable this for testing 194285612Sdelphij#else 195285612Sdelphij# define COND_DEF 0 // enable this by default 196285612Sdelphij#endif 197285612Sdelphij 19854359Sroberto#include "ntp_io.h" 19954359Sroberto#include "ntp_stdlib.h" 20054359Sroberto 20154359Sroberto#include "parse.h" 20254359Sroberto#include "mbg_gps166.h" 20354359Sroberto#include "trimble.h" 20454359Sroberto#include "binio.h" 20554359Sroberto#include "ascii.h" 20654359Sroberto#include "ieee754io.h" 207182007Sroberto#include "recvbuff.h" 20854359Sroberto 209285612Sdelphijstatic char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST"; 21054359Sroberto 21154359Sroberto/**=========================================================================== 21254359Sroberto ** external interface to ntp mechanism 21354359Sroberto **/ 21454359Sroberto 215285612Sdelphijstatic int parse_start (int, struct peer *); 216285612Sdelphijstatic void parse_shutdown (int, struct peer *); 217285612Sdelphijstatic void parse_poll (int, struct peer *); 218285612Sdelphijstatic void parse_control (int, const struct refclockstat *, struct refclockstat *, struct peer *); 21954359Sroberto 22054359Srobertostruct refclock refclock_parse = { 22154359Sroberto parse_start, 22254359Sroberto parse_shutdown, 22354359Sroberto parse_poll, 22454359Sroberto parse_control, 225182007Sroberto noentry, 226182007Sroberto noentry, 22754359Sroberto NOFLAGS 22854359Sroberto}; 22954359Sroberto 23054359Sroberto/* 23154359Sroberto * Definitions 23254359Sroberto */ 23354359Sroberto#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ 23454359Sroberto#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ 235182007Sroberto#define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */ 23654359Sroberto 23754359Sroberto#undef ABS 23854359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) 23954359Sroberto 240182007Sroberto#define PARSE_HARDPPS_DISABLE 0 241182007Sroberto#define PARSE_HARDPPS_ENABLE 1 242182007Sroberto 24354359Sroberto/**=========================================================================== 24454359Sroberto ** function vector for dynamically binding io handling mechanism 24554359Sroberto **/ 24654359Sroberto 24754359Srobertostruct parseunit; /* to keep inquiring minds happy */ 24854359Sroberto 24954359Srobertotypedef struct bind 25054359Sroberto{ 25154359Sroberto const char *bd_description; /* name of type of binding */ 252285612Sdelphij int (*bd_init) (struct parseunit *); /* initialize */ 253285612Sdelphij void (*bd_end) (struct parseunit *); /* end */ 254285612Sdelphij int (*bd_setcs) (struct parseunit *, parsectl_t *); /* set character size */ 255285612Sdelphij int (*bd_disable) (struct parseunit *); /* disable */ 256285612Sdelphij int (*bd_enable) (struct parseunit *); /* enable */ 257285612Sdelphij int (*bd_getfmt) (struct parseunit *, parsectl_t *); /* get format */ 258285612Sdelphij int (*bd_setfmt) (struct parseunit *, parsectl_t *); /* setfmt */ 259285612Sdelphij int (*bd_timecode) (struct parseunit *, parsectl_t *); /* get time code */ 260285612Sdelphij void (*bd_receive) (struct recvbuf *); /* receive operation */ 261285612Sdelphij int (*bd_io_input) (struct recvbuf *); /* input operation */ 26254359Sroberto} bind_t; 26354359Sroberto 26454359Sroberto#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) 26554359Sroberto#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) 26654359Sroberto#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) 26754359Sroberto#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) 26854359Sroberto#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) 26954359Sroberto#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) 27054359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) 27154359Sroberto 27254359Sroberto/* 273285612Sdelphij * special handling flags 27454359Sroberto */ 275285612Sdelphij#define PARSE_F_PPSONSECOND 0x00000001 /* PPS pulses are on second */ 276285612Sdelphij#define PARSE_F_POWERUPTRUST 0x00000100 /* POWERUP state ist trusted for */ 277285612Sdelphij /* trusttime after SYNC was seen */ 27854359Sroberto/**=========================================================================== 27954359Sroberto ** error message regression handling 28054359Sroberto ** 28154359Sroberto ** there are quite a few errors that can occur in rapid succession such as 28254359Sroberto ** noisy input data or no data at all. in order to reduce the amount of 28354359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit 28454359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a 28554359Sroberto ** configurable number of messages is displayed that way, we move on to the 28654359Sroberto ** next time unit / count for that class. a count of messages that have been 28754359Sroberto ** suppressed is held and displayed whenever a corresponding message is 28854359Sroberto ** displayed. the time units for a message class will also be displayed. 28954359Sroberto ** whenever an error condition clears we reset the error message state, 29054359Sroberto ** thus we would still generate much output on pathological conditions 29154359Sroberto ** where the system oscillates between OK and NOT OK states. coping 29254359Sroberto ** with that condition is currently considered too complicated. 29354359Sroberto **/ 29454359Sroberto 29554359Sroberto#define ERR_ALL (unsigned)~0 /* "all" errors */ 29654359Sroberto#define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ 29754359Sroberto#define ERR_NODATA (unsigned)1 /* no input data */ 29854359Sroberto#define ERR_BADIO (unsigned)2 /* read/write/select errors */ 29954359Sroberto#define ERR_BADSTATUS (unsigned)3 /* unsync states */ 30054359Sroberto#define ERR_BADEVENT (unsigned)4 /* non nominal events */ 30154359Sroberto#define ERR_INTERNAL (unsigned)5 /* internal error */ 30254359Sroberto#define ERR_CNT (unsigned)(ERR_INTERNAL+1) 30354359Sroberto 30454359Sroberto#define ERR(_X_) if (list_err(parse, (_X_))) 30554359Sroberto 30654359Srobertostruct errorregression 30754359Sroberto{ 30854359Sroberto u_long err_count; /* number of repititions per class */ 30954359Sroberto u_long err_delay; /* minimum delay between messages */ 31054359Sroberto}; 31154359Sroberto 31254359Srobertostatic struct errorregression 31354359Srobertoerr_baddata[] = /* error messages for bad input data */ 31454359Sroberto{ 31554359Sroberto { 1, 0 }, /* output first message immediately */ 31654359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 31754359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 31854359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 31954359Sroberto}; 32054359Sroberto 32154359Srobertostatic struct errorregression 32254359Srobertoerr_nodata[] = /* error messages for missing input data */ 32354359Sroberto{ 32454359Sroberto { 1, 0 }, /* output first message immediately */ 32554359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 32654359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 32754359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 32854359Sroberto}; 32954359Sroberto 33054359Srobertostatic struct errorregression 33154359Srobertoerr_badstatus[] = /* unsynchronized state messages */ 33254359Sroberto{ 33354359Sroberto { 1, 0 }, /* output first message immediately */ 33454359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 33554359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 33654359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 33754359Sroberto}; 33854359Sroberto 33954359Srobertostatic struct errorregression 34054359Srobertoerr_badio[] = /* io failures (bad reads, selects, ...) */ 34154359Sroberto{ 34254359Sroberto { 1, 0 }, /* output first message immediately */ 34354359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 34454359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 34554359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 34654359Sroberto}; 34754359Sroberto 34854359Srobertostatic struct errorregression 34954359Srobertoerr_badevent[] = /* non nominal events */ 35054359Sroberto{ 35154359Sroberto { 20, 0 }, /* output first message immediately */ 35254359Sroberto { 6, 60 }, /* output next five messages in 60 second intervals */ 35354359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 35454359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 35554359Sroberto}; 35654359Sroberto 35754359Srobertostatic struct errorregression 35854359Srobertoerr_internal[] = /* really bad things - basically coding/OS errors */ 35954359Sroberto{ 36054359Sroberto { 0, 0 }, /* output all messages immediately */ 36154359Sroberto}; 36254359Sroberto 36354359Srobertostatic struct errorregression * 36454359Srobertoerr_tbl[] = 36554359Sroberto{ 36654359Sroberto err_baddata, 36754359Sroberto err_nodata, 36854359Sroberto err_badio, 36954359Sroberto err_badstatus, 37054359Sroberto err_badevent, 37154359Sroberto err_internal 37254359Sroberto}; 37354359Sroberto 37454359Srobertostruct errorinfo 37554359Sroberto{ 37654359Sroberto u_long err_started; /* begin time (ntp) of error condition */ 37754359Sroberto u_long err_last; /* last time (ntp) error occurred */ 37854359Sroberto u_long err_cnt; /* number of error repititions */ 37954359Sroberto u_long err_suppressed; /* number of suppressed messages */ 38054359Sroberto struct errorregression *err_stage; /* current error stage */ 38154359Sroberto}; 38254359Sroberto 38354359Sroberto/**=========================================================================== 38454359Sroberto ** refclock instance data 38554359Sroberto **/ 38654359Sroberto 38754359Srobertostruct parseunit 38854359Sroberto{ 38954359Sroberto /* 39054359Sroberto * NTP management 39154359Sroberto */ 39254359Sroberto struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ 39354359Sroberto struct refclockproc *generic; /* backlink to refclockproc structure */ 39454359Sroberto 39554359Sroberto /* 39654359Sroberto * PARSE io 39754359Sroberto */ 39854359Sroberto bind_t *binding; /* io handling binding */ 399285612Sdelphij 40054359Sroberto /* 40154359Sroberto * parse state 40254359Sroberto */ 40354359Sroberto parse_t parseio; /* io handling structure (user level parsing) */ 40454359Sroberto 40554359Sroberto /* 40654359Sroberto * type specific parameters 40754359Sroberto */ 40854359Sroberto struct parse_clockinfo *parse_type; /* link to clock description */ 40954359Sroberto 41054359Sroberto /* 41154359Sroberto * clock state handling/reporting 41254359Sroberto */ 41354359Sroberto u_char flags; /* flags (leap_control) */ 41454359Sroberto u_long lastchange; /* time (ntp) when last state change accured */ 41554359Sroberto u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ 41656746Sroberto u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */ 41754359Sroberto u_short lastformat; /* last format used */ 41854359Sroberto u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ 419182007Sroberto u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */ 420182007Sroberto double ppsphaseadjust; /* phase adjustment of PPS time stamp */ 421182007Sroberto u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ 42254359Sroberto u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ 423182007Sroberto int ppsfd; /* fd to ise for PPS io */ 424182007Sroberto#ifdef HAVE_PPSAPI 425182007Sroberto int hardppsstate; /* current hard pps state */ 426285612Sdelphij struct refclock_atom atom; /* PPSAPI structure */ 427182007Sroberto#endif 428182007Sroberto parsetime_t timedata; /* last (parse module) data */ 42954359Sroberto void *localdata; /* optional local, receiver-specific data */ 43054359Sroberto unsigned long localstate; /* private local state */ 43154359Sroberto struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ 43254359Sroberto struct ctl_var *kv; /* additional pseudo variables */ 43354359Sroberto u_long laststatistic; /* time when staticstics where output */ 43454359Sroberto}; 43554359Sroberto 43654359Sroberto 43754359Sroberto/**=========================================================================== 43854359Sroberto ** Clockinfo section all parameter for specific clock types 43954359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters 44054359Sroberto **/ 44154359Sroberto 442285612Sdelphijstatic void poll_dpoll (struct parseunit *); 443285612Sdelphijstatic void poll_poll (struct peer *); 444285612Sdelphijstatic int poll_init (struct parseunit *); 44554359Sroberto 44654359Srobertotypedef struct poll_info 44754359Sroberto{ 44854359Sroberto u_long rate; /* poll rate - once every "rate" seconds - 0 off */ 44954359Sroberto const char *string; /* string to send for polling */ 45054359Sroberto u_long count; /* number of characters in string */ 45154359Sroberto} poll_info_t; 45254359Sroberto 45354359Sroberto#define NO_CL_FLAGS 0 45454359Sroberto#define NO_POLL 0 45554359Sroberto#define NO_INIT 0 45654359Sroberto#define NO_END 0 45754359Sroberto#define NO_EVENT 0 458182007Sroberto#define NO_LCLDATA 0 45954359Sroberto#define NO_MESSAGE 0 46054359Sroberto#define NO_PPSDELAY 0 46154359Sroberto 46254359Sroberto#define DCF_ID "DCF" /* generic DCF */ 46354359Sroberto#define DCF_A_ID "DCFa" /* AM demodulation */ 46454359Sroberto#define DCF_P_ID "DCFp" /* psuedo random phase shift */ 46554359Sroberto#define GPS_ID "GPS" /* GPS receiver */ 46654359Sroberto 467285612Sdelphij#define NOCLOCK_ROOTDELAY 0.0 468285612Sdelphij#define NOCLOCK_BASEDELAY 0.0 469285612Sdelphij#define NOCLOCK_DESCRIPTION 0 47054359Sroberto#define NOCLOCK_MAXUNSYNC 0 47154359Sroberto#define NOCLOCK_CFLAG 0 47254359Sroberto#define NOCLOCK_IFLAG 0 47354359Sroberto#define NOCLOCK_OFLAG 0 47454359Sroberto#define NOCLOCK_LFLAG 0 475285612Sdelphij#define NOCLOCK_ID "TILT" 476285612Sdelphij#define NOCLOCK_POLL NO_POLL 477285612Sdelphij#define NOCLOCK_INIT NO_INIT 478285612Sdelphij#define NOCLOCK_END NO_END 479285612Sdelphij#define NOCLOCK_DATA NO_LCLDATA 480285612Sdelphij#define NOCLOCK_FORMAT "" 481285612Sdelphij#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 482285612Sdelphij#define NOCLOCK_SAMPLES 0 483285612Sdelphij#define NOCLOCK_KEEP 0 48454359Sroberto 48554359Sroberto#define DCF_TYPE CTL_SST_TS_LF 48654359Sroberto#define GPS_TYPE CTL_SST_TS_UHF 48754359Sroberto 48854359Sroberto/* 48954359Sroberto * receiver specific constants 49054359Sroberto */ 49154359Sroberto#define MBG_SPEED (B9600) 492182007Sroberto#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB) 49354359Sroberto#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) 49454359Sroberto#define MBG_OFLAG 0 49554359Sroberto#define MBG_LFLAG 0 49654359Sroberto#define MBG_FLAGS PARSE_F_PPSONSECOND 49754359Sroberto 49854359Sroberto/* 49954359Sroberto * Meinberg DCF77 receivers 50054359Sroberto */ 50154359Sroberto#define DCFUA31_ROOTDELAY 0.0 /* 0 */ 50254359Sroberto#define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ 50354359Sroberto#define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" 50454359Sroberto#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ 50554359Sroberto#define DCFUA31_SPEED MBG_SPEED 50654359Sroberto#define DCFUA31_CFLAG MBG_CFLAG 50754359Sroberto#define DCFUA31_IFLAG MBG_IFLAG 50854359Sroberto#define DCFUA31_OFLAG MBG_OFLAG 50954359Sroberto#define DCFUA31_LFLAG MBG_LFLAG 51054359Sroberto#define DCFUA31_SAMPLES 5 51154359Sroberto#define DCFUA31_KEEP 3 51254359Sroberto#define DCFUA31_FORMAT "Meinberg Standard" 51354359Sroberto 51454359Sroberto/* 51554359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver 51654359Sroberto */ 51754359Sroberto#define DCFPZF535_ROOTDELAY 0.0 51854359Sroberto#define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 51954359Sroberto#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" 52054359Sroberto#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours 52154359Sroberto * @ 5e-8df/f we have accumulated 52254359Sroberto * at most 2.16 ms (thus we move to 52354359Sroberto * NTP synchronisation */ 52454359Sroberto#define DCFPZF535_SPEED MBG_SPEED 52554359Sroberto#define DCFPZF535_CFLAG MBG_CFLAG 52654359Sroberto#define DCFPZF535_IFLAG MBG_IFLAG 52754359Sroberto#define DCFPZF535_OFLAG MBG_OFLAG 52854359Sroberto#define DCFPZF535_LFLAG MBG_LFLAG 52954359Sroberto#define DCFPZF535_SAMPLES 5 53054359Sroberto#define DCFPZF535_KEEP 3 53154359Sroberto#define DCFPZF535_FORMAT "Meinberg Standard" 53254359Sroberto 53354359Sroberto/* 53454359Sroberto * Meinberg DCF PZF535/OCXO receiver 53554359Sroberto */ 53654359Sroberto#define DCFPZF535OCXO_ROOTDELAY 0.0 53754359Sroberto#define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 53854359Sroberto#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" 53954359Sroberto#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 54054359Sroberto * @ 5e-9df/f we have accumulated 54154359Sroberto * at most an error of 1.73 ms 54254359Sroberto * (thus we move to NTP synchronisation) */ 54354359Sroberto#define DCFPZF535OCXO_SPEED MBG_SPEED 54454359Sroberto#define DCFPZF535OCXO_CFLAG MBG_CFLAG 54554359Sroberto#define DCFPZF535OCXO_IFLAG MBG_IFLAG 54654359Sroberto#define DCFPZF535OCXO_OFLAG MBG_OFLAG 54754359Sroberto#define DCFPZF535OCXO_LFLAG MBG_LFLAG 54854359Sroberto#define DCFPZF535OCXO_SAMPLES 5 54954359Sroberto#define DCFPZF535OCXO_KEEP 3 55054359Sroberto#define DCFPZF535OCXO_FORMAT "Meinberg Standard" 55154359Sroberto 55254359Sroberto/* 553285612Sdelphij * Meinberg GPS receivers 55454359Sroberto */ 555285612Sdelphijstatic void gps16x_message (struct parseunit *, parsetime_t *); 556285612Sdelphijstatic int gps16x_poll_init (struct parseunit *); 55754359Sroberto 55854359Sroberto#define GPS16X_ROOTDELAY 0.0 /* nothing here */ 55954359Sroberto#define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 560285612Sdelphij#define GPS16X_DESCRIPTION "Meinberg GPS receiver" 56154359Sroberto#define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 56254359Sroberto * @ 5e-9df/f we have accumulated 56354359Sroberto * at most an error of 1.73 ms 56454359Sroberto * (thus we move to NTP synchronisation) */ 56554359Sroberto#define GPS16X_SPEED B19200 56654359Sroberto#define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) 56754359Sroberto#define GPS16X_IFLAG (IGNBRK|IGNPAR) 56854359Sroberto#define GPS16X_OFLAG MBG_OFLAG 56954359Sroberto#define GPS16X_LFLAG MBG_LFLAG 57054359Sroberto#define GPS16X_POLLRATE 6 57154359Sroberto#define GPS16X_POLLCMD "" 57254359Sroberto#define GPS16X_CMDSIZE 0 57354359Sroberto 57454359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; 57554359Sroberto 57654359Sroberto#define GPS16X_INIT gps16x_poll_init 57754359Sroberto#define GPS16X_POLL 0 57854359Sroberto#define GPS16X_END 0 57954359Sroberto#define GPS16X_DATA ((void *)(&gps16x_pollinfo)) 58054359Sroberto#define GPS16X_MESSAGE gps16x_message 58154359Sroberto#define GPS16X_ID GPS_ID 58254359Sroberto#define GPS16X_FORMAT "Meinberg GPS Extended" 58354359Sroberto#define GPS16X_SAMPLES 5 58454359Sroberto#define GPS16X_KEEP 3 58554359Sroberto 58654359Sroberto/* 58754359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) 58854359Sroberto * 58954359Sroberto * This is really not the hottest clock - but before you have nothing ... 59054359Sroberto */ 59154359Sroberto#define DCF7000_ROOTDELAY 0.0 /* 0 */ 59254359Sroberto#define DCF7000_BASEDELAY 0.405 /* slow blow */ 59354359Sroberto#define DCF7000_DESCRIPTION "ELV DCF7000" 59454359Sroberto#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ 59554359Sroberto#define DCF7000_SPEED (B9600) 59654359Sroberto#define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) 59754359Sroberto#define DCF7000_IFLAG (IGNBRK) 59854359Sroberto#define DCF7000_OFLAG 0 59954359Sroberto#define DCF7000_LFLAG 0 60054359Sroberto#define DCF7000_SAMPLES 5 60154359Sroberto#define DCF7000_KEEP 3 60254359Sroberto#define DCF7000_FORMAT "ELV DCF7000" 60354359Sroberto 60454359Sroberto/* 60554359Sroberto * Schmid DCF Receiver Kit 60654359Sroberto * 60754359Sroberto * When the WSDCF clock is operating optimally we want the primary clock 60854359Sroberto * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer 60954359Sroberto * structure is set to 290 ms and we compute delays which are at least 61054359Sroberto * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format 61154359Sroberto */ 61254359Sroberto#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ 61354359Sroberto#define WS_POLLCMD "\163" 61454359Sroberto#define WS_CMDSIZE 1 61554359Sroberto 61654359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; 61754359Sroberto 61854359Sroberto#define WSDCF_INIT poll_init 61954359Sroberto#define WSDCF_POLL poll_dpoll 62054359Sroberto#define WSDCF_END 0 62154359Sroberto#define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) 62254359Sroberto#define WSDCF_ROOTDELAY 0.0 /* 0 */ 62354359Sroberto#define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ 62454359Sroberto#define WSDCF_DESCRIPTION "WS/DCF Receiver" 62554359Sroberto#define WSDCF_FORMAT "Schmid" 62654359Sroberto#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ 62754359Sroberto#define WSDCF_SPEED (B1200) 62854359Sroberto#define WSDCF_CFLAG (CS8|CREAD|CLOCAL) 62954359Sroberto#define WSDCF_IFLAG 0 63054359Sroberto#define WSDCF_OFLAG 0 63154359Sroberto#define WSDCF_LFLAG 0 63254359Sroberto#define WSDCF_SAMPLES 5 63354359Sroberto#define WSDCF_KEEP 3 63454359Sroberto 63554359Sroberto/* 63654359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants 63754359Sroberto */ 63854359Sroberto#define RAWDCF_FLAGS 0 63954359Sroberto#define RAWDCF_ROOTDELAY 0.0 /* 0 */ 64054359Sroberto#define RAWDCF_BASEDELAY 0.258 64154359Sroberto#define RAWDCF_FORMAT "RAW DCF77 Timecode" 64254359Sroberto#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ 64354359Sroberto#define RAWDCF_SPEED (B50) 64454359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ 64554359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */ 64654359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) 64754359Sroberto#else 64854359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) 64954359Sroberto#endif 65054359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ 65154359Sroberto# define RAWDCF_IFLAG 0 65254359Sroberto#else 65354359Sroberto# define RAWDCF_IFLAG (IGNPAR) 65454359Sroberto#endif 65554359Sroberto#define RAWDCF_OFLAG 0 65654359Sroberto#define RAWDCF_LFLAG 0 65754359Sroberto#define RAWDCF_SAMPLES 20 65854359Sroberto#define RAWDCF_KEEP 12 65954359Sroberto#define RAWDCF_INIT 0 66054359Sroberto 66154359Sroberto/* 66254359Sroberto * RAW DCF variants 66354359Sroberto */ 66454359Sroberto/* 66554359Sroberto * Conrad receiver 66654359Sroberto * 66754359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad 66854359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232 66954359Sroberto */ 67054359Sroberto#define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ 67154359Sroberto#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" 67254359Sroberto 673182007Sroberto/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */ 674182007Sroberto#define GUDE_EMC_USB_V20_SPEED (B4800) 675182007Sroberto#define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */ 676182007Sroberto#define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)" 677182007Sroberto 67854359Sroberto/* 67954359Sroberto * TimeBrick receiver 68054359Sroberto */ 68154359Sroberto#define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ 68254359Sroberto#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" 68354359Sroberto 68454359Sroberto/* 68554359Sroberto * IGEL:clock receiver 68654359Sroberto */ 68754359Sroberto#define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ 68854359Sroberto#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" 68954359Sroberto#define IGELCLOCK_SPEED (B1200) 69054359Sroberto#define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) 69154359Sroberto 69254359Sroberto/* 69354359Sroberto * RAWDCF receivers that need to be powered from DTR 69454359Sroberto * (like Expert mouse clock) 69554359Sroberto */ 696285612Sdelphijstatic int rawdcf_init_1 (struct parseunit *); 69756746Sroberto#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 698285612Sdelphij#define RAWDCFDTRSET75_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)" 69956746Sroberto#define RAWDCFDTRSET_INIT rawdcf_init_1 70054359Sroberto 70154359Sroberto/* 70256746Sroberto * RAWDCF receivers that need to be powered from 70356746Sroberto * DTR CLR and RTS SET 70454359Sroberto */ 705285612Sdelphijstatic int rawdcf_init_2 (struct parseunit *); 70656746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 707285612Sdelphij#define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)" 70856746Sroberto#define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2 70954359Sroberto 71054359Sroberto/* 71154359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols) 71254359Sroberto */ 71354359Sroberto#ifndef TRIM_POLLRATE 71454359Sroberto#define TRIM_POLLRATE 0 /* only true direct polling */ 71554359Sroberto#endif 71654359Sroberto 71754359Sroberto#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" 71854359Sroberto#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) 71954359Sroberto 72054359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; 721285612Sdelphijstatic int trimbletaip_init (struct parseunit *); 722285612Sdelphijstatic void trimbletaip_event (struct parseunit *, int); 72354359Sroberto 72454359Sroberto/* query time & UTC correction data */ 72554359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; 72654359Sroberto 72754359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; 728285612Sdelphijstatic int trimbletsip_init (struct parseunit *); 729285612Sdelphijstatic void trimbletsip_end (struct parseunit *); 730285612Sdelphijstatic void trimbletsip_message (struct parseunit *, parsetime_t *); 731285612Sdelphijstatic void trimbletsip_event (struct parseunit *, int); 73254359Sroberto 73354359Sroberto#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ 734182007Sroberto#define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME 73554359Sroberto 73654359Sroberto#define TRIMBLETAIP_SPEED (B4800) 73754359Sroberto#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) 73854359Sroberto#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) 73954359Sroberto#define TRIMBLETAIP_OFLAG (OPOST|ONLCR) 74054359Sroberto#define TRIMBLETAIP_LFLAG (0) 74154359Sroberto 74254359Sroberto#define TRIMBLETSIP_SPEED (B9600) 74354359Sroberto#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) 74454359Sroberto#define TRIMBLETSIP_IFLAG (IGNBRK) 74554359Sroberto#define TRIMBLETSIP_OFLAG (0) 74654359Sroberto#define TRIMBLETSIP_LFLAG (ICANON) 74754359Sroberto 74854359Sroberto#define TRIMBLETSIP_SAMPLES 5 74954359Sroberto#define TRIMBLETSIP_KEEP 3 75054359Sroberto#define TRIMBLETAIP_SAMPLES 5 75154359Sroberto#define TRIMBLETAIP_KEEP 3 75254359Sroberto 75354359Sroberto#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) 75454359Sroberto#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) 75554359Sroberto 75654359Sroberto#define TRIMBLETAIP_POLL poll_dpoll 75754359Sroberto#define TRIMBLETSIP_POLL poll_dpoll 75854359Sroberto 75954359Sroberto#define TRIMBLETAIP_INIT trimbletaip_init 76054359Sroberto#define TRIMBLETSIP_INIT trimbletsip_init 76154359Sroberto 762285612Sdelphij#define TRIMBLETAIP_EVENT trimbletaip_event 76354359Sroberto 764285612Sdelphij#define TRIMBLETSIP_EVENT trimbletsip_event 76554359Sroberto#define TRIMBLETSIP_MESSAGE trimbletsip_message 76654359Sroberto 76754359Sroberto#define TRIMBLETAIP_END 0 76854359Sroberto#define TRIMBLETSIP_END trimbletsip_end 76954359Sroberto 77054359Sroberto#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) 77154359Sroberto#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) 77254359Sroberto 77354359Sroberto#define TRIMBLETAIP_ID GPS_ID 77454359Sroberto#define TRIMBLETSIP_ID GPS_ID 77554359Sroberto 77654359Sroberto#define TRIMBLETAIP_FORMAT "Trimble TAIP" 77754359Sroberto#define TRIMBLETSIP_FORMAT "Trimble TSIP" 77854359Sroberto 77954359Sroberto#define TRIMBLETAIP_ROOTDELAY 0x0 78054359Sroberto#define TRIMBLETSIP_ROOTDELAY 0x0 78154359Sroberto 78254359Sroberto#define TRIMBLETAIP_BASEDELAY 0.0 78354359Sroberto#define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ 78454359Sroberto 78554359Sroberto#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" 78654359Sroberto#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" 78754359Sroberto 78854359Sroberto#define TRIMBLETAIP_MAXUNSYNC 0 78954359Sroberto#define TRIMBLETSIP_MAXUNSYNC 0 79054359Sroberto 79154359Sroberto#define TRIMBLETAIP_EOL '<' 79254359Sroberto 79354359Sroberto/* 79454359Sroberto * RadioCode Clocks RCC 800 receiver 79554359Sroberto */ 79654359Sroberto#define RCC_POLLRATE 0 /* only true direct polling */ 79754359Sroberto#define RCC_POLLCMD "\r" 79854359Sroberto#define RCC_CMDSIZE 1 79954359Sroberto 80054359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; 80154359Sroberto#define RCC8000_FLAGS 0 80254359Sroberto#define RCC8000_POLL poll_dpoll 80354359Sroberto#define RCC8000_INIT poll_init 80454359Sroberto#define RCC8000_END 0 80554359Sroberto#define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) 80654359Sroberto#define RCC8000_ROOTDELAY 0.0 80754359Sroberto#define RCC8000_BASEDELAY 0.0 80854359Sroberto#define RCC8000_ID "MSF" 80954359Sroberto#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" 81054359Sroberto#define RCC8000_FORMAT "Radiocode RCC8000" 81154359Sroberto#define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ 81254359Sroberto#define RCC8000_SPEED (B2400) 81354359Sroberto#define RCC8000_CFLAG (CS8|CREAD|CLOCAL) 81454359Sroberto#define RCC8000_IFLAG (IGNBRK|IGNPAR) 81554359Sroberto#define RCC8000_OFLAG 0 81654359Sroberto#define RCC8000_LFLAG 0 81754359Sroberto#define RCC8000_SAMPLES 5 81854359Sroberto#define RCC8000_KEEP 3 81954359Sroberto 82054359Sroberto/* 821285612Sdelphij * Hopf Radio clock 6021 Format 82254359Sroberto * 82354359Sroberto */ 82454359Sroberto#define HOPF6021_ROOTDELAY 0.0 82554359Sroberto#define HOPF6021_BASEDELAY 0.0 82654359Sroberto#define HOPF6021_DESCRIPTION "HOPF 6021" 82754359Sroberto#define HOPF6021_FORMAT "hopf Funkuhr 6021" 82854359Sroberto#define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ 82954359Sroberto#define HOPF6021_SPEED (B9600) 83054359Sroberto#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) 83154359Sroberto#define HOPF6021_IFLAG (IGNBRK|ISTRIP) 83254359Sroberto#define HOPF6021_OFLAG 0 83354359Sroberto#define HOPF6021_LFLAG 0 83454359Sroberto#define HOPF6021_FLAGS 0 83554359Sroberto#define HOPF6021_SAMPLES 5 83654359Sroberto#define HOPF6021_KEEP 3 83754359Sroberto 83854359Sroberto/* 83954359Sroberto * Diem's Computime Radio Clock Receiver 84054359Sroberto */ 84154359Sroberto#define COMPUTIME_FLAGS 0 84254359Sroberto#define COMPUTIME_ROOTDELAY 0.0 84354359Sroberto#define COMPUTIME_BASEDELAY 0.0 84454359Sroberto#define COMPUTIME_ID DCF_ID 84554359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver" 84654359Sroberto#define COMPUTIME_FORMAT "Diem's Computime Radio Clock" 84754359Sroberto#define COMPUTIME_TYPE DCF_TYPE 84854359Sroberto#define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 84954359Sroberto#define COMPUTIME_SPEED (B9600) 85054359Sroberto#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) 85154359Sroberto#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) 85254359Sroberto#define COMPUTIME_OFLAG 0 85354359Sroberto#define COMPUTIME_LFLAG 0 85454359Sroberto#define COMPUTIME_SAMPLES 5 85554359Sroberto#define COMPUTIME_KEEP 3 85654359Sroberto 85754359Sroberto/* 85854359Sroberto * Varitext Radio Clock Receiver 85954359Sroberto */ 86054359Sroberto#define VARITEXT_FLAGS 0 86154359Sroberto#define VARITEXT_ROOTDELAY 0.0 86254359Sroberto#define VARITEXT_BASEDELAY 0.0 86354359Sroberto#define VARITEXT_ID "MSF" 86454359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver" 86554359Sroberto#define VARITEXT_FORMAT "Varitext Radio Clock" 86654359Sroberto#define VARITEXT_TYPE DCF_TYPE 86754359Sroberto#define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 86854359Sroberto#define VARITEXT_SPEED (B9600) 86954359Sroberto#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) 87054359Sroberto#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ 87154359Sroberto#define VARITEXT_OFLAG 0 87254359Sroberto#define VARITEXT_LFLAG 0 87354359Sroberto#define VARITEXT_SAMPLES 32 87454359Sroberto#define VARITEXT_KEEP 20 87554359Sroberto 876285612Sdelphij/* 877285612Sdelphij * SEL240x Satellite Sychronized Clock 878285612Sdelphij */ 879285612Sdelphij#define SEL240X_POLLRATE 0 /* only true direct polling */ 880285612Sdelphij#define SEL240X_POLLCMD "BUB8" 881285612Sdelphij#define SEL240X_CMDSIZE 4 882285612Sdelphij 883285612Sdelphijstatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE, 884285612Sdelphij SEL240X_POLLCMD, 885285612Sdelphij SEL240X_CMDSIZE }; 886285612Sdelphij#define SEL240X_FLAGS (PARSE_F_PPSONSECOND) 887285612Sdelphij#define SEL240X_POLL poll_dpoll 888285612Sdelphij#define SEL240X_INIT poll_init 889285612Sdelphij#define SEL240X_END 0 890285612Sdelphij#define SEL240X_DATA ((void *)(&sel240x_pollinfo)) 891285612Sdelphij#define SEL240X_ROOTDELAY 0.0 892285612Sdelphij#define SEL240X_BASEDELAY 0.0 893285612Sdelphij#define SEL240X_ID GPS_ID 894285612Sdelphij#define SEL240X_DESCRIPTION "SEL240x Satellite Synchronized Clock" 895285612Sdelphij#define SEL240X_FORMAT "SEL B8" 896285612Sdelphij#define SEL240X_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours */ 897285612Sdelphij#define SEL240X_SPEED (B9600) 898285612Sdelphij#define SEL240X_CFLAG (CS8|CREAD|CLOCAL) 899285612Sdelphij#define SEL240X_IFLAG (IGNBRK|IGNPAR) 900285612Sdelphij#define SEL240X_OFLAG (0) 901285612Sdelphij#define SEL240X_LFLAG (0) 902285612Sdelphij#define SEL240X_SAMPLES 5 903285612Sdelphij#define SEL240X_KEEP 3 904285612Sdelphij 90554359Srobertostatic struct parse_clockinfo 90654359Sroberto{ 907285612Sdelphij u_long cl_flags; /* operation flags (PPS interpretation, trust handling) */ 908285612Sdelphij void (*cl_poll) (struct parseunit *); /* active poll routine */ 909285612Sdelphij int (*cl_init) (struct parseunit *); /* active poll init routine */ 910285612Sdelphij void (*cl_event) (struct parseunit *, int); /* special event handling (e.g. reset clock) */ 911285612Sdelphij void (*cl_end) (struct parseunit *); /* active poll end routine */ 912285612Sdelphij void (*cl_message) (struct parseunit *, parsetime_t *); /* process a lower layer message */ 91354359Sroberto void *cl_data; /* local data area for "poll" mechanism */ 91454359Sroberto double cl_rootdelay; /* rootdelay */ 91554359Sroberto double cl_basedelay; /* current offset by which the RS232 91654359Sroberto time code is delayed from the actual time */ 91754359Sroberto const char *cl_id; /* ID code */ 91854359Sroberto const char *cl_description; /* device name */ 91954359Sroberto const char *cl_format; /* fixed format */ 92054359Sroberto u_char cl_type; /* clock type (ntp control) */ 921132451Sroberto u_long cl_maxunsync; /* time to trust oscillator after losing synch */ 92254359Sroberto u_long cl_speed; /* terminal input & output baudrate */ 92354359Sroberto u_long cl_cflag; /* terminal control flags */ 92454359Sroberto u_long cl_iflag; /* terminal input flags */ 92554359Sroberto u_long cl_oflag; /* terminal output flags */ 92654359Sroberto u_long cl_lflag; /* terminal local flags */ 92754359Sroberto u_long cl_samples; /* samples for median filter */ 92854359Sroberto u_long cl_keep; /* samples for median filter to keep */ 92954359Sroberto} parse_clockinfo[] = 93054359Sroberto{ 93154359Sroberto { /* mode 0 */ 93254359Sroberto MBG_FLAGS, 93354359Sroberto NO_POLL, 93454359Sroberto NO_INIT, 93554359Sroberto NO_EVENT, 93654359Sroberto NO_END, 93754359Sroberto NO_MESSAGE, 938182007Sroberto NO_LCLDATA, 93954359Sroberto DCFPZF535_ROOTDELAY, 94054359Sroberto DCFPZF535_BASEDELAY, 94154359Sroberto DCF_P_ID, 94254359Sroberto DCFPZF535_DESCRIPTION, 94354359Sroberto DCFPZF535_FORMAT, 94454359Sroberto DCF_TYPE, 94554359Sroberto DCFPZF535_MAXUNSYNC, 94654359Sroberto DCFPZF535_SPEED, 94754359Sroberto DCFPZF535_CFLAG, 94854359Sroberto DCFPZF535_IFLAG, 94954359Sroberto DCFPZF535_OFLAG, 95054359Sroberto DCFPZF535_LFLAG, 95154359Sroberto DCFPZF535_SAMPLES, 95254359Sroberto DCFPZF535_KEEP 95354359Sroberto }, 95454359Sroberto { /* mode 1 */ 95554359Sroberto MBG_FLAGS, 95654359Sroberto NO_POLL, 95754359Sroberto NO_INIT, 95854359Sroberto NO_EVENT, 95954359Sroberto NO_END, 96054359Sroberto NO_MESSAGE, 961182007Sroberto NO_LCLDATA, 96254359Sroberto DCFPZF535OCXO_ROOTDELAY, 96354359Sroberto DCFPZF535OCXO_BASEDELAY, 96454359Sroberto DCF_P_ID, 96554359Sroberto DCFPZF535OCXO_DESCRIPTION, 96654359Sroberto DCFPZF535OCXO_FORMAT, 96754359Sroberto DCF_TYPE, 96854359Sroberto DCFPZF535OCXO_MAXUNSYNC, 96954359Sroberto DCFPZF535OCXO_SPEED, 97054359Sroberto DCFPZF535OCXO_CFLAG, 97154359Sroberto DCFPZF535OCXO_IFLAG, 97254359Sroberto DCFPZF535OCXO_OFLAG, 97354359Sroberto DCFPZF535OCXO_LFLAG, 97454359Sroberto DCFPZF535OCXO_SAMPLES, 97554359Sroberto DCFPZF535OCXO_KEEP 97654359Sroberto }, 97754359Sroberto { /* mode 2 */ 97854359Sroberto MBG_FLAGS, 97954359Sroberto NO_POLL, 98054359Sroberto NO_INIT, 98154359Sroberto NO_EVENT, 98254359Sroberto NO_END, 98354359Sroberto NO_MESSAGE, 984182007Sroberto NO_LCLDATA, 98554359Sroberto DCFUA31_ROOTDELAY, 98654359Sroberto DCFUA31_BASEDELAY, 98754359Sroberto DCF_A_ID, 98854359Sroberto DCFUA31_DESCRIPTION, 98954359Sroberto DCFUA31_FORMAT, 99054359Sroberto DCF_TYPE, 99154359Sroberto DCFUA31_MAXUNSYNC, 99254359Sroberto DCFUA31_SPEED, 99354359Sroberto DCFUA31_CFLAG, 99454359Sroberto DCFUA31_IFLAG, 99554359Sroberto DCFUA31_OFLAG, 99654359Sroberto DCFUA31_LFLAG, 99754359Sroberto DCFUA31_SAMPLES, 99854359Sroberto DCFUA31_KEEP 99954359Sroberto }, 100054359Sroberto { /* mode 3 */ 100154359Sroberto MBG_FLAGS, 100254359Sroberto NO_POLL, 100354359Sroberto NO_INIT, 100454359Sroberto NO_EVENT, 100554359Sroberto NO_END, 100654359Sroberto NO_MESSAGE, 1007182007Sroberto NO_LCLDATA, 100854359Sroberto DCF7000_ROOTDELAY, 100954359Sroberto DCF7000_BASEDELAY, 101054359Sroberto DCF_A_ID, 101154359Sroberto DCF7000_DESCRIPTION, 101254359Sroberto DCF7000_FORMAT, 101354359Sroberto DCF_TYPE, 101454359Sroberto DCF7000_MAXUNSYNC, 101554359Sroberto DCF7000_SPEED, 101654359Sroberto DCF7000_CFLAG, 101754359Sroberto DCF7000_IFLAG, 101854359Sroberto DCF7000_OFLAG, 101954359Sroberto DCF7000_LFLAG, 102054359Sroberto DCF7000_SAMPLES, 102154359Sroberto DCF7000_KEEP 102254359Sroberto }, 102354359Sroberto { /* mode 4 */ 102454359Sroberto NO_CL_FLAGS, 102554359Sroberto WSDCF_POLL, 102654359Sroberto WSDCF_INIT, 102754359Sroberto NO_EVENT, 102854359Sroberto WSDCF_END, 102954359Sroberto NO_MESSAGE, 103054359Sroberto WSDCF_DATA, 103154359Sroberto WSDCF_ROOTDELAY, 103254359Sroberto WSDCF_BASEDELAY, 103354359Sroberto DCF_A_ID, 103454359Sroberto WSDCF_DESCRIPTION, 103554359Sroberto WSDCF_FORMAT, 103654359Sroberto DCF_TYPE, 103754359Sroberto WSDCF_MAXUNSYNC, 103854359Sroberto WSDCF_SPEED, 103954359Sroberto WSDCF_CFLAG, 104054359Sroberto WSDCF_IFLAG, 104154359Sroberto WSDCF_OFLAG, 104254359Sroberto WSDCF_LFLAG, 104354359Sroberto WSDCF_SAMPLES, 104454359Sroberto WSDCF_KEEP 104554359Sroberto }, 104654359Sroberto { /* mode 5 */ 104754359Sroberto RAWDCF_FLAGS, 104854359Sroberto NO_POLL, 104954359Sroberto RAWDCF_INIT, 105054359Sroberto NO_EVENT, 105154359Sroberto NO_END, 105254359Sroberto NO_MESSAGE, 1053182007Sroberto NO_LCLDATA, 105454359Sroberto RAWDCF_ROOTDELAY, 105554359Sroberto CONRAD_BASEDELAY, 105654359Sroberto DCF_A_ID, 105754359Sroberto CONRAD_DESCRIPTION, 105854359Sroberto RAWDCF_FORMAT, 105954359Sroberto DCF_TYPE, 106054359Sroberto RAWDCF_MAXUNSYNC, 106154359Sroberto RAWDCF_SPEED, 106254359Sroberto RAWDCF_CFLAG, 106354359Sroberto RAWDCF_IFLAG, 106454359Sroberto RAWDCF_OFLAG, 106554359Sroberto RAWDCF_LFLAG, 106654359Sroberto RAWDCF_SAMPLES, 106754359Sroberto RAWDCF_KEEP 106854359Sroberto }, 106954359Sroberto { /* mode 6 */ 107054359Sroberto RAWDCF_FLAGS, 107154359Sroberto NO_POLL, 107254359Sroberto RAWDCF_INIT, 107354359Sroberto NO_EVENT, 107454359Sroberto NO_END, 107554359Sroberto NO_MESSAGE, 1076182007Sroberto NO_LCLDATA, 107754359Sroberto RAWDCF_ROOTDELAY, 107854359Sroberto TIMEBRICK_BASEDELAY, 107954359Sroberto DCF_A_ID, 108054359Sroberto TIMEBRICK_DESCRIPTION, 108154359Sroberto RAWDCF_FORMAT, 108254359Sroberto DCF_TYPE, 108354359Sroberto RAWDCF_MAXUNSYNC, 108454359Sroberto RAWDCF_SPEED, 108554359Sroberto RAWDCF_CFLAG, 108654359Sroberto RAWDCF_IFLAG, 108754359Sroberto RAWDCF_OFLAG, 108854359Sroberto RAWDCF_LFLAG, 108954359Sroberto RAWDCF_SAMPLES, 109054359Sroberto RAWDCF_KEEP 109154359Sroberto }, 109254359Sroberto { /* mode 7 */ 109354359Sroberto MBG_FLAGS, 109454359Sroberto GPS16X_POLL, 109554359Sroberto GPS16X_INIT, 109654359Sroberto NO_EVENT, 109754359Sroberto GPS16X_END, 109854359Sroberto GPS16X_MESSAGE, 109954359Sroberto GPS16X_DATA, 110054359Sroberto GPS16X_ROOTDELAY, 110154359Sroberto GPS16X_BASEDELAY, 110254359Sroberto GPS16X_ID, 110354359Sroberto GPS16X_DESCRIPTION, 110454359Sroberto GPS16X_FORMAT, 110554359Sroberto GPS_TYPE, 110654359Sroberto GPS16X_MAXUNSYNC, 110754359Sroberto GPS16X_SPEED, 110854359Sroberto GPS16X_CFLAG, 110954359Sroberto GPS16X_IFLAG, 111054359Sroberto GPS16X_OFLAG, 111154359Sroberto GPS16X_LFLAG, 111254359Sroberto GPS16X_SAMPLES, 111354359Sroberto GPS16X_KEEP 111454359Sroberto }, 111554359Sroberto { /* mode 8 */ 111654359Sroberto RAWDCF_FLAGS, 111754359Sroberto NO_POLL, 111854359Sroberto NO_INIT, 111954359Sroberto NO_EVENT, 112054359Sroberto NO_END, 112154359Sroberto NO_MESSAGE, 1122182007Sroberto NO_LCLDATA, 112354359Sroberto RAWDCF_ROOTDELAY, 112454359Sroberto IGELCLOCK_BASEDELAY, 112554359Sroberto DCF_A_ID, 112654359Sroberto IGELCLOCK_DESCRIPTION, 112754359Sroberto RAWDCF_FORMAT, 112854359Sroberto DCF_TYPE, 112954359Sroberto RAWDCF_MAXUNSYNC, 113054359Sroberto IGELCLOCK_SPEED, 113154359Sroberto IGELCLOCK_CFLAG, 113254359Sroberto RAWDCF_IFLAG, 113354359Sroberto RAWDCF_OFLAG, 113454359Sroberto RAWDCF_LFLAG, 113554359Sroberto RAWDCF_SAMPLES, 113654359Sroberto RAWDCF_KEEP 113754359Sroberto }, 113854359Sroberto { /* mode 9 */ 113954359Sroberto TRIMBLETAIP_FLAGS, 114054359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 114154359Sroberto NO_POLL, 114254359Sroberto#else 114354359Sroberto TRIMBLETAIP_POLL, 114454359Sroberto#endif 114554359Sroberto TRIMBLETAIP_INIT, 114654359Sroberto TRIMBLETAIP_EVENT, 114754359Sroberto TRIMBLETAIP_END, 114854359Sroberto NO_MESSAGE, 114954359Sroberto TRIMBLETAIP_DATA, 115054359Sroberto TRIMBLETAIP_ROOTDELAY, 115154359Sroberto TRIMBLETAIP_BASEDELAY, 115254359Sroberto TRIMBLETAIP_ID, 115354359Sroberto TRIMBLETAIP_DESCRIPTION, 115454359Sroberto TRIMBLETAIP_FORMAT, 115554359Sroberto GPS_TYPE, 115654359Sroberto TRIMBLETAIP_MAXUNSYNC, 115754359Sroberto TRIMBLETAIP_SPEED, 115854359Sroberto TRIMBLETAIP_CFLAG, 115954359Sroberto TRIMBLETAIP_IFLAG, 116054359Sroberto TRIMBLETAIP_OFLAG, 116154359Sroberto TRIMBLETAIP_LFLAG, 116254359Sroberto TRIMBLETAIP_SAMPLES, 116354359Sroberto TRIMBLETAIP_KEEP 116454359Sroberto }, 116554359Sroberto { /* mode 10 */ 116654359Sroberto TRIMBLETSIP_FLAGS, 116754359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 116854359Sroberto NO_POLL, 116954359Sroberto#else 117054359Sroberto TRIMBLETSIP_POLL, 117154359Sroberto#endif 117254359Sroberto TRIMBLETSIP_INIT, 117354359Sroberto TRIMBLETSIP_EVENT, 117454359Sroberto TRIMBLETSIP_END, 117554359Sroberto TRIMBLETSIP_MESSAGE, 117654359Sroberto TRIMBLETSIP_DATA, 117754359Sroberto TRIMBLETSIP_ROOTDELAY, 117854359Sroberto TRIMBLETSIP_BASEDELAY, 117954359Sroberto TRIMBLETSIP_ID, 118054359Sroberto TRIMBLETSIP_DESCRIPTION, 118154359Sroberto TRIMBLETSIP_FORMAT, 118254359Sroberto GPS_TYPE, 118354359Sroberto TRIMBLETSIP_MAXUNSYNC, 118454359Sroberto TRIMBLETSIP_SPEED, 118554359Sroberto TRIMBLETSIP_CFLAG, 118654359Sroberto TRIMBLETSIP_IFLAG, 118754359Sroberto TRIMBLETSIP_OFLAG, 118854359Sroberto TRIMBLETSIP_LFLAG, 118954359Sroberto TRIMBLETSIP_SAMPLES, 119054359Sroberto TRIMBLETSIP_KEEP 119154359Sroberto }, 119254359Sroberto { /* mode 11 */ 119354359Sroberto NO_CL_FLAGS, 119454359Sroberto RCC8000_POLL, 119554359Sroberto RCC8000_INIT, 119654359Sroberto NO_EVENT, 119754359Sroberto RCC8000_END, 119854359Sroberto NO_MESSAGE, 119954359Sroberto RCC8000_DATA, 120054359Sroberto RCC8000_ROOTDELAY, 120154359Sroberto RCC8000_BASEDELAY, 120254359Sroberto RCC8000_ID, 120354359Sroberto RCC8000_DESCRIPTION, 120454359Sroberto RCC8000_FORMAT, 120554359Sroberto DCF_TYPE, 120654359Sroberto RCC8000_MAXUNSYNC, 120754359Sroberto RCC8000_SPEED, 120854359Sroberto RCC8000_CFLAG, 120954359Sroberto RCC8000_IFLAG, 121054359Sroberto RCC8000_OFLAG, 121154359Sroberto RCC8000_LFLAG, 121254359Sroberto RCC8000_SAMPLES, 121354359Sroberto RCC8000_KEEP 121454359Sroberto }, 121554359Sroberto { /* mode 12 */ 121654359Sroberto HOPF6021_FLAGS, 1217285612Sdelphij NO_POLL, 121854359Sroberto NO_INIT, 121954359Sroberto NO_EVENT, 122054359Sroberto NO_END, 122154359Sroberto NO_MESSAGE, 1222182007Sroberto NO_LCLDATA, 122354359Sroberto HOPF6021_ROOTDELAY, 122454359Sroberto HOPF6021_BASEDELAY, 122554359Sroberto DCF_ID, 122654359Sroberto HOPF6021_DESCRIPTION, 122754359Sroberto HOPF6021_FORMAT, 122854359Sroberto DCF_TYPE, 122954359Sroberto HOPF6021_MAXUNSYNC, 123054359Sroberto HOPF6021_SPEED, 123154359Sroberto HOPF6021_CFLAG, 123254359Sroberto HOPF6021_IFLAG, 123354359Sroberto HOPF6021_OFLAG, 123454359Sroberto HOPF6021_LFLAG, 123554359Sroberto HOPF6021_SAMPLES, 123654359Sroberto HOPF6021_KEEP 123754359Sroberto }, 123854359Sroberto { /* mode 13 */ 123954359Sroberto COMPUTIME_FLAGS, 124054359Sroberto NO_POLL, 124154359Sroberto NO_INIT, 124254359Sroberto NO_EVENT, 124354359Sroberto NO_END, 124454359Sroberto NO_MESSAGE, 1245182007Sroberto NO_LCLDATA, 124654359Sroberto COMPUTIME_ROOTDELAY, 124754359Sroberto COMPUTIME_BASEDELAY, 124854359Sroberto COMPUTIME_ID, 124954359Sroberto COMPUTIME_DESCRIPTION, 125054359Sroberto COMPUTIME_FORMAT, 125154359Sroberto COMPUTIME_TYPE, 125254359Sroberto COMPUTIME_MAXUNSYNC, 125354359Sroberto COMPUTIME_SPEED, 125454359Sroberto COMPUTIME_CFLAG, 125554359Sroberto COMPUTIME_IFLAG, 125654359Sroberto COMPUTIME_OFLAG, 125754359Sroberto COMPUTIME_LFLAG, 125854359Sroberto COMPUTIME_SAMPLES, 125954359Sroberto COMPUTIME_KEEP 126054359Sroberto }, 126154359Sroberto { /* mode 14 */ 126254359Sroberto RAWDCF_FLAGS, 126354359Sroberto NO_POLL, 126456746Sroberto RAWDCFDTRSET_INIT, 126554359Sroberto NO_EVENT, 126654359Sroberto NO_END, 126754359Sroberto NO_MESSAGE, 1268182007Sroberto NO_LCLDATA, 126954359Sroberto RAWDCF_ROOTDELAY, 127054359Sroberto RAWDCF_BASEDELAY, 127154359Sroberto DCF_A_ID, 127256746Sroberto RAWDCFDTRSET_DESCRIPTION, 127354359Sroberto RAWDCF_FORMAT, 127454359Sroberto DCF_TYPE, 127554359Sroberto RAWDCF_MAXUNSYNC, 127654359Sroberto RAWDCF_SPEED, 127754359Sroberto RAWDCF_CFLAG, 127854359Sroberto RAWDCF_IFLAG, 127954359Sroberto RAWDCF_OFLAG, 128054359Sroberto RAWDCF_LFLAG, 128154359Sroberto RAWDCF_SAMPLES, 128254359Sroberto RAWDCF_KEEP 128354359Sroberto }, 128454359Sroberto { /* mode 15 */ 128556746Sroberto 0, /* operation flags (io modes) */ 128682498Sroberto NO_POLL, /* active poll routine */ 128782498Sroberto NO_INIT, /* active poll init routine */ 128856746Sroberto NO_EVENT, /* special event handling (e.g. reset clock) */ 128956746Sroberto NO_END, /* active poll end routine */ 129056746Sroberto NO_MESSAGE, /* process a lower layer message */ 1291182007Sroberto NO_LCLDATA, /* local data area for "poll" mechanism */ 129256746Sroberto 0, /* rootdelay */ 129382498Sroberto 11.0 /* bits */ / 9600, /* current offset by which the RS232 129456746Sroberto time code is delayed from the actual time */ 129556746Sroberto DCF_ID, /* ID code */ 129656746Sroberto "WHARTON 400A Series clock", /* device name */ 129782498Sroberto "WHARTON 400A Series clock Output Format 1", /* fixed format */ 129856746Sroberto /* Must match a format-name in a libparse/clk_xxx.c file */ 129956746Sroberto DCF_TYPE, /* clock type (ntp control) */ 1300132451Sroberto (1*60*60), /* time to trust oscillator after losing synch */ 130156746Sroberto B9600, /* terminal input & output baudrate */ 130256746Sroberto (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ 130356746Sroberto 0, /* terminal input flags */ 130456746Sroberto 0, /* terminal output flags */ 130556746Sroberto 0, /* terminal local flags */ 130656746Sroberto 5, /* samples for median filter */ 130756746Sroberto 3, /* samples for median filter to keep */ 130854359Sroberto }, 130956746Sroberto { /* mode 16 - RAWDCF RTS set, DTR clr */ 131056746Sroberto RAWDCF_FLAGS, 131156746Sroberto NO_POLL, 131256746Sroberto RAWDCFDTRCLRRTSSET_INIT, 131356746Sroberto NO_EVENT, 131456746Sroberto NO_END, 131556746Sroberto NO_MESSAGE, 1316182007Sroberto NO_LCLDATA, 131756746Sroberto RAWDCF_ROOTDELAY, 131856746Sroberto RAWDCF_BASEDELAY, 131956746Sroberto DCF_A_ID, 132056746Sroberto RAWDCFDTRCLRRTSSET_DESCRIPTION, 132156746Sroberto RAWDCF_FORMAT, 132256746Sroberto DCF_TYPE, 132356746Sroberto RAWDCF_MAXUNSYNC, 132456746Sroberto RAWDCF_SPEED, 132556746Sroberto RAWDCF_CFLAG, 132656746Sroberto RAWDCF_IFLAG, 132756746Sroberto RAWDCF_OFLAG, 132856746Sroberto RAWDCF_LFLAG, 132956746Sroberto RAWDCF_SAMPLES, 133056746Sroberto RAWDCF_KEEP 133156746Sroberto }, 133256746Sroberto { /* mode 17 */ 133354359Sroberto VARITEXT_FLAGS, 133454359Sroberto NO_POLL, 133554359Sroberto NO_INIT, 133654359Sroberto NO_EVENT, 133754359Sroberto NO_END, 133854359Sroberto NO_MESSAGE, 1339182007Sroberto NO_LCLDATA, 134054359Sroberto VARITEXT_ROOTDELAY, 134154359Sroberto VARITEXT_BASEDELAY, 134254359Sroberto VARITEXT_ID, 134354359Sroberto VARITEXT_DESCRIPTION, 134454359Sroberto VARITEXT_FORMAT, 134554359Sroberto VARITEXT_TYPE, 134654359Sroberto VARITEXT_MAXUNSYNC, 134754359Sroberto VARITEXT_SPEED, 134854359Sroberto VARITEXT_CFLAG, 134954359Sroberto VARITEXT_IFLAG, 135054359Sroberto VARITEXT_OFLAG, 135154359Sroberto VARITEXT_LFLAG, 135254359Sroberto VARITEXT_SAMPLES, 135354359Sroberto VARITEXT_KEEP 1354182007Sroberto }, 1355182007Sroberto { /* mode 18 */ 1356182007Sroberto MBG_FLAGS, 1357182007Sroberto NO_POLL, 1358182007Sroberto NO_INIT, 1359182007Sroberto NO_EVENT, 1360182007Sroberto GPS16X_END, 1361182007Sroberto GPS16X_MESSAGE, 1362182007Sroberto GPS16X_DATA, 1363182007Sroberto GPS16X_ROOTDELAY, 1364182007Sroberto GPS16X_BASEDELAY, 1365182007Sroberto GPS16X_ID, 1366182007Sroberto GPS16X_DESCRIPTION, 1367182007Sroberto GPS16X_FORMAT, 1368182007Sroberto GPS_TYPE, 1369182007Sroberto GPS16X_MAXUNSYNC, 1370182007Sroberto GPS16X_SPEED, 1371182007Sroberto GPS16X_CFLAG, 1372182007Sroberto GPS16X_IFLAG, 1373182007Sroberto GPS16X_OFLAG, 1374182007Sroberto GPS16X_LFLAG, 1375182007Sroberto GPS16X_SAMPLES, 1376182007Sroberto GPS16X_KEEP 1377182007Sroberto }, 1378182007Sroberto { /* mode 19 */ 1379182007Sroberto RAWDCF_FLAGS, 1380182007Sroberto NO_POLL, 1381182007Sroberto RAWDCF_INIT, 1382182007Sroberto NO_EVENT, 1383182007Sroberto NO_END, 1384182007Sroberto NO_MESSAGE, 1385182007Sroberto NO_LCLDATA, 1386182007Sroberto RAWDCF_ROOTDELAY, 1387182007Sroberto GUDE_EMC_USB_V20_BASEDELAY, 1388182007Sroberto DCF_A_ID, 1389182007Sroberto GUDE_EMC_USB_V20_DESCRIPTION, 1390182007Sroberto RAWDCF_FORMAT, 1391182007Sroberto DCF_TYPE, 1392182007Sroberto RAWDCF_MAXUNSYNC, 1393182007Sroberto GUDE_EMC_USB_V20_SPEED, 1394182007Sroberto RAWDCF_CFLAG, 1395182007Sroberto RAWDCF_IFLAG, 1396182007Sroberto RAWDCF_OFLAG, 1397182007Sroberto RAWDCF_LFLAG, 1398182007Sroberto RAWDCF_SAMPLES, 1399182007Sroberto RAWDCF_KEEP 1400182007Sroberto }, 1401285612Sdelphij { /* mode 20, like mode 14 but driven by 75 baud */ 1402285612Sdelphij RAWDCF_FLAGS, 1403285612Sdelphij NO_POLL, 1404285612Sdelphij RAWDCFDTRSET_INIT, 1405285612Sdelphij NO_EVENT, 1406285612Sdelphij NO_END, 1407285612Sdelphij NO_MESSAGE, 1408285612Sdelphij NO_LCLDATA, 1409285612Sdelphij RAWDCF_ROOTDELAY, 1410285612Sdelphij RAWDCF_BASEDELAY, 1411285612Sdelphij DCF_A_ID, 1412285612Sdelphij RAWDCFDTRSET75_DESCRIPTION, 1413285612Sdelphij RAWDCF_FORMAT, 1414285612Sdelphij DCF_TYPE, 1415285612Sdelphij RAWDCF_MAXUNSYNC, 1416285612Sdelphij B75, 1417285612Sdelphij RAWDCF_CFLAG, 1418285612Sdelphij RAWDCF_IFLAG, 1419285612Sdelphij RAWDCF_OFLAG, 1420285612Sdelphij RAWDCF_LFLAG, 1421285612Sdelphij RAWDCF_SAMPLES, 1422285612Sdelphij RAWDCF_KEEP 1423285612Sdelphij }, 1424285612Sdelphij { /* mode 21, like mode 16 but driven by 75 baud 1425285612Sdelphij - RAWDCF RTS set, DTR clr */ 1426285612Sdelphij RAWDCF_FLAGS, 1427285612Sdelphij NO_POLL, 1428285612Sdelphij RAWDCFDTRCLRRTSSET_INIT, 1429285612Sdelphij NO_EVENT, 1430285612Sdelphij NO_END, 1431285612Sdelphij NO_MESSAGE, 1432285612Sdelphij NO_LCLDATA, 1433285612Sdelphij RAWDCF_ROOTDELAY, 1434285612Sdelphij RAWDCF_BASEDELAY, 1435285612Sdelphij DCF_A_ID, 1436285612Sdelphij RAWDCFDTRCLRRTSSET75_DESCRIPTION, 1437285612Sdelphij RAWDCF_FORMAT, 1438285612Sdelphij DCF_TYPE, 1439285612Sdelphij RAWDCF_MAXUNSYNC, 1440285612Sdelphij B75, 1441285612Sdelphij RAWDCF_CFLAG, 1442285612Sdelphij RAWDCF_IFLAG, 1443285612Sdelphij RAWDCF_OFLAG, 1444285612Sdelphij RAWDCF_LFLAG, 1445285612Sdelphij RAWDCF_SAMPLES, 1446285612Sdelphij RAWDCF_KEEP 1447285612Sdelphij }, 1448285612Sdelphij { /* mode 22 - like 2 with POWERUP trust */ 1449285612Sdelphij MBG_FLAGS | PARSE_F_POWERUPTRUST, 1450285612Sdelphij NO_POLL, 1451285612Sdelphij NO_INIT, 1452285612Sdelphij NO_EVENT, 1453285612Sdelphij NO_END, 1454285612Sdelphij NO_MESSAGE, 1455285612Sdelphij NO_LCLDATA, 1456285612Sdelphij DCFUA31_ROOTDELAY, 1457285612Sdelphij DCFUA31_BASEDELAY, 1458285612Sdelphij DCF_A_ID, 1459285612Sdelphij DCFUA31_DESCRIPTION, 1460285612Sdelphij DCFUA31_FORMAT, 1461285612Sdelphij DCF_TYPE, 1462285612Sdelphij DCFUA31_MAXUNSYNC, 1463285612Sdelphij DCFUA31_SPEED, 1464285612Sdelphij DCFUA31_CFLAG, 1465285612Sdelphij DCFUA31_IFLAG, 1466285612Sdelphij DCFUA31_OFLAG, 1467285612Sdelphij DCFUA31_LFLAG, 1468285612Sdelphij DCFUA31_SAMPLES, 1469285612Sdelphij DCFUA31_KEEP 1470285612Sdelphij }, 1471285612Sdelphij { /* mode 23 - like 7 with POWERUP trust */ 1472285612Sdelphij MBG_FLAGS | PARSE_F_POWERUPTRUST, 1473285612Sdelphij GPS16X_POLL, 1474285612Sdelphij GPS16X_INIT, 1475285612Sdelphij NO_EVENT, 1476285612Sdelphij GPS16X_END, 1477285612Sdelphij GPS16X_MESSAGE, 1478285612Sdelphij GPS16X_DATA, 1479285612Sdelphij GPS16X_ROOTDELAY, 1480285612Sdelphij GPS16X_BASEDELAY, 1481285612Sdelphij GPS16X_ID, 1482285612Sdelphij GPS16X_DESCRIPTION, 1483285612Sdelphij GPS16X_FORMAT, 1484285612Sdelphij GPS_TYPE, 1485285612Sdelphij GPS16X_MAXUNSYNC, 1486285612Sdelphij GPS16X_SPEED, 1487285612Sdelphij GPS16X_CFLAG, 1488285612Sdelphij GPS16X_IFLAG, 1489285612Sdelphij GPS16X_OFLAG, 1490285612Sdelphij GPS16X_LFLAG, 1491285612Sdelphij GPS16X_SAMPLES, 1492285612Sdelphij GPS16X_KEEP 1493285612Sdelphij }, 1494285612Sdelphij { /* mode 24 */ 1495285612Sdelphij SEL240X_FLAGS, 1496285612Sdelphij SEL240X_POLL, 1497285612Sdelphij SEL240X_INIT, 1498285612Sdelphij NO_EVENT, 1499285612Sdelphij SEL240X_END, 1500285612Sdelphij NO_MESSAGE, 1501285612Sdelphij SEL240X_DATA, 1502285612Sdelphij SEL240X_ROOTDELAY, 1503285612Sdelphij SEL240X_BASEDELAY, 1504285612Sdelphij SEL240X_ID, 1505285612Sdelphij SEL240X_DESCRIPTION, 1506285612Sdelphij SEL240X_FORMAT, 1507285612Sdelphij GPS_TYPE, 1508285612Sdelphij SEL240X_MAXUNSYNC, 1509285612Sdelphij SEL240X_SPEED, 1510285612Sdelphij SEL240X_CFLAG, 1511285612Sdelphij SEL240X_IFLAG, 1512285612Sdelphij SEL240X_OFLAG, 1513285612Sdelphij SEL240X_LFLAG, 1514285612Sdelphij SEL240X_SAMPLES, 1515285612Sdelphij SEL240X_KEEP 1516285612Sdelphij }, 151754359Sroberto}; 151854359Sroberto 151954359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); 152054359Sroberto 1521132451Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) 152254359Sroberto#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) 152354359Sroberto#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) 1524132451Sroberto#define CLK_PPS(x) (((x)->ttl) & 0x80) 152554359Sroberto 152654359Sroberto/* 152754359Sroberto * Other constant stuff 152854359Sroberto */ 152954359Sroberto#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ 153054359Sroberto 153154359Sroberto#define PARSESTATISTICS (60*60) /* output state statistics every hour */ 153254359Sroberto 153354359Srobertostatic int notice = 0; 153454359Sroberto 153554359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) 153654359Sroberto 1537285612Sdelphijstatic void parse_event (struct parseunit *, int); 1538285612Sdelphijstatic void parse_process (struct parseunit *, parsetime_t *); 1539285612Sdelphijstatic void clear_err (struct parseunit *, u_long); 1540285612Sdelphijstatic int list_err (struct parseunit *, u_long); 1541285612Sdelphijstatic char * l_mktime (u_long); 154254359Sroberto 154354359Sroberto/**=========================================================================== 154454359Sroberto ** implementation error message regression module 154554359Sroberto **/ 154654359Srobertostatic void 154754359Srobertoclear_err( 154854359Sroberto struct parseunit *parse, 154954359Sroberto u_long lstate 155054359Sroberto ) 155154359Sroberto{ 155254359Sroberto if (lstate == ERR_ALL) 155354359Sroberto { 1554285612Sdelphij size_t i; 155554359Sroberto 155654359Sroberto for (i = 0; i < ERR_CNT; i++) 155754359Sroberto { 155854359Sroberto parse->errors[i].err_stage = err_tbl[i]; 155954359Sroberto parse->errors[i].err_cnt = 0; 156054359Sroberto parse->errors[i].err_last = 0; 156154359Sroberto parse->errors[i].err_started = 0; 156254359Sroberto parse->errors[i].err_suppressed = 0; 156354359Sroberto } 156454359Sroberto } 156554359Sroberto else 156654359Sroberto { 156754359Sroberto parse->errors[lstate].err_stage = err_tbl[lstate]; 156854359Sroberto parse->errors[lstate].err_cnt = 0; 156954359Sroberto parse->errors[lstate].err_last = 0; 157054359Sroberto parse->errors[lstate].err_started = 0; 157154359Sroberto parse->errors[lstate].err_suppressed = 0; 157254359Sroberto } 157354359Sroberto} 157454359Sroberto 157554359Srobertostatic int 157654359Srobertolist_err( 157754359Sroberto struct parseunit *parse, 157854359Sroberto u_long lstate 157954359Sroberto ) 158054359Sroberto{ 158154359Sroberto int do_it; 158254359Sroberto struct errorinfo *err = &parse->errors[lstate]; 158354359Sroberto 158454359Sroberto if (err->err_started == 0) 158554359Sroberto { 158654359Sroberto err->err_started = current_time; 158754359Sroberto } 158854359Sroberto 158954359Sroberto do_it = (current_time - err->err_last) >= err->err_stage->err_delay; 159054359Sroberto 159154359Sroberto if (do_it) 159254359Sroberto err->err_cnt++; 1593285612Sdelphij 159454359Sroberto if (err->err_stage->err_count && 159554359Sroberto (err->err_cnt >= err->err_stage->err_count)) 159654359Sroberto { 159754359Sroberto err->err_stage++; 159854359Sroberto err->err_cnt = 0; 159954359Sroberto } 160054359Sroberto 160154359Sroberto if (!err->err_cnt && do_it) 160254359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", 160354359Sroberto CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); 160454359Sroberto 160554359Sroberto if (!do_it) 160654359Sroberto err->err_suppressed++; 160754359Sroberto else 160854359Sroberto err->err_last = current_time; 160954359Sroberto 161054359Sroberto if (do_it && err->err_suppressed) 161154359Sroberto { 161254359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", 161354359Sroberto CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", 161454359Sroberto l_mktime(current_time - err->err_started)); 161554359Sroberto err->err_suppressed = 0; 161654359Sroberto } 1617285612Sdelphij 161854359Sroberto return do_it; 161954359Sroberto} 162054359Sroberto 162154359Sroberto/*-------------------------------------------------- 162254359Sroberto * mkreadable - make a printable ascii string (without 162354359Sroberto * embedded quotes so that the ntpq protocol isn't 162454359Sroberto * fooled 162554359Sroberto */ 162654359Sroberto#ifndef isprint 162754359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) 162854359Sroberto#endif 162954359Sroberto 163054359Srobertostatic char * 163154359Srobertomkreadable( 163254359Sroberto char *buffer, 1633293650Sglebius size_t blen, 163454359Sroberto const char *src, 1635293650Sglebius size_t srclen, 163654359Sroberto int hex 163754359Sroberto ) 163854359Sroberto{ 1639285612Sdelphij static const char ellipsis[] = "..."; 164054359Sroberto char *b = buffer; 1641285612Sdelphij char *endb = NULL; 164254359Sroberto 164354359Sroberto if (blen < 4) 1644285612Sdelphij return NULL; /* don't bother with mini buffers */ 164554359Sroberto 1646285612Sdelphij endb = buffer + blen - sizeof(ellipsis); 164754359Sroberto 164854359Sroberto blen--; /* account for '\0' */ 164954359Sroberto 165054359Sroberto while (blen && srclen--) 165154359Sroberto { 165254359Sroberto if (!hex && /* no binary only */ 165354359Sroberto (*src != '\\') && /* no plain \ */ 165454359Sroberto (*src != '"') && /* no " */ 1655285612Sdelphij isprint((unsigned char)*src)) /* only printables */ 165654359Sroberto { /* they are easy... */ 165754359Sroberto *buffer++ = *src++; 165854359Sroberto blen--; 165954359Sroberto } 166054359Sroberto else 166154359Sroberto { 166254359Sroberto if (blen < 4) 166354359Sroberto { 166454359Sroberto while (blen--) 166554359Sroberto { 166654359Sroberto *buffer++ = '.'; 166754359Sroberto } 166854359Sroberto *buffer = '\0'; 166954359Sroberto return b; 167054359Sroberto } 167154359Sroberto else 167254359Sroberto { 167354359Sroberto if (*src == '\\') 167454359Sroberto { 1675285612Sdelphij memcpy(buffer, "\\\\", 2); 167654359Sroberto buffer += 2; 167754359Sroberto blen -= 2; 167854359Sroberto src++; 167954359Sroberto } 168054359Sroberto else 168154359Sroberto { 1682285612Sdelphij snprintf(buffer, blen, "\\x%02x", *src++); 168354359Sroberto blen -= 4; 168454359Sroberto buffer += 4; 168554359Sroberto } 168654359Sroberto } 168754359Sroberto } 168854359Sroberto if (srclen && !blen && endb) /* overflow - set last chars to ... */ 1689285612Sdelphij memcpy(endb, ellipsis, sizeof(ellipsis)); 169054359Sroberto } 169154359Sroberto 169254359Sroberto *buffer = '\0'; 169354359Sroberto return b; 169454359Sroberto} 169554359Sroberto 169654359Sroberto 169754359Sroberto/*-------------------------------------------------- 169854359Sroberto * mkascii - make a printable ascii string 169954359Sroberto * assumes (unless defined better) 7-bit ASCII 170054359Sroberto */ 170154359Srobertostatic char * 170254359Srobertomkascii( 170354359Sroberto char *buffer, 170454359Sroberto long blen, 170554359Sroberto const char *src, 170654359Sroberto u_long srclen 170754359Sroberto ) 170854359Sroberto{ 170954359Sroberto return mkreadable(buffer, blen, src, srclen, 0); 171054359Sroberto} 171154359Sroberto 171254359Sroberto/**=========================================================================== 171354359Sroberto ** implementation of i/o handling methods 171454359Sroberto ** (all STREAM, partial STREAM, user level) 171554359Sroberto **/ 171654359Sroberto 171754359Sroberto/* 171854359Sroberto * define possible io handling methods 171954359Sroberto */ 172054359Sroberto#ifdef STREAM 1721285612Sdelphijstatic int ppsclock_init (struct parseunit *); 1722285612Sdelphijstatic int stream_init (struct parseunit *); 1723285612Sdelphijstatic void stream_end (struct parseunit *); 1724285612Sdelphijstatic int stream_enable (struct parseunit *); 1725285612Sdelphijstatic int stream_disable (struct parseunit *); 1726285612Sdelphijstatic int stream_setcs (struct parseunit *, parsectl_t *); 1727285612Sdelphijstatic int stream_getfmt (struct parseunit *, parsectl_t *); 1728285612Sdelphijstatic int stream_setfmt (struct parseunit *, parsectl_t *); 1729285612Sdelphijstatic int stream_timecode (struct parseunit *, parsectl_t *); 1730285612Sdelphijstatic void stream_receive (struct recvbuf *); 173154359Sroberto#endif 173254359Sroberto 1733285612Sdelphijstatic int local_init (struct parseunit *); 1734285612Sdelphijstatic void local_end (struct parseunit *); 1735285612Sdelphijstatic int local_nop (struct parseunit *); 1736285612Sdelphijstatic int local_setcs (struct parseunit *, parsectl_t *); 1737285612Sdelphijstatic int local_getfmt (struct parseunit *, parsectl_t *); 1738285612Sdelphijstatic int local_setfmt (struct parseunit *, parsectl_t *); 1739285612Sdelphijstatic int local_timecode (struct parseunit *, parsectl_t *); 1740285612Sdelphijstatic void local_receive (struct recvbuf *); 1741285612Sdelphijstatic int local_input (struct recvbuf *); 1742285612Sdelphij 174354359Srobertostatic bind_t io_bindings[] = 174454359Sroberto{ 174554359Sroberto#ifdef STREAM 174654359Sroberto { 174754359Sroberto "parse STREAM", 174854359Sroberto stream_init, 174954359Sroberto stream_end, 175054359Sroberto stream_setcs, 175154359Sroberto stream_disable, 175254359Sroberto stream_enable, 175354359Sroberto stream_getfmt, 175454359Sroberto stream_setfmt, 175554359Sroberto stream_timecode, 175654359Sroberto stream_receive, 175754359Sroberto 0, 175854359Sroberto }, 175954359Sroberto { 176054359Sroberto "ppsclock STREAM", 176154359Sroberto ppsclock_init, 176254359Sroberto local_end, 176354359Sroberto local_setcs, 176454359Sroberto local_nop, 176554359Sroberto local_nop, 176654359Sroberto local_getfmt, 176754359Sroberto local_setfmt, 176854359Sroberto local_timecode, 176954359Sroberto local_receive, 177054359Sroberto local_input, 177154359Sroberto }, 177254359Sroberto#endif 177354359Sroberto { 177454359Sroberto "normal", 177554359Sroberto local_init, 177654359Sroberto local_end, 177754359Sroberto local_setcs, 177854359Sroberto local_nop, 177954359Sroberto local_nop, 178054359Sroberto local_getfmt, 178154359Sroberto local_setfmt, 178254359Sroberto local_timecode, 178354359Sroberto local_receive, 178454359Sroberto local_input, 178554359Sroberto }, 178654359Sroberto { 178754359Sroberto (char *)0, 1788285612Sdelphij NULL, 1789285612Sdelphij NULL, 1790285612Sdelphij NULL, 1791285612Sdelphij NULL, 1792285612Sdelphij NULL, 1793285612Sdelphij NULL, 1794285612Sdelphij NULL, 1795285612Sdelphij NULL, 1796285612Sdelphij NULL, 1797285612Sdelphij NULL, 179854359Sroberto } 179954359Sroberto}; 180054359Sroberto 180154359Sroberto#ifdef STREAM 180254359Sroberto 180354359Sroberto/*-------------------------------------------------- 180454359Sroberto * ppsclock STREAM init 180554359Sroberto */ 180654359Srobertostatic int 180754359Srobertoppsclock_init( 180854359Sroberto struct parseunit *parse 180954359Sroberto ) 181054359Sroberto{ 181154359Sroberto static char m1[] = "ppsclocd"; 181254359Sroberto static char m2[] = "ppsclock"; 1813285612Sdelphij 181454359Sroberto /* 181554359Sroberto * now push the parse streams module 181654359Sroberto * it will ensure exclusive access to the device 181754359Sroberto */ 1818182007Sroberto if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 && 1819182007Sroberto ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1) 182054359Sroberto { 182154359Sroberto if (errno != EINVAL) 182256746Sroberto { 182356746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 182456746Sroberto CLK_UNIT(parse->peer)); 182554359Sroberto } 182654359Sroberto return 0; 182754359Sroberto } 182854359Sroberto if (!local_init(parse)) 182954359Sroberto { 1830182007Sroberto (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0); 183154359Sroberto return 0; 183254359Sroberto } 183354359Sroberto 183454359Sroberto parse->flags |= PARSE_PPSCLOCK; 183554359Sroberto return 1; 183654359Sroberto} 183754359Sroberto 183854359Sroberto/*-------------------------------------------------- 183954359Sroberto * parse STREAM init 184054359Sroberto */ 184154359Srobertostatic int 184254359Srobertostream_init( 184354359Sroberto struct parseunit *parse 184454359Sroberto ) 184554359Sroberto{ 184654359Sroberto static char m1[] = "parse"; 184754359Sroberto /* 184854359Sroberto * now push the parse streams module 184954359Sroberto * to test whether it is there (neat interface 8-( ) 185054359Sroberto */ 185154359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 185254359Sroberto { 185354359Sroberto if (errno != EINVAL) /* accept non-existence */ 185456746Sroberto { 185556746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 185654359Sroberto } 185754359Sroberto return 0; 185854359Sroberto } 185954359Sroberto else 186054359Sroberto { 186154359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 186254359Sroberto /* empty loop */; 186354359Sroberto 186454359Sroberto /* 186554359Sroberto * now push it a second time after we have removed all 186654359Sroberto * module garbage 186754359Sroberto */ 186854359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 186954359Sroberto { 187054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 187154359Sroberto return 0; 187254359Sroberto } 187354359Sroberto else 187454359Sroberto { 187554359Sroberto return 1; 187654359Sroberto } 187754359Sroberto } 187854359Sroberto} 187954359Sroberto 188054359Sroberto/*-------------------------------------------------- 188154359Sroberto * parse STREAM end 188254359Sroberto */ 188354359Srobertostatic void 188454359Srobertostream_end( 188554359Sroberto struct parseunit *parse 188654359Sroberto ) 188754359Sroberto{ 188854359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 188954359Sroberto /* empty loop */; 189054359Sroberto} 189154359Sroberto 189254359Sroberto/*-------------------------------------------------- 189354359Sroberto * STREAM setcs 189454359Sroberto */ 189554359Srobertostatic int 189654359Srobertostream_setcs( 189754359Sroberto struct parseunit *parse, 189854359Sroberto parsectl_t *tcl 189954359Sroberto ) 190054359Sroberto{ 190154359Sroberto struct strioctl strioc; 1902285612Sdelphij 190354359Sroberto strioc.ic_cmd = PARSEIOC_SETCS; 190454359Sroberto strioc.ic_timout = 0; 190554359Sroberto strioc.ic_dp = (char *)tcl; 190654359Sroberto strioc.ic_len = sizeof (*tcl); 190754359Sroberto 190854359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 190954359Sroberto { 191054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 191154359Sroberto return 0; 191254359Sroberto } 191354359Sroberto return 1; 191454359Sroberto} 191554359Sroberto 191654359Sroberto/*-------------------------------------------------- 191754359Sroberto * STREAM enable 191854359Sroberto */ 191954359Srobertostatic int 192054359Srobertostream_enable( 192154359Sroberto struct parseunit *parse 192254359Sroberto ) 192354359Sroberto{ 192454359Sroberto struct strioctl strioc; 1925285612Sdelphij 192654359Sroberto strioc.ic_cmd = PARSEIOC_ENABLE; 192754359Sroberto strioc.ic_timout = 0; 192854359Sroberto strioc.ic_dp = (char *)0; 192954359Sroberto strioc.ic_len = 0; 193054359Sroberto 193154359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 193254359Sroberto { 193354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 193454359Sroberto return 0; 193554359Sroberto } 193654359Sroberto parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 193754359Sroberto return 1; 193854359Sroberto} 193954359Sroberto 194054359Sroberto/*-------------------------------------------------- 194154359Sroberto * STREAM disable 194254359Sroberto */ 194354359Srobertostatic int 194454359Srobertostream_disable( 194554359Sroberto struct parseunit *parse 194654359Sroberto ) 194754359Sroberto{ 194854359Sroberto struct strioctl strioc; 1949285612Sdelphij 195054359Sroberto strioc.ic_cmd = PARSEIOC_DISABLE; 195154359Sroberto strioc.ic_timout = 0; 195254359Sroberto strioc.ic_dp = (char *)0; 195354359Sroberto strioc.ic_len = 0; 195454359Sroberto 195554359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 195654359Sroberto { 195754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 195854359Sroberto return 0; 195954359Sroberto } 196054359Sroberto parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 196154359Sroberto return 1; 196254359Sroberto} 196354359Sroberto 196454359Sroberto/*-------------------------------------------------- 196554359Sroberto * STREAM getfmt 196654359Sroberto */ 196754359Srobertostatic int 196854359Srobertostream_getfmt( 196954359Sroberto struct parseunit *parse, 197054359Sroberto parsectl_t *tcl 197154359Sroberto ) 197254359Sroberto{ 197354359Sroberto struct strioctl strioc; 1974285612Sdelphij 197554359Sroberto strioc.ic_cmd = PARSEIOC_GETFMT; 197654359Sroberto strioc.ic_timout = 0; 197754359Sroberto strioc.ic_dp = (char *)tcl; 197854359Sroberto strioc.ic_len = sizeof (*tcl); 197954359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 198054359Sroberto { 198154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 198254359Sroberto return 0; 198354359Sroberto } 198454359Sroberto return 1; 198554359Sroberto} 198654359Sroberto 198754359Sroberto/*-------------------------------------------------- 198854359Sroberto * STREAM setfmt 198954359Sroberto */ 199054359Srobertostatic int 199154359Srobertostream_setfmt( 199254359Sroberto struct parseunit *parse, 199354359Sroberto parsectl_t *tcl 199454359Sroberto ) 199554359Sroberto{ 199654359Sroberto struct strioctl strioc; 1997285612Sdelphij 199854359Sroberto strioc.ic_cmd = PARSEIOC_SETFMT; 199954359Sroberto strioc.ic_timout = 0; 200054359Sroberto strioc.ic_dp = (char *)tcl; 200154359Sroberto strioc.ic_len = sizeof (*tcl); 200254359Sroberto 200354359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 200454359Sroberto { 200554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 200654359Sroberto return 0; 200754359Sroberto } 200854359Sroberto return 1; 200954359Sroberto} 201054359Sroberto 201154359Sroberto 201254359Sroberto/*-------------------------------------------------- 201354359Sroberto * STREAM timecode 201454359Sroberto */ 201554359Srobertostatic int 201654359Srobertostream_timecode( 201754359Sroberto struct parseunit *parse, 201854359Sroberto parsectl_t *tcl 201954359Sroberto ) 202054359Sroberto{ 202154359Sroberto struct strioctl strioc; 2022285612Sdelphij 202354359Sroberto strioc.ic_cmd = PARSEIOC_TIMECODE; 202454359Sroberto strioc.ic_timout = 0; 202554359Sroberto strioc.ic_dp = (char *)tcl; 202654359Sroberto strioc.ic_len = sizeof (*tcl); 2027285612Sdelphij 202854359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 202954359Sroberto { 203054359Sroberto ERR(ERR_INTERNAL) 203154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 203254359Sroberto return 0; 203354359Sroberto } 203454359Sroberto clear_err(parse, ERR_INTERNAL); 203554359Sroberto return 1; 203654359Sroberto} 203754359Sroberto 203854359Sroberto/*-------------------------------------------------- 203954359Sroberto * STREAM receive 204054359Sroberto */ 204154359Srobertostatic void 204254359Srobertostream_receive( 204354359Sroberto struct recvbuf *rbufp 204454359Sroberto ) 204554359Sroberto{ 2046285612Sdelphij struct parseunit * parse; 204754359Sroberto parsetime_t parsetime; 204854359Sroberto 2049285612Sdelphij parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 205054359Sroberto if (!parse->peer) 205154359Sroberto return; 205254359Sroberto 205354359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 205454359Sroberto { 205554359Sroberto ERR(ERR_BADIO) 205654359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 205754359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 205854359Sroberto parse_event(parse, CEVNT_BADREPLY); 205954359Sroberto return; 206054359Sroberto } 206154359Sroberto clear_err(parse, ERR_BADIO); 2062285612Sdelphij 206354359Sroberto memmove((caddr_t)&parsetime, 206454359Sroberto (caddr_t)rbufp->recv_buffer, 206554359Sroberto sizeof(parsetime_t)); 206654359Sroberto 206754359Sroberto#ifdef DEBUG 206854359Sroberto if (debug > 3) 206954359Sroberto { 207054359Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 207154359Sroberto CLK_UNIT(parse->peer), 207254359Sroberto (unsigned int)parsetime.parse_status, 207354359Sroberto (unsigned int)parsetime.parse_state, 2074182007Sroberto (unsigned long)parsetime.parse_time.tv.tv_sec, 2075182007Sroberto (unsigned long)parsetime.parse_time.tv.tv_usec, 2076182007Sroberto (unsigned long)parsetime.parse_stime.tv.tv_sec, 2077182007Sroberto (unsigned long)parsetime.parse_stime.tv.tv_usec, 2078182007Sroberto (unsigned long)parsetime.parse_ptime.tv.tv_sec, 2079182007Sroberto (unsigned long)parsetime.parse_ptime.tv.tv_usec); 208054359Sroberto } 208154359Sroberto#endif 208254359Sroberto 208354359Sroberto /* 208454359Sroberto * switch time stamp world - be sure to normalize small usec field 208554359Sroberto * errors. 208654359Sroberto */ 208754359Sroberto 2088285612Sdelphij parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv); 208954359Sroberto 209054359Sroberto if (PARSE_TIMECODE(parsetime.parse_state)) 209154359Sroberto { 2092285612Sdelphij parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv); 209354359Sroberto } 209454359Sroberto 209554359Sroberto if (PARSE_PPS(parsetime.parse_state)) 2096285612Sdelphij { 2097285612Sdelphij parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv); 2098285612Sdelphij } 209954359Sroberto 210054359Sroberto parse_process(parse, &parsetime); 210154359Sroberto} 210254359Sroberto#endif 210354359Sroberto 210454359Sroberto/*-------------------------------------------------- 210554359Sroberto * local init 210654359Sroberto */ 210754359Srobertostatic int 210854359Srobertolocal_init( 210954359Sroberto struct parseunit *parse 211054359Sroberto ) 211154359Sroberto{ 211254359Sroberto return parse_ioinit(&parse->parseio); 211354359Sroberto} 211454359Sroberto 211554359Sroberto/*-------------------------------------------------- 211654359Sroberto * local end 211754359Sroberto */ 211854359Srobertostatic void 211954359Srobertolocal_end( 212054359Sroberto struct parseunit *parse 212154359Sroberto ) 212254359Sroberto{ 212354359Sroberto parse_ioend(&parse->parseio); 212454359Sroberto} 212554359Sroberto 212654359Sroberto 212754359Sroberto/*-------------------------------------------------- 212854359Sroberto * local nop 212954359Sroberto */ 213054359Srobertostatic int 213154359Srobertolocal_nop( 213254359Sroberto struct parseunit *parse 213354359Sroberto ) 213454359Sroberto{ 213554359Sroberto return 1; 213654359Sroberto} 213754359Sroberto 213854359Sroberto/*-------------------------------------------------- 213954359Sroberto * local setcs 214054359Sroberto */ 214154359Srobertostatic int 214254359Srobertolocal_setcs( 214354359Sroberto struct parseunit *parse, 214454359Sroberto parsectl_t *tcl 214554359Sroberto ) 214654359Sroberto{ 214754359Sroberto return parse_setcs(tcl, &parse->parseio); 214854359Sroberto} 214954359Sroberto 215054359Sroberto/*-------------------------------------------------- 215154359Sroberto * local getfmt 215254359Sroberto */ 215354359Srobertostatic int 215454359Srobertolocal_getfmt( 215554359Sroberto struct parseunit *parse, 215654359Sroberto parsectl_t *tcl 215754359Sroberto ) 215854359Sroberto{ 215954359Sroberto return parse_getfmt(tcl, &parse->parseio); 216054359Sroberto} 216154359Sroberto 216254359Sroberto/*-------------------------------------------------- 216354359Sroberto * local setfmt 216454359Sroberto */ 216554359Srobertostatic int 216654359Srobertolocal_setfmt( 216754359Sroberto struct parseunit *parse, 216854359Sroberto parsectl_t *tcl 216954359Sroberto ) 217054359Sroberto{ 217154359Sroberto return parse_setfmt(tcl, &parse->parseio); 217254359Sroberto} 217354359Sroberto 217454359Sroberto/*-------------------------------------------------- 217554359Sroberto * local timecode 217654359Sroberto */ 217754359Srobertostatic int 217854359Srobertolocal_timecode( 217954359Sroberto struct parseunit *parse, 218054359Sroberto parsectl_t *tcl 218154359Sroberto ) 218254359Sroberto{ 218354359Sroberto return parse_timecode(tcl, &parse->parseio); 218454359Sroberto} 218554359Sroberto 218654359Sroberto 218754359Sroberto/*-------------------------------------------------- 218854359Sroberto * local input 218954359Sroberto */ 219054359Srobertostatic int 219154359Srobertolocal_input( 219254359Sroberto struct recvbuf *rbufp 219354359Sroberto ) 219454359Sroberto{ 2195285612Sdelphij struct parseunit * parse; 2196285612Sdelphij 219754359Sroberto int count; 219854359Sroberto unsigned char *s; 219954359Sroberto timestamp_t ts; 220054359Sroberto 2201285612Sdelphij parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 220254359Sroberto if (!parse->peer) 220354359Sroberto return 0; 220454359Sroberto 220554359Sroberto /* 220654359Sroberto * eat all characters, parsing then and feeding complete samples 220754359Sroberto */ 220854359Sroberto count = rbufp->recv_length; 220954359Sroberto s = (unsigned char *)rbufp->recv_buffer; 221054359Sroberto ts.fp = rbufp->recv_time; 221154359Sroberto 221254359Sroberto while (count--) 221354359Sroberto { 221454359Sroberto if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 221554359Sroberto { 2216182007Sroberto struct recvbuf *buf; 221754359Sroberto 221854359Sroberto /* 221954359Sroberto * got something good to eat 222054359Sroberto */ 222154359Sroberto if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 222254359Sroberto { 2223182007Sroberto#ifdef HAVE_PPSAPI 2224182007Sroberto if (parse->flags & PARSE_PPSCLOCK) 2225182007Sroberto { 2226182007Sroberto struct timespec pps_timeout; 2227182007Sroberto pps_info_t pps_info; 2228285612Sdelphij 2229182007Sroberto pps_timeout.tv_sec = 0; 2230182007Sroberto pps_timeout.tv_nsec = 0; 2231182007Sroberto 2232285612Sdelphij if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info, 2233182007Sroberto &pps_timeout) == 0) 2234182007Sroberto { 2235182007Sroberto if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial) 2236182007Sroberto { 2237182007Sroberto double dtemp; 2238182007Sroberto 2239182007Sroberto struct timespec pts; 2240182007Sroberto /* 2241182007Sroberto * add PPS time stamp if available via ppsclock module 2242182007Sroberto * and not supplied already. 2243182007Sroberto */ 2244182007Sroberto if (parse->flags & PARSE_CLEAR) 2245182007Sroberto pts = pps_info.clear_timestamp; 2246182007Sroberto else 2247182007Sroberto pts = pps_info.assert_timestamp; 2248182007Sroberto 2249285612Sdelphij parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970); 2250182007Sroberto 2251285612Sdelphij dtemp = (double) pts.tv_nsec / 1e9; 2252182007Sroberto if (dtemp < 0.) { 2253182007Sroberto dtemp += 1; 2254182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui--; 2255182007Sroberto } 2256182007Sroberto if (dtemp > 1.) { 2257182007Sroberto dtemp -= 1; 2258182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui++; 2259182007Sroberto } 2260285612Sdelphij parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC); 2261182007Sroberto 2262285612Sdelphij parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2263182007Sroberto#ifdef DEBUG 2264182007Sroberto if (debug > 3) 2265182007Sroberto { 2266182007Sroberto printf( 2267301256Sdelphij "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n", 2268301256Sdelphij (long)rbufp->fd, 2269182007Sroberto (long)pps_info.assert_sequence + (long)pps_info.clear_sequence, 2270182007Sroberto lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6)); 2271182007Sroberto } 2272182007Sroberto#endif 2273182007Sroberto } 2274182007Sroberto#ifdef DEBUG 2275182007Sroberto else 2276182007Sroberto { 2277182007Sroberto if (debug > 3) 2278182007Sroberto { 2279182007Sroberto printf( 2280301256Sdelphij "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2281301256Sdelphij (long)rbufp->fd, 2282182007Sroberto (long)pps_info.assert_sequence, (long)pps_info.clear_sequence); 2283182007Sroberto } 2284182007Sroberto } 2285182007Sroberto#endif 2286182007Sroberto parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence; 2287182007Sroberto } 2288182007Sroberto#ifdef DEBUG 2289182007Sroberto else 2290182007Sroberto { 2291182007Sroberto if (debug > 3) 2292182007Sroberto { 2293182007Sroberto printf( 2294301256Sdelphij "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n", 2295301256Sdelphij (long)rbufp->fd, 2296182007Sroberto errno); 2297182007Sroberto } 2298182007Sroberto } 2299182007Sroberto#endif 2300182007Sroberto } 2301182007Sroberto#else 230254359Sroberto#ifdef TIOCDCDTIMESTAMP 230354359Sroberto struct timeval dcd_time; 2304285612Sdelphij 2305182007Sroberto if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 230654359Sroberto { 230754359Sroberto l_fp tstmp; 2308285612Sdelphij 230954359Sroberto TVTOTS(&dcd_time, &tstmp); 231054359Sroberto tstmp.l_ui += JAN_1970; 231154359Sroberto L_SUB(&ts.fp, &tstmp); 231254359Sroberto if (ts.fp.l_ui == 0) 231354359Sroberto { 231454359Sroberto#ifdef DEBUG 231554359Sroberto if (debug) 231654359Sroberto { 231754359Sroberto printf( 231854359Sroberto "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 2319182007Sroberto parse->ppsfd, 232054359Sroberto lfptoa(&tstmp, 6)); 232154359Sroberto printf(" sigio %s\n", 232254359Sroberto lfptoa(&ts.fp, 6)); 232354359Sroberto } 232454359Sroberto#endif 232554359Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 232654359Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 232754359Sroberto } 232854359Sroberto } 232954359Sroberto#else /* TIOCDCDTIMESTAMP */ 233054359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 233154359Sroberto if (parse->flags & PARSE_PPSCLOCK) 2332182007Sroberto { 2333182007Sroberto l_fp tts; 2334182007Sroberto struct ppsclockev ev; 233554359Sroberto 233654359Sroberto#ifdef HAVE_CIOGETEV 2337182007Sroberto if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0) 233854359Sroberto#endif 233954359Sroberto#ifdef HAVE_TIOCGPPSEV 2340182007Sroberto if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0) 234154359Sroberto#endif 234254359Sroberto { 2343182007Sroberto if (ev.serial != parse->ppsserial) 2344182007Sroberto { 2345182007Sroberto /* 2346182007Sroberto * add PPS time stamp if available via ppsclock module 2347182007Sroberto * and not supplied already. 2348182007Sroberto */ 2349182007Sroberto if (!buftvtots((const char *)&ev.tv, &tts)) 235054359Sroberto { 2351182007Sroberto ERR(ERR_BADDATA) 2352182007Sroberto msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 235354359Sroberto } 2354182007Sroberto else 2355182007Sroberto { 2356182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tts; 2357182007Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2358182007Sroberto } 2359182007Sroberto } 2360182007Sroberto parse->ppsserial = ev.serial; 236154359Sroberto } 2362182007Sroberto } 236354359Sroberto#endif 236454359Sroberto#endif /* TIOCDCDTIMESTAMP */ 2365182007Sroberto#endif /* !HAVE_PPSAPI */ 236654359Sroberto } 236754359Sroberto if (count) 236854359Sroberto { /* simulate receive */ 2369182007Sroberto buf = get_free_recv_buffer(); 2370182007Sroberto if (buf != NULL) { 2371182007Sroberto memmove((caddr_t)buf->recv_buffer, 2372182007Sroberto (caddr_t)&parse->parseio.parse_dtime, 2373182007Sroberto sizeof(parsetime_t)); 2374182007Sroberto buf->recv_length = sizeof(parsetime_t); 2375182007Sroberto buf->recv_time = rbufp->recv_time; 2376285612Sdelphij#ifndef HAVE_IO_COMPLETION_PORT 2377182007Sroberto buf->srcadr = rbufp->srcadr; 2378285612Sdelphij#endif 2379182007Sroberto buf->dstadr = rbufp->dstadr; 2380182007Sroberto buf->receiver = rbufp->receiver; 2381182007Sroberto buf->fd = rbufp->fd; 2382182007Sroberto buf->X_from_where = rbufp->X_from_where; 2383285612Sdelphij parse->generic->io.recvcount++; 2384285612Sdelphij packets_received++; 2385182007Sroberto add_full_recv_buffer(buf); 2386285612Sdelphij#ifdef HAVE_IO_COMPLETION_PORT 2387285612Sdelphij SetEvent(WaitableIoEventHandle); 2388285612Sdelphij#endif 2389182007Sroberto } 239054359Sroberto parse_iodone(&parse->parseio); 239154359Sroberto } 239254359Sroberto else 239354359Sroberto { 239456746Sroberto memmove((caddr_t)rbufp->recv_buffer, 239556746Sroberto (caddr_t)&parse->parseio.parse_dtime, 239656746Sroberto sizeof(parsetime_t)); 239756746Sroberto parse_iodone(&parse->parseio); 239854359Sroberto rbufp->recv_length = sizeof(parsetime_t); 239954359Sroberto return 1; /* got something & in place return */ 240054359Sroberto } 240154359Sroberto } 240254359Sroberto } 240354359Sroberto return 0; /* nothing to pass up */ 240454359Sroberto} 240554359Sroberto 240654359Sroberto/*-------------------------------------------------- 240754359Sroberto * local receive 240854359Sroberto */ 240954359Srobertostatic void 241054359Srobertolocal_receive( 241154359Sroberto struct recvbuf *rbufp 241254359Sroberto ) 241354359Sroberto{ 2414285612Sdelphij struct parseunit * parse; 241554359Sroberto parsetime_t parsetime; 241654359Sroberto 2417285612Sdelphij parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 241854359Sroberto if (!parse->peer) 241954359Sroberto return; 242054359Sroberto 242154359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 242254359Sroberto { 242354359Sroberto ERR(ERR_BADIO) 242454359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 242554359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 242654359Sroberto parse_event(parse, CEVNT_BADREPLY); 242754359Sroberto return; 242854359Sroberto } 242954359Sroberto clear_err(parse, ERR_BADIO); 2430285612Sdelphij 243154359Sroberto memmove((caddr_t)&parsetime, 243254359Sroberto (caddr_t)rbufp->recv_buffer, 243354359Sroberto sizeof(parsetime_t)); 243454359Sroberto 243554359Sroberto#ifdef DEBUG 243654359Sroberto if (debug > 3) 243754359Sroberto { 2438182007Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n", 243954359Sroberto CLK_UNIT(parse->peer), 244054359Sroberto (unsigned int)parsetime.parse_status, 244154359Sroberto (unsigned int)parsetime.parse_state, 2442182007Sroberto (unsigned long)parsetime.parse_time.fp.l_ui, 2443182007Sroberto (unsigned long)parsetime.parse_time.fp.l_uf, 2444182007Sroberto (unsigned long)parsetime.parse_stime.fp.l_ui, 2445182007Sroberto (unsigned long)parsetime.parse_stime.fp.l_uf, 2446182007Sroberto (unsigned long)parsetime.parse_ptime.fp.l_ui, 2447182007Sroberto (unsigned long)parsetime.parse_ptime.fp.l_uf); 244854359Sroberto } 244954359Sroberto#endif 245054359Sroberto 245154359Sroberto parse_process(parse, &parsetime); 245254359Sroberto} 245354359Sroberto 245454359Sroberto/*-------------------------------------------------- 245554359Sroberto * init_iobinding - find and initialize lower layers 245654359Sroberto */ 245754359Srobertostatic bind_t * 245854359Srobertoinit_iobinding( 245954359Sroberto struct parseunit *parse 246054359Sroberto ) 246154359Sroberto{ 246254359Sroberto bind_t *b = io_bindings; 246354359Sroberto 246454359Sroberto while (b->bd_description != (char *)0) 246554359Sroberto { 246654359Sroberto if ((*b->bd_init)(parse)) 246754359Sroberto { 246854359Sroberto return b; 246954359Sroberto } 247054359Sroberto b++; 247154359Sroberto } 247254359Sroberto return (bind_t *)0; 247354359Sroberto} 247454359Sroberto 247554359Sroberto/**=========================================================================== 247654359Sroberto ** support routines 247754359Sroberto **/ 247854359Sroberto 2479285612Sdelphijstatic NTP_PRINTF(4, 5) char * 2480285612Sdelphijap(char *buffer, size_t len, char *pos, const char *fmt, ...) 2481285612Sdelphij{ 2482285612Sdelphij va_list va; 2483285612Sdelphij int l; 2484285612Sdelphij size_t rem = len - (pos - buffer); 2485285612Sdelphij 2486285612Sdelphij if (rem == 0) 2487285612Sdelphij return pos; 2488285612Sdelphij 2489285612Sdelphij va_start(va, fmt); 2490285612Sdelphij l = vsnprintf(pos, rem, fmt, va); 2491285612Sdelphij va_end(va); 2492285612Sdelphij 2493285612Sdelphij if (l != -1) { 2494285612Sdelphij rem--; 2495285612Sdelphij if (rem >= (size_t)l) 2496285612Sdelphij pos += l; 2497285612Sdelphij else 2498285612Sdelphij pos += rem; 2499285612Sdelphij } 2500285612Sdelphij 2501285612Sdelphij return pos; 2502285612Sdelphij} 2503285612Sdelphij 250454359Sroberto/*-------------------------------------------------- 250554359Sroberto * convert a flag field to a string 250654359Sroberto */ 250754359Srobertostatic char * 250854359Srobertoparsestate( 250954359Sroberto u_long lstate, 2510182007Sroberto char *buffer, 2511182007Sroberto int size 251254359Sroberto ) 251354359Sroberto{ 251454359Sroberto static struct bits 251554359Sroberto { 251654359Sroberto u_long bit; 251754359Sroberto const char *name; 251854359Sroberto } flagstrings[] = 251954359Sroberto { 252056746Sroberto { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 252156746Sroberto { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 252256746Sroberto { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 252356746Sroberto { PARSEB_DST, "DST" }, 252456746Sroberto { PARSEB_UTC, "UTC DISPLAY" }, 252556746Sroberto { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 252656746Sroberto { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 252754359Sroberto { PARSEB_LEAPSECOND, "LEAP SECOND" }, 2528285612Sdelphij { PARSEB_CALLBIT, "CALL BIT" }, 252956746Sroberto { PARSEB_TIMECODE, "TIME CODE" }, 253056746Sroberto { PARSEB_PPS, "PPS" }, 253156746Sroberto { PARSEB_POSITION, "POSITION" }, 2532285612Sdelphij { 0, NULL } 253354359Sroberto }; 253454359Sroberto 253554359Sroberto static struct sbits 253654359Sroberto { 253754359Sroberto u_long bit; 253854359Sroberto const char *name; 253954359Sroberto } sflagstrings[] = 254054359Sroberto { 254154359Sroberto { PARSEB_S_LEAP, "LEAP INDICATION" }, 254254359Sroberto { PARSEB_S_PPS, "PPS SIGNAL" }, 2543285612Sdelphij { PARSEB_S_CALLBIT, "CALLBIT" }, 254454359Sroberto { PARSEB_S_POSITION, "POSITION" }, 2545285612Sdelphij { 0, NULL } 254654359Sroberto }; 254754359Sroberto int i; 2548182007Sroberto char *s, *t; 254954359Sroberto 255054359Sroberto *buffer = '\0'; 2551182007Sroberto s = t = buffer; 255254359Sroberto 255354359Sroberto i = 0; 255454359Sroberto while (flagstrings[i].bit) 255554359Sroberto { 255654359Sroberto if (flagstrings[i].bit & lstate) 255754359Sroberto { 2558182007Sroberto if (s != t) 2559285612Sdelphij t = ap(buffer, size, t, "; "); 2560285612Sdelphij t = ap(buffer, size, t, "%s", flagstrings[i].name); 256154359Sroberto } 256254359Sroberto i++; 256354359Sroberto } 256454359Sroberto 2565285612Sdelphij if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION)) 256654359Sroberto { 2567182007Sroberto if (s != t) 2568285612Sdelphij t = ap(buffer, size, t, "; "); 256954359Sroberto 2570285612Sdelphij t = ap(buffer, size, t, "("); 257154359Sroberto 2572285612Sdelphij s = t; 257354359Sroberto 257454359Sroberto i = 0; 257554359Sroberto while (sflagstrings[i].bit) 257654359Sroberto { 257754359Sroberto if (sflagstrings[i].bit & lstate) 257854359Sroberto { 257954359Sroberto if (t != s) 258054359Sroberto { 2581285612Sdelphij t = ap(buffer, size, t, "; "); 258254359Sroberto } 2583285612Sdelphij 2584285612Sdelphij t = ap(buffer, size, t, "%s", 2585285612Sdelphij sflagstrings[i].name); 258654359Sroberto } 258754359Sroberto i++; 258854359Sroberto } 2589285612Sdelphij t = ap(buffer, size, t, ")"); 2590289997Sglebius /* t is unused here, but if we don't track it and 2591289997Sglebius * need it later, that's a bug waiting to happen. 2592289997Sglebius */ 259354359Sroberto } 259454359Sroberto return buffer; 259554359Sroberto} 259654359Sroberto 259754359Sroberto/*-------------------------------------------------- 259854359Sroberto * convert a status flag field to a string 259954359Sroberto */ 260054359Srobertostatic char * 260154359Srobertoparsestatus( 260254359Sroberto u_long lstate, 2603182007Sroberto char *buffer, 2604182007Sroberto int size 260554359Sroberto ) 260654359Sroberto{ 260754359Sroberto static struct bits 260854359Sroberto { 260954359Sroberto u_long bit; 261054359Sroberto const char *name; 261154359Sroberto } flagstrings[] = 261254359Sroberto { 261354359Sroberto { CVT_OK, "CONVERSION SUCCESSFUL" }, 261454359Sroberto { CVT_NONE, "NO CONVERSION" }, 261554359Sroberto { CVT_FAIL, "CONVERSION FAILED" }, 261654359Sroberto { CVT_BADFMT, "ILLEGAL FORMAT" }, 261754359Sroberto { CVT_BADDATE, "DATE ILLEGAL" }, 261854359Sroberto { CVT_BADTIME, "TIME ILLEGAL" }, 261954359Sroberto { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 2620285612Sdelphij { 0, NULL } 262154359Sroberto }; 262254359Sroberto int i; 2623285612Sdelphij char *t; 262454359Sroberto 2625285612Sdelphij t = buffer; 262654359Sroberto *buffer = '\0'; 262754359Sroberto 262854359Sroberto i = 0; 262954359Sroberto while (flagstrings[i].bit) 263054359Sroberto { 263154359Sroberto if (flagstrings[i].bit & lstate) 263254359Sroberto { 2633285612Sdelphij if (t != buffer) 2634285612Sdelphij t = ap(buffer, size, t, "; "); 2635285612Sdelphij t = ap(buffer, size, t, "%s", flagstrings[i].name); 263654359Sroberto } 263754359Sroberto i++; 263854359Sroberto } 263954359Sroberto 264054359Sroberto return buffer; 264154359Sroberto} 264254359Sroberto 264354359Sroberto/*-------------------------------------------------- 264454359Sroberto * convert a clock status flag field to a string 264554359Sroberto */ 264654359Srobertostatic const char * 264754359Srobertoclockstatus( 264854359Sroberto u_long lstate 264954359Sroberto ) 265054359Sroberto{ 265154359Sroberto static char buffer[20]; 265254359Sroberto static struct status 265354359Sroberto { 265454359Sroberto u_long value; 265554359Sroberto const char *name; 265654359Sroberto } flagstrings[] = 265754359Sroberto { 265854359Sroberto { CEVNT_NOMINAL, "NOMINAL" }, 265954359Sroberto { CEVNT_TIMEOUT, "NO RESPONSE" }, 266054359Sroberto { CEVNT_BADREPLY,"BAD FORMAT" }, 266154359Sroberto { CEVNT_FAULT, "FAULT" }, 266254359Sroberto { CEVNT_PROP, "PROPAGATION DELAY" }, 266354359Sroberto { CEVNT_BADDATE, "ILLEGAL DATE" }, 266454359Sroberto { CEVNT_BADTIME, "ILLEGAL TIME" }, 2665285612Sdelphij { (unsigned)~0L, NULL } 266654359Sroberto }; 266754359Sroberto int i; 266854359Sroberto 266954359Sroberto i = 0; 2670285612Sdelphij while (flagstrings[i].value != (u_int)~0) 267154359Sroberto { 267254359Sroberto if (flagstrings[i].value == lstate) 267354359Sroberto { 267454359Sroberto return flagstrings[i].name; 267554359Sroberto } 267654359Sroberto i++; 267754359Sroberto } 267854359Sroberto 2679182007Sroberto snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate); 268054359Sroberto 268154359Sroberto return buffer; 268254359Sroberto} 268354359Sroberto 268454359Sroberto 268554359Sroberto/*-------------------------------------------------- 268654359Sroberto * l_mktime - make representation of a relative time 268754359Sroberto */ 268854359Srobertostatic char * 268954359Srobertol_mktime( 269054359Sroberto u_long delta 269154359Sroberto ) 269254359Sroberto{ 269354359Sroberto u_long tmp, m, s; 269454359Sroberto static char buffer[40]; 2695182007Sroberto char *t; 269654359Sroberto 269754359Sroberto buffer[0] = '\0'; 2698285612Sdelphij t = buffer; 269954359Sroberto 270054359Sroberto if ((tmp = delta / (60*60*24)) != 0) 270154359Sroberto { 2702285612Sdelphij t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp); 270354359Sroberto delta -= tmp * 60*60*24; 270454359Sroberto } 270554359Sroberto 270654359Sroberto s = delta % 60; 270754359Sroberto delta /= 60; 270854359Sroberto m = delta % 60; 270954359Sroberto delta /= 60; 271054359Sroberto 2711285612Sdelphij t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d", 2712285612Sdelphij (int)delta, (int)m, (int)s); 271354359Sroberto 271454359Sroberto return buffer; 271554359Sroberto} 271654359Sroberto 271754359Sroberto 271854359Sroberto/*-------------------------------------------------- 271954359Sroberto * parse_statistics - list summary of clock states 272054359Sroberto */ 272154359Srobertostatic void 272254359Srobertoparse_statistics( 272354359Sroberto struct parseunit *parse 272454359Sroberto ) 272554359Sroberto{ 272654359Sroberto int i; 272754359Sroberto 272854359Sroberto NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 272954359Sroberto { 273054359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 273154359Sroberto CLK_UNIT(parse->peer), 273254359Sroberto l_mktime(current_time - parse->generic->timestarted)); 273354359Sroberto 273454359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 273554359Sroberto CLK_UNIT(parse->peer), 273654359Sroberto clockstatus(parse->generic->currentstatus)); 273754359Sroberto 273854359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 273954359Sroberto { 274054359Sroberto u_long s_time; 274154359Sroberto u_long percent, d = current_time - parse->generic->timestarted; 274254359Sroberto 274354359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 274454359Sroberto 274554359Sroberto while (((u_long)(~0) / 10000) < percent) 274654359Sroberto { 274754359Sroberto percent /= 10; 274854359Sroberto d /= 10; 274954359Sroberto } 275054359Sroberto 275154359Sroberto if (d) 275254359Sroberto percent = (percent * 10000) / d; 275354359Sroberto else 275454359Sroberto percent = 10000; 275554359Sroberto 275654359Sroberto if (s_time) 275754359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 275854359Sroberto CLK_UNIT(parse->peer), 275954359Sroberto clockstatus((unsigned int)i), 276054359Sroberto l_mktime(s_time), 276154359Sroberto percent / 100, percent % 100); 276254359Sroberto } 276354359Sroberto } 276454359Sroberto} 276554359Sroberto 276654359Sroberto/*-------------------------------------------------- 276754359Sroberto * cparse_statistics - wrapper for statistics call 276854359Sroberto */ 276954359Srobertostatic void 277054359Srobertocparse_statistics( 2771182007Sroberto struct parseunit *parse 277254359Sroberto ) 277354359Sroberto{ 277454359Sroberto if (parse->laststatistic + PARSESTATISTICS < current_time) 277554359Sroberto parse_statistics(parse); 277654359Sroberto parse->laststatistic = current_time; 277754359Sroberto} 277854359Sroberto 277954359Sroberto/**=========================================================================== 278054359Sroberto ** ntp interface routines 278154359Sroberto **/ 278254359Sroberto 278354359Sroberto/*-------------------------------------------------- 278454359Sroberto * parse_shutdown - shut down a PARSE clock 278554359Sroberto */ 278654359Srobertostatic void 278754359Srobertoparse_shutdown( 278854359Sroberto int unit, 278954359Sroberto struct peer *peer 279054359Sroberto ) 279154359Sroberto{ 2792285612Sdelphij struct parseunit *parse = NULL; 279354359Sroberto 2794182007Sroberto if (peer && peer->procptr) 2795285612Sdelphij parse = peer->procptr->unitptr; 2796182007Sroberto 2797182007Sroberto if (!parse) 279854359Sroberto { 2799182007Sroberto /* nothing to clean up */ 280054359Sroberto return; 280154359Sroberto } 280254359Sroberto 2803285612Sdelphij if (!parse->peer) 2804182007Sroberto { 2805182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit); 2806182007Sroberto return; 2807182007Sroberto } 2808182007Sroberto 2809182007Sroberto#ifdef HAVE_PPSAPI 2810182007Sroberto if (parse->flags & PARSE_PPSCLOCK) 2811182007Sroberto { 2812285612Sdelphij (void)time_pps_destroy(parse->atom.handle); 2813182007Sroberto } 2814182007Sroberto#endif 2815182007Sroberto if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2816285612Sdelphij (void)closeserial(parse->ppsfd); /* close separate PPS source */ 2817182007Sroberto 281854359Sroberto /* 281954359Sroberto * print statistics a last time and 282054359Sroberto * stop statistics machine 282154359Sroberto */ 282254359Sroberto parse_statistics(parse); 282354359Sroberto 282454359Sroberto if (parse->parse_type->cl_end) 282554359Sroberto { 282654359Sroberto parse->parse_type->cl_end(parse); 282754359Sroberto } 2828285612Sdelphij 2829182007Sroberto /* 2830182007Sroberto * cleanup before leaving this world 2831182007Sroberto */ 283254359Sroberto if (parse->binding) 283354359Sroberto PARSE_END(parse); 283454359Sroberto 283554359Sroberto /* 283654359Sroberto * Tell the I/O module to turn us off. We're history. 283754359Sroberto */ 283854359Sroberto io_closeclock(&parse->generic->io); 283954359Sroberto 284054359Sroberto free_varlist(parse->kv); 2841285612Sdelphij 284254359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 284354359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 284454359Sroberto CLK_UNIT(parse->peer), parse->parse_type->cl_description); 284554359Sroberto 284654359Sroberto parse->peer = (struct peer *)0; /* unused now */ 2847182007Sroberto peer->procptr->unitptr = (caddr_t)0; 284854359Sroberto free(parse); 284954359Sroberto} 285054359Sroberto 2851182007Sroberto#ifdef HAVE_PPSAPI 2852182007Sroberto/*---------------------------------------- 2853182007Sroberto * set up HARDPPS via PPSAPI 2854182007Sroberto */ 2855182007Srobertostatic void 2856182007Srobertoparse_hardpps( 2857182007Sroberto struct parseunit *parse, 2858182007Sroberto int mode 2859182007Sroberto ) 2860182007Sroberto{ 2861182007Sroberto if (parse->hardppsstate == mode) 2862182007Sroberto return; 2863182007Sroberto 2864182007Sroberto if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) { 2865182007Sroberto int i = 0; 2866182007Sroberto 2867285612Sdelphij if (mode == PARSE_HARDPPS_ENABLE) 2868182007Sroberto { 2869182007Sroberto if (parse->flags & PARSE_CLEAR) 2870182007Sroberto i = PPS_CAPTURECLEAR; 2871182007Sroberto else 2872182007Sroberto i = PPS_CAPTUREASSERT; 2873182007Sroberto } 2874285612Sdelphij 2875285612Sdelphij if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i, 2876182007Sroberto PPS_TSFMT_TSPEC) < 0) { 2877182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m", 2878182007Sroberto CLK_UNIT(parse->peer)); 2879182007Sroberto } else { 2880182007Sroberto NLOG(NLOG_CLOCKINFO) 2881182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled", 2882182007Sroberto CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis"); 2883182007Sroberto /* 2884182007Sroberto * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS 2885182007Sroberto */ 2886182007Sroberto if (mode == PARSE_HARDPPS_ENABLE) 2887285612Sdelphij hardpps_enable = 1; 2888182007Sroberto } 2889182007Sroberto } 2890182007Sroberto 2891182007Sroberto parse->hardppsstate = mode; 2892182007Sroberto} 2893182007Sroberto 2894182007Sroberto/*---------------------------------------- 2895182007Sroberto * set up PPS via PPSAPI 2896182007Sroberto */ 2897182007Srobertostatic int 2898182007Srobertoparse_ppsapi( 2899182007Sroberto struct parseunit *parse 2900182007Sroberto ) 2901182007Sroberto{ 2902285612Sdelphij int cap, mode_ppsoffset; 2903285612Sdelphij const char *cp; 2904182007Sroberto 2905285612Sdelphij parse->flags &= (u_char) (~PARSE_PPSCLOCK); 2906285612Sdelphij 2907285612Sdelphij /* 2908285612Sdelphij * collect PPSAPI offset capability - should move into generic handling 2909285612Sdelphij */ 2910285612Sdelphij if (time_pps_getcap(parse->atom.handle, &cap) < 0) { 2911182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m", 2912182007Sroberto CLK_UNIT(parse->peer)); 2913285612Sdelphij 2914182007Sroberto return 0; 2915182007Sroberto } 2916182007Sroberto 2917285612Sdelphij /* 2918285612Sdelphij * initialize generic PPSAPI interface 2919285612Sdelphij * 2920285612Sdelphij * we leave out CLK_FLAG3 as time_pps_kcbind() 2921285612Sdelphij * is handled here for now. Ideally this should also 2922285612Sdelphij * be part of the generic PPSAPI interface 2923285612Sdelphij */ 2924285612Sdelphij if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom)) 2925182007Sroberto return 0; 2926182007Sroberto 2927182007Sroberto /* nb. only turn things on, if someone else has turned something 2928182007Sroberto * on before we get here, leave it alone! 2929182007Sroberto */ 2930182007Sroberto 2931182007Sroberto if (parse->flags & PARSE_CLEAR) { 2932182007Sroberto cp = "CLEAR"; 2933285612Sdelphij mode_ppsoffset = PPS_OFFSETCLEAR; 2934182007Sroberto } else { 2935182007Sroberto cp = "ASSERT"; 2936285612Sdelphij mode_ppsoffset = PPS_OFFSETASSERT; 2937182007Sroberto } 2938182007Sroberto 2939182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2940182007Sroberto CLK_UNIT(parse->peer), cp); 2941182007Sroberto 2942285612Sdelphij if (!(mode_ppsoffset & cap)) { 2943182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)", 2944182007Sroberto CLK_UNIT(parse->peer), cp, cap); 2945285612Sdelphij mode_ppsoffset = 0; 2946182007Sroberto } else { 2947285612Sdelphij if (mode_ppsoffset == PPS_OFFSETCLEAR) 2948285612Sdelphij { 2949285612Sdelphij parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2950285612Sdelphij parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2951182007Sroberto } 2952285612Sdelphij 2953285612Sdelphij if (mode_ppsoffset == PPS_OFFSETASSERT) 2954285612Sdelphij { 2955285612Sdelphij parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2956285612Sdelphij parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2957182007Sroberto } 2958182007Sroberto } 2959182007Sroberto 2960285612Sdelphij parse->atom.pps_params.mode |= mode_ppsoffset; 2961182007Sroberto 2962285612Sdelphij if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) { 2963182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m", 2964182007Sroberto CLK_UNIT(parse->peer)); 2965182007Sroberto return 0; 2966182007Sroberto } 2967182007Sroberto 2968182007Sroberto parse->flags |= PARSE_PPSCLOCK; 2969182007Sroberto return 1; 2970182007Sroberto} 2971182007Sroberto#else 2972182007Sroberto#define parse_hardpps(_PARSE_, _MODE_) /* empty */ 2973182007Sroberto#endif 2974182007Sroberto 297554359Sroberto/*-------------------------------------------------- 297654359Sroberto * parse_start - open the PARSE devices and initialize data for processing 297754359Sroberto */ 297854359Srobertostatic int 297954359Srobertoparse_start( 298054359Sroberto int sysunit, 298154359Sroberto struct peer *peer 298254359Sroberto ) 298354359Sroberto{ 298454359Sroberto u_int unit; 298554359Sroberto int fd232; 298654359Sroberto#ifdef HAVE_TERMIOS 298754359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 298854359Sroberto#endif 298954359Sroberto#ifdef HAVE_SYSV_TTYS 299054359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 299154359Sroberto#endif 299254359Sroberto struct parseunit * parse; 299354359Sroberto char parsedev[sizeof(PARSEDEVICE)+20]; 2994182007Sroberto char parseppsdev[sizeof(PARSEPPSDEVICE)+20]; 299554359Sroberto parsectl_t tmp_ctl; 299654359Sroberto u_int type; 299754359Sroberto 2998182007Sroberto /* 2999182007Sroberto * get out Copyright information once 3000182007Sroberto */ 3001182007Sroberto if (!notice) 3002182007Sroberto { 3003182007Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 3004285612Sdelphij msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2015, Frank Kardel"); 3005182007Sroberto notice = 1; 3006182007Sroberto } 3007182007Sroberto 300854359Sroberto type = CLK_TYPE(peer); 300954359Sroberto unit = CLK_UNIT(peer); 301054359Sroberto 3011285612Sdelphij if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0)) 301254359Sroberto { 301354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 301454359Sroberto unit, CLK_REALTYPE(peer), ncltypes-1); 301554359Sroberto return 0; 301654359Sroberto } 301754359Sroberto 301854359Sroberto /* 301954359Sroberto * Unit okay, attempt to open the device. 302054359Sroberto */ 3021182007Sroberto (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit); 3022182007Sroberto (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit); 302354359Sroberto 302454359Sroberto#ifndef O_NOCTTY 302554359Sroberto#define O_NOCTTY 0 302654359Sroberto#endif 3027285612Sdelphij#ifndef O_NONBLOCK 3028285612Sdelphij#define O_NONBLOCK 0 302954359Sroberto#endif 303054359Sroberto 3031285612Sdelphij fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3032285612Sdelphij 303354359Sroberto if (fd232 == -1) 303454359Sroberto { 303554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 303654359Sroberto return 0; 303754359Sroberto } 303854359Sroberto 3039285612Sdelphij parse = emalloc_zero(sizeof(*parse)); 304054359Sroberto 304154359Sroberto parse->generic = peer->procptr; /* link up */ 304254359Sroberto parse->generic->unitptr = (caddr_t)parse; /* link down */ 304354359Sroberto 304454359Sroberto /* 304554359Sroberto * Set up the structures 304654359Sroberto */ 304754359Sroberto parse->generic->timestarted = current_time; 304854359Sroberto parse->lastchange = current_time; 304954359Sroberto 305054359Sroberto parse->flags = 0; 305154359Sroberto parse->pollneeddata = 0; 305254359Sroberto parse->laststatistic = current_time; 305354359Sroberto parse->lastformat = (unsigned short)~0; /* assume no format known */ 3054182007Sroberto parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 305554359Sroberto parse->lastmissed = 0; /* assume got everything */ 305654359Sroberto parse->ppsserial = 0; 3057182007Sroberto parse->ppsfd = -1; 305854359Sroberto parse->localdata = (void *)0; 305954359Sroberto parse->localstate = 0; 306054359Sroberto parse->kv = (struct ctl_var *)0; 306154359Sroberto 306254359Sroberto clear_err(parse, ERR_ALL); 3063285612Sdelphij 306454359Sroberto parse->parse_type = &parse_clockinfo[type]; 3065285612Sdelphij 3066182007Sroberto parse->maxunsync = parse->parse_type->cl_maxunsync; 3067182007Sroberto 306854359Sroberto parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 306954359Sroberto 307054359Sroberto parse->generic->fudgetime2 = 0.0; 3071182007Sroberto parse->ppsphaseadjust = parse->generic->fudgetime2; 307254359Sroberto 3073182007Sroberto parse->generic->clockdesc = parse->parse_type->cl_description; 307454359Sroberto 307554359Sroberto peer->rootdelay = parse->parse_type->cl_rootdelay; 307654359Sroberto peer->sstclktype = parse->parse_type->cl_type; 307754359Sroberto peer->precision = sys_precision; 3078285612Sdelphij 307954359Sroberto peer->stratum = STRATUM_REFCLOCK; 3080182007Sroberto 308154359Sroberto if (peer->stratum <= 1) 308254359Sroberto memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 308354359Sroberto else 308454359Sroberto parse->generic->refid = htonl(PARSEHSREFID); 3085285612Sdelphij 308654359Sroberto parse->generic->io.fd = fd232; 3087285612Sdelphij 308854359Sroberto parse->peer = peer; /* marks it also as busy */ 308954359Sroberto 309054359Sroberto /* 309154359Sroberto * configure terminal line 309254359Sroberto */ 309354359Sroberto if (TTY_GETATTR(fd232, &tio) == -1) 309454359Sroberto { 309554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 309654359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 309754359Sroberto return 0; 309854359Sroberto } 309954359Sroberto else 310054359Sroberto { 310154359Sroberto#ifndef _PC_VDISABLE 310254359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 310354359Sroberto#else 310454359Sroberto int disablec; 310554359Sroberto errno = 0; /* pathconf can deliver -1 without changing errno ! */ 310654359Sroberto 310754359Sroberto disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 310854359Sroberto if (disablec == -1 && errno) 310954359Sroberto { 311054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 311154359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 311254359Sroberto } 311354359Sroberto else 311454359Sroberto if (disablec != -1) 311554359Sroberto memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 311654359Sroberto#endif 311754359Sroberto 311854359Sroberto#if defined (VMIN) || defined(VTIME) 311954359Sroberto if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 312054359Sroberto { 312154359Sroberto#ifdef VMIN 312254359Sroberto tio.c_cc[VMIN] = 1; 312354359Sroberto#endif 312454359Sroberto#ifdef VTIME 312554359Sroberto tio.c_cc[VTIME] = 0; 312654359Sroberto#endif 312754359Sroberto } 312854359Sroberto#endif 312954359Sroberto 3130285612Sdelphij tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag; 3131285612Sdelphij tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag; 3132285612Sdelphij tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag; 3133285612Sdelphij tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag; 313454359Sroberto 3135285612Sdelphij 313654359Sroberto#ifdef HAVE_TERMIOS 3137285612Sdelphij if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) || 3138285612Sdelphij (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1)) 313954359Sroberto { 314054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 314154359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 314254359Sroberto return 0; 314354359Sroberto } 314454359Sroberto#else 314554359Sroberto tio.c_cflag |= parse_clockinfo[type].cl_speed; 314654359Sroberto#endif 314754359Sroberto 3148182007Sroberto /* 3149182007Sroberto * set up pps device 3150182007Sroberto * if the PARSEPPSDEVICE can be opened that will be used 3151182007Sroberto * for PPS else PARSEDEVICE will be used 3152182007Sroberto */ 3153285612Sdelphij parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3154182007Sroberto 3155182007Sroberto if (parse->ppsfd == -1) 3156182007Sroberto { 3157182007Sroberto parse->ppsfd = fd232; 3158182007Sroberto } 3159182007Sroberto 3160182007Sroberto/* 3161182007Sroberto * Linux PPS - the old way 3162182007Sroberto */ 316354359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 316454359Sroberto { 3165182007Sroberto struct serial_struct ss; 3166182007Sroberto if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 || 3167182007Sroberto ( 316854359Sroberto#ifdef ASYNC_LOW_LATENCY 3169182007Sroberto ss.flags |= ASYNC_LOW_LATENCY, 317054359Sroberto#endif 3171182007Sroberto#ifndef HAVE_PPSAPI 317254359Sroberto#ifdef ASYNC_PPS_CD_NEG 3173182007Sroberto ss.flags |= ASYNC_PPS_CD_NEG, 317454359Sroberto#endif 3175182007Sroberto#endif 3176182007Sroberto ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) { 3177182007Sroberto msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd); 3178182007Sroberto msyslog(LOG_NOTICE, 3179182007Sroberto "refclock_parse: optional PPS processing not available"); 3180182007Sroberto } else { 3181182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3182182007Sroberto#ifdef ASYNC_PPS_CD_NEG 3183182007Sroberto NLOG(NLOG_CLOCKINFO) 3184182007Sroberto msyslog(LOG_INFO, 3185182007Sroberto "refclock_parse: PPS detection on"); 3186182007Sroberto#endif 3187182007Sroberto } 318854359Sroberto } 318954359Sroberto#endif 3190182007Sroberto 3191182007Sroberto/* 3192182007Sroberto * SUN the Solaris way 3193182007Sroberto */ 319454359Sroberto#ifdef HAVE_TIOCSPPS /* SUN PPS support */ 319554359Sroberto if (CLK_PPS(parse->peer)) 3196182007Sroberto { 3197182007Sroberto int i = 1; 3198285612Sdelphij 3199182007Sroberto if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0) 3200182007Sroberto { 3201182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3202182007Sroberto } 3203182007Sroberto } 320454359Sroberto#endif 320554359Sroberto 3206182007Sroberto/* 3207182007Sroberto * PPS via PPSAPI 3208182007Sroberto */ 3209182007Sroberto#if defined(HAVE_PPSAPI) 3210182007Sroberto parse->hardppsstate = PARSE_HARDPPS_DISABLE; 3211182007Sroberto if (CLK_PPS(parse->peer)) 3212182007Sroberto { 3213285612Sdelphij if (!refclock_ppsapi(parse->ppsfd, &parse->atom)) 3214182007Sroberto { 3215182007Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer)); 3216182007Sroberto } 3217182007Sroberto else 3218182007Sroberto { 3219182007Sroberto parse_ppsapi(parse); 3220182007Sroberto } 3221182007Sroberto } 3222182007Sroberto#endif 3223182007Sroberto 322454359Sroberto if (TTY_SETATTR(fd232, &tio) == -1) 322554359Sroberto { 322654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 322754359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 322854359Sroberto return 0; 322954359Sroberto } 323054359Sroberto } 323154359Sroberto 323254359Sroberto /* 3233182007Sroberto * pick correct input machine 323454359Sroberto */ 3235285612Sdelphij parse->generic->io.srcclock = peer; 323654359Sroberto parse->generic->io.datalen = 0; 3237285612Sdelphij 323854359Sroberto parse->binding = init_iobinding(parse); 323954359Sroberto 324054359Sroberto if (parse->binding == (bind_t *)0) 324154359Sroberto { 324254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 324354359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 324454359Sroberto return 0; /* well, ok - special initialisation broke */ 3245285612Sdelphij } 324654359Sroberto 3247182007Sroberto parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 3248182007Sroberto parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 3249182007Sroberto 325054359Sroberto /* 325154359Sroberto * as we always(?) get 8 bit chars we want to be 325254359Sroberto * sure, that the upper bits are zero for less 325354359Sroberto * than 8 bit I/O - so we pass that information on. 325454359Sroberto * note that there can be only one bit count format 325554359Sroberto * per file descriptor 325654359Sroberto */ 325754359Sroberto 325854359Sroberto switch (tio.c_cflag & CSIZE) 325954359Sroberto { 326054359Sroberto case CS5: 326154359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 326254359Sroberto break; 326354359Sroberto 326454359Sroberto case CS6: 326554359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 326654359Sroberto break; 326754359Sroberto 326854359Sroberto case CS7: 326954359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 327054359Sroberto break; 327154359Sroberto 327254359Sroberto case CS8: 327354359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 327454359Sroberto break; 327554359Sroberto } 327654359Sroberto 327754359Sroberto if (!PARSE_SETCS(parse, &tmp_ctl)) 327854359Sroberto { 327954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 328054359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 328154359Sroberto return 0; /* well, ok - special initialisation broke */ 328254359Sroberto } 328354359Sroberto 3284285612Sdelphij strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 3285285612Sdelphij tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer); 3286285612Sdelphij 328754359Sroberto if (!PARSE_SETFMT(parse, &tmp_ctl)) 328854359Sroberto { 328954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 329054359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 329154359Sroberto return 0; /* well, ok - special initialisation broke */ 329254359Sroberto } 3293285612Sdelphij 329454359Sroberto /* 329554359Sroberto * get rid of all IO accumulated so far 329654359Sroberto */ 329754359Sroberto#ifdef HAVE_TERMIOS 329854359Sroberto (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 329954359Sroberto#else 3300182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH) 330154359Sroberto { 330254359Sroberto int flshcmd = TCIOFLUSH; 330354359Sroberto 330454359Sroberto (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 330554359Sroberto } 330654359Sroberto#endif 330754359Sroberto#endif 330856746Sroberto 330954359Sroberto /* 331054359Sroberto * try to do any special initializations 331154359Sroberto */ 331254359Sroberto if (parse->parse_type->cl_init) 331354359Sroberto { 331454359Sroberto if (parse->parse_type->cl_init(parse)) 331554359Sroberto { 331654359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 331754359Sroberto return 0; /* well, ok - special initialisation broke */ 331854359Sroberto } 331954359Sroberto } 3320285612Sdelphij 332154359Sroberto /* 3322182007Sroberto * Insert in async io device list. 332354359Sroberto */ 3324182007Sroberto if (!io_addclock(&parse->generic->io)) 332554359Sroberto { 3326182007Sroberto msyslog(LOG_ERR, 3327182007Sroberto "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 3328182007Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3329182007Sroberto return 0; 333054359Sroberto } 333154359Sroberto 333254359Sroberto /* 333354359Sroberto * print out configuration 333454359Sroberto */ 333554359Sroberto NLOG(NLOG_CLOCKINFO) 333654359Sroberto { 333754359Sroberto /* conditional if clause for conditional syslog */ 3338182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added", 333954359Sroberto CLK_UNIT(parse->peer), 3340182007Sroberto parse->parse_type->cl_description, parsedev, 3341182007Sroberto (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev); 334254359Sroberto 3343182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d", 334454359Sroberto CLK_UNIT(parse->peer), 3345182007Sroberto parse->peer->stratum, 3346182007Sroberto l_mktime(parse->maxunsync), parse->peer->precision); 334754359Sroberto 3348182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling", 334954359Sroberto CLK_UNIT(parse->peer), 335054359Sroberto parse->parse_type->cl_rootdelay, 335154359Sroberto parse->generic->fudgetime1, 3352182007Sroberto parse->ppsphaseadjust, 3353182007Sroberto parse->binding->bd_description); 335454359Sroberto 3355182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 335654359Sroberto parse->parse_type->cl_format); 3357182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer), 3358182007Sroberto CLK_PPS(parse->peer) ? "" : "NO ", 3359182007Sroberto CLK_PPS(parse->peer) ? 3360182007Sroberto#ifdef PPS_METHOD 3361182007Sroberto " (implementation " PPS_METHOD ")" 3362182007Sroberto#else 3363182007Sroberto "" 336454359Sroberto#endif 3365182007Sroberto : "" 3366182007Sroberto ); 336754359Sroberto } 336854359Sroberto 336954359Sroberto return 1; 337054359Sroberto} 337154359Sroberto 337254359Sroberto/*-------------------------------------------------- 3373182007Sroberto * parse_ctl - process changes on flags/time values 3374182007Sroberto */ 3375182007Srobertostatic void 3376182007Srobertoparse_ctl( 3377182007Sroberto struct parseunit *parse, 3378285612Sdelphij const struct refclockstat *in 3379182007Sroberto ) 3380182007Sroberto{ 3381182007Sroberto if (in) 3382182007Sroberto { 3383182007Sroberto if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3384182007Sroberto { 3385285612Sdelphij u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4; 3386285612Sdelphij parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask); 3387182007Sroberto#if defined(HAVE_PPSAPI) 3388182007Sroberto if (CLK_PPS(parse->peer)) 3389182007Sroberto { 3390182007Sroberto parse_ppsapi(parse); 3391182007Sroberto } 3392182007Sroberto#endif 3393182007Sroberto } 3394285612Sdelphij 3395182007Sroberto if (in->haveflags & CLK_HAVETIME1) 3396182007Sroberto { 3397182007Sroberto parse->generic->fudgetime1 = in->fudgetime1; 3398182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s", 3399182007Sroberto CLK_UNIT(parse->peer), 3400182007Sroberto parse->generic->fudgetime1); 3401182007Sroberto } 3402285612Sdelphij 3403182007Sroberto if (in->haveflags & CLK_HAVETIME2) 3404182007Sroberto { 3405182007Sroberto parse->generic->fudgetime2 = in->fudgetime2; 3406285612Sdelphij if (parse->flags & PARSE_TRUSTTIME) 3407182007Sroberto { 3408182007Sroberto parse->maxunsync = (u_long)ABS(in->fudgetime2); 3409182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s", 3410182007Sroberto CLK_UNIT(parse->peer), 3411182007Sroberto l_mktime(parse->maxunsync)); 3412182007Sroberto } 3413182007Sroberto else 3414182007Sroberto { 3415182007Sroberto parse->ppsphaseadjust = in->fudgetime2; 3416182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s", 3417182007Sroberto CLK_UNIT(parse->peer), 3418182007Sroberto parse->ppsphaseadjust); 3419182007Sroberto#if defined(HAVE_PPSAPI) 3420182007Sroberto if (CLK_PPS(parse->peer)) 3421182007Sroberto { 3422182007Sroberto parse_ppsapi(parse); 3423182007Sroberto } 3424182007Sroberto#endif 3425182007Sroberto } 3426182007Sroberto } 3427182007Sroberto } 3428182007Sroberto} 3429182007Sroberto 3430182007Sroberto/*-------------------------------------------------- 343154359Sroberto * parse_poll - called by the transmit procedure 343254359Sroberto */ 343354359Srobertostatic void 343454359Srobertoparse_poll( 343554359Sroberto int unit, 343654359Sroberto struct peer *peer 343754359Sroberto ) 343854359Sroberto{ 3439285612Sdelphij struct parseunit *parse = peer->procptr->unitptr; 344054359Sroberto 344154359Sroberto if (peer != parse->peer) 344254359Sroberto { 344354359Sroberto msyslog(LOG_ERR, 344454359Sroberto "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 344554359Sroberto unit); 344654359Sroberto return; 344754359Sroberto } 344854359Sroberto 344954359Sroberto /* 345054359Sroberto * Update clock stat counters 345154359Sroberto */ 345254359Sroberto parse->generic->polls++; 345354359Sroberto 3454285612Sdelphij if (parse->pollneeddata && 3455285612Sdelphij ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 345654359Sroberto { 345754359Sroberto /* 345856746Sroberto * start worrying when exceeding a poll inteval 345954359Sroberto * bad news - didn't get a response last time 346054359Sroberto */ 346154359Sroberto parse->lastmissed = current_time; 346254359Sroberto parse_event(parse, CEVNT_TIMEOUT); 3463285612Sdelphij 346454359Sroberto ERR(ERR_NODATA) 3465182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer)); 346654359Sroberto } 346754359Sroberto 346854359Sroberto /* 346954359Sroberto * we just mark that we want the next sample for the clock filter 347054359Sroberto */ 347156746Sroberto parse->pollneeddata = current_time; 347254359Sroberto 347354359Sroberto if (parse->parse_type->cl_poll) 347454359Sroberto { 347554359Sroberto parse->parse_type->cl_poll(parse); 347654359Sroberto } 347754359Sroberto 347854359Sroberto cparse_statistics(parse); 347954359Sroberto 348054359Sroberto return; 348154359Sroberto} 348254359Sroberto 348354359Sroberto#define LEN_STATES 300 /* length of state string */ 348454359Sroberto 348554359Sroberto/*-------------------------------------------------- 348654359Sroberto * parse_control - set fudge factors, return statistics 348754359Sroberto */ 348854359Srobertostatic void 348954359Srobertoparse_control( 349054359Sroberto int unit, 3491285612Sdelphij const struct refclockstat *in, 349254359Sroberto struct refclockstat *out, 349354359Sroberto struct peer *peer 349454359Sroberto ) 349554359Sroberto{ 3496285612Sdelphij struct parseunit *parse = peer->procptr->unitptr; 349754359Sroberto parsectl_t tmpctl; 349854359Sroberto 349954359Sroberto static char outstatus[400]; /* status output buffer */ 350054359Sroberto 350154359Sroberto if (out) 350254359Sroberto { 350354359Sroberto out->lencode = 0; 350454359Sroberto out->p_lastcode = 0; 350554359Sroberto out->kv_list = (struct ctl_var *)0; 350654359Sroberto } 350754359Sroberto 350854359Sroberto if (!parse || !parse->peer) 350954359Sroberto { 351054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 351154359Sroberto unit); 351254359Sroberto return; 351354359Sroberto } 351454359Sroberto 351554359Sroberto unit = CLK_UNIT(parse->peer); 351654359Sroberto 3517182007Sroberto /* 3518182007Sroberto * handle changes 3519182007Sroberto */ 3520182007Sroberto parse_ctl(parse, in); 3521285612Sdelphij 3522182007Sroberto /* 3523182007Sroberto * supply data 3524182007Sroberto */ 352554359Sroberto if (out) 352654359Sroberto { 352754359Sroberto u_long sum = 0; 3528182007Sroberto char *tt, *start; 352954359Sroberto int i; 353054359Sroberto 353154359Sroberto outstatus[0] = '\0'; 353254359Sroberto 353354359Sroberto out->type = REFCLK_PARSE; 353454359Sroberto 353554359Sroberto /* 3536182007Sroberto * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1 3537182007Sroberto */ 3538182007Sroberto parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust; 3539182007Sroberto 3540182007Sroberto /* 354154359Sroberto * figure out skew between PPS and RS232 - just for informational 3542182007Sroberto * purposes 354354359Sroberto */ 3544182007Sroberto if (PARSE_SYNC(parse->timedata.parse_state)) 354554359Sroberto { 3546182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state)) 354754359Sroberto { 354854359Sroberto l_fp off; 354954359Sroberto 355054359Sroberto /* 355154359Sroberto * we have a PPS and RS232 signal - calculate the skew 355254359Sroberto * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 355354359Sroberto */ 3554182007Sroberto off = parse->timedata.parse_stime.fp; 3555182007Sroberto L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */ 355654359Sroberto tt = add_var(&out->kv_list, 80, RO); 3557182007Sroberto snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6)); 355854359Sroberto } 355954359Sroberto } 356054359Sroberto 3561182007Sroberto if (PARSE_PPS(parse->timedata.parse_state)) 356254359Sroberto { 356354359Sroberto tt = add_var(&out->kv_list, 80, RO|DEF); 3564182007Sroberto snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp)); 356554359Sroberto } 356654359Sroberto 3567182007Sroberto start = tt = add_var(&out->kv_list, 128, RO|DEF); 3568285612Sdelphij tt = ap(start, 128, tt, "refclock_time=\""); 356954359Sroberto 3570182007Sroberto if (parse->timedata.parse_time.fp.l_ui == 0) 357154359Sroberto { 3572285612Sdelphij tt = ap(start, 128, tt, "<UNDEFINED>\""); 357354359Sroberto } 357454359Sroberto else 357554359Sroberto { 3576285612Sdelphij tt = ap(start, 128, tt, "%s\"", 3577285612Sdelphij gmprettydate(&parse->timedata.parse_time.fp)); 357854359Sroberto } 357954359Sroberto 358054359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 358154359Sroberto { 358254359Sroberto ERR(ERR_INTERNAL) 358354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 358454359Sroberto } 358554359Sroberto else 358654359Sroberto { 3587182007Sroberto start = tt = add_var(&out->kv_list, 512, RO|DEF); 3588285612Sdelphij tt = ap(start, 512, tt, "refclock_status=\""); 358954359Sroberto 359054359Sroberto /* 359154359Sroberto * copy PPS flags from last read transaction (informational only) 359254359Sroberto */ 3593182007Sroberto tmpctl.parsegettc.parse_state |= parse->timedata.parse_state & 359454359Sroberto (PARSEB_PPS|PARSEB_S_PPS); 359554359Sroberto 3596285612Sdelphij (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 359754359Sroberto 3598285612Sdelphij tt += strlen(tt); 359954359Sroberto 3600285612Sdelphij tt = ap(start, 512, tt, "\""); 3601285612Sdelphij 360254359Sroberto if (tmpctl.parsegettc.parse_count) 360354359Sroberto mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 3604182007Sroberto tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count)); 360554359Sroberto 360654359Sroberto } 3607285612Sdelphij 360854359Sroberto tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 3609285612Sdelphij 361054359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 361154359Sroberto { 361254359Sroberto ERR(ERR_INTERNAL) 361354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 361454359Sroberto } 361554359Sroberto else 361654359Sroberto { 3617330141Sdelphij int count = tmpctl.parseformat.parse_count; 3618330141Sdelphij if (count) 3619330141Sdelphij --count; 362054359Sroberto 3621285612Sdelphij start = tt = add_var(&out->kv_list, 80, RO|DEF); 3622285612Sdelphij tt = ap(start, 80, tt, "refclock_format=\""); 3623285612Sdelphij 3624285612Sdelphij if (count > 0) { 3625285612Sdelphij tt = ap(start, 80, tt, "%*.*s", 3626285612Sdelphij count, 3627285612Sdelphij count, 3628285612Sdelphij tmpctl.parseformat.parse_buffer); 3629285612Sdelphij } 3630285612Sdelphij 3631285612Sdelphij tt = ap(start, 80, tt, "\""); 363254359Sroberto } 363354359Sroberto 363454359Sroberto /* 363554359Sroberto * gather state statistics 363654359Sroberto */ 363754359Sroberto 363854359Sroberto start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3639285612Sdelphij tt = ap(start, LEN_STATES, tt, "refclock_states=\""); 364054359Sroberto 364154359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 364254359Sroberto { 364354359Sroberto u_long s_time; 364454359Sroberto u_long d = current_time - parse->generic->timestarted; 364554359Sroberto u_long percent; 364654359Sroberto 364754359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 364854359Sroberto 364954359Sroberto while (((u_long)(~0) / 10000) < percent) 365054359Sroberto { 365154359Sroberto percent /= 10; 365254359Sroberto d /= 10; 365354359Sroberto } 3654285612Sdelphij 365554359Sroberto if (d) 365654359Sroberto percent = (percent * 10000) / d; 365754359Sroberto else 365854359Sroberto percent = 10000; 365954359Sroberto 366054359Sroberto if (s_time) 366154359Sroberto { 366254359Sroberto char item[80]; 366354359Sroberto int count; 3664285612Sdelphij 3665182007Sroberto snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 366654359Sroberto sum ? "; " : "", 366754359Sroberto (parse->generic->currentstatus == i) ? "*" : "", 366854359Sroberto clockstatus((unsigned int)i), 366954359Sroberto l_mktime(s_time), 367054359Sroberto (int)(percent / 100), (int)(percent % 100)); 3671285612Sdelphij if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start))) 367254359Sroberto { 3673285612Sdelphij tt = ap(start, LEN_STATES, tt, 3674285612Sdelphij "%s", item); 367554359Sroberto } 367654359Sroberto sum += s_time; 367754359Sroberto } 367854359Sroberto } 3679285612Sdelphij 3680316069Sdelphij ap(start, LEN_STATES, tt, "; running time: %s\"", l_mktime(sum)); 3681285612Sdelphij 368254359Sroberto tt = add_var(&out->kv_list, 32, RO); 3683182007Sroberto snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 3684285612Sdelphij 368554359Sroberto tt = add_var(&out->kv_list, 80, RO); 3686182007Sroberto snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 368754359Sroberto 368854359Sroberto tt = add_var(&out->kv_list, 128, RO); 3689182007Sroberto snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 3690285612Sdelphij 369154359Sroberto { 369254359Sroberto struct ctl_var *k; 3693285612Sdelphij 369454359Sroberto k = parse->kv; 369554359Sroberto while (k && !(k->flags & EOV)) 369654359Sroberto { 369754359Sroberto set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 369854359Sroberto k++; 369954359Sroberto } 370054359Sroberto } 3701285612Sdelphij 3702285612Sdelphij out->lencode = (u_short) strlen(outstatus); 370354359Sroberto out->p_lastcode = outstatus; 370454359Sroberto } 370554359Sroberto} 370654359Sroberto 370754359Sroberto/**=========================================================================== 370854359Sroberto ** processing routines 370954359Sroberto **/ 371054359Sroberto 371154359Sroberto/*-------------------------------------------------- 371254359Sroberto * event handling - note that nominal events will also be posted 3713182007Sroberto * keep track of state dwelling times 371454359Sroberto */ 371554359Srobertostatic void 371654359Srobertoparse_event( 371754359Sroberto struct parseunit *parse, 371854359Sroberto int event 371954359Sroberto ) 372054359Sroberto{ 372154359Sroberto if (parse->generic->currentstatus != (u_char) event) 372254359Sroberto { 372354359Sroberto parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 372454359Sroberto parse->lastchange = current_time; 372554359Sroberto 372654359Sroberto if (parse->parse_type->cl_event) 372754359Sroberto parse->parse_type->cl_event(parse, event); 3728285612Sdelphij 3729182007Sroberto if (event == CEVNT_NOMINAL) 373054359Sroberto { 373154359Sroberto NLOG(NLOG_CLOCKSTATUS) 373254359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 373354359Sroberto CLK_UNIT(parse->peer)); 373454359Sroberto } 373554359Sroberto 3736182007Sroberto refclock_report(parse->peer, event); 373754359Sroberto } 373854359Sroberto} 373954359Sroberto 374054359Sroberto/*-------------------------------------------------- 374154359Sroberto * process a PARSE time sample 374254359Sroberto */ 374354359Srobertostatic void 374454359Srobertoparse_process( 374554359Sroberto struct parseunit *parse, 374654359Sroberto parsetime_t *parsetime 374754359Sroberto ) 374854359Sroberto{ 374954359Sroberto l_fp off, rectime, reftime; 375054359Sroberto double fudge; 3751285612Sdelphij 3752285612Sdelphij /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */ 3753285612Sdelphij ZERO(off); 3754285612Sdelphij 375554359Sroberto /* 375654359Sroberto * check for changes in conversion status 375754359Sroberto * (only one for each new status !) 375854359Sroberto */ 375954359Sroberto if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 376054359Sroberto ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3761182007Sroberto (parse->timedata.parse_status != parsetime->parse_status)) 376254359Sroberto { 376354359Sroberto char buffer[400]; 3764285612Sdelphij 376554359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 376654359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3767182007Sroberto CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 3768285612Sdelphij 376954359Sroberto if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 377054359Sroberto { 377154359Sroberto /* 377254359Sroberto * tell more about the story - list time code 377354359Sroberto * there is a slight change for a race condition and 377454359Sroberto * the time code might be overwritten by the next packet 377554359Sroberto */ 377654359Sroberto parsectl_t tmpctl; 3777285612Sdelphij 377854359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 377954359Sroberto { 378054359Sroberto ERR(ERR_INTERNAL) 378154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 378254359Sroberto } 378354359Sroberto else 378454359Sroberto { 3785330141Sdelphij unsigned int count = tmpctl.parsegettc.parse_count; 3786330141Sdelphij if (count) 3787330141Sdelphij --count; 378854359Sroberto ERR(ERR_BADDATA) 3789330141Sdelphij msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 3790330141Sdelphij CLK_UNIT(parse->peer), 3791330141Sdelphij mkascii(buffer, sizeof(buffer), 3792330141Sdelphij tmpctl.parsegettc.parse_buffer, count)); 379354359Sroberto } 3794285612Sdelphij /* copy status to show only changes in case of failures */ 3795285612Sdelphij parse->timedata.parse_status = parsetime->parse_status; 379654359Sroberto } 379754359Sroberto } 379854359Sroberto 379954359Sroberto /* 380054359Sroberto * examine status and post appropriate events 380154359Sroberto */ 380254359Sroberto if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 380354359Sroberto { 380454359Sroberto /* 380554359Sroberto * got bad data - tell the rest of the system 380654359Sroberto */ 380754359Sroberto switch (parsetime->parse_status & CVT_MASK) 380854359Sroberto { 380954359Sroberto case CVT_NONE: 381054359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 381154359Sroberto parse->parse_type->cl_message) 381254359Sroberto parse->parse_type->cl_message(parse, parsetime); 3813182007Sroberto /* 3814182007Sroberto * save PPS information that comes piggyback 3815182007Sroberto */ 3816182007Sroberto if (PARSE_PPS(parsetime->parse_state)) 3817182007Sroberto { 3818182007Sroberto parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3819182007Sroberto parse->timedata.parse_ptime = parsetime->parse_ptime; 3820182007Sroberto } 382154359Sroberto break; /* well, still waiting - timeout is handled at higher levels */ 3822285612Sdelphij 382354359Sroberto case CVT_FAIL: 382454359Sroberto if (parsetime->parse_status & CVT_BADFMT) 382554359Sroberto { 382654359Sroberto parse_event(parse, CEVNT_BADREPLY); 382754359Sroberto } 382854359Sroberto else 382954359Sroberto if (parsetime->parse_status & CVT_BADDATE) 383054359Sroberto { 383154359Sroberto parse_event(parse, CEVNT_BADDATE); 383254359Sroberto } 383354359Sroberto else 383454359Sroberto if (parsetime->parse_status & CVT_BADTIME) 383554359Sroberto { 383654359Sroberto parse_event(parse, CEVNT_BADTIME); 383754359Sroberto } 383854359Sroberto else 383954359Sroberto { 384054359Sroberto parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 384154359Sroberto } 384254359Sroberto } 384354359Sroberto return; /* skip the rest - useless */ 384454359Sroberto } 384554359Sroberto 384654359Sroberto /* 384754359Sroberto * check for format changes 384854359Sroberto * (in case somebody has swapped clocks 8-) 384954359Sroberto */ 385054359Sroberto if (parse->lastformat != parsetime->parse_format) 385154359Sroberto { 385254359Sroberto parsectl_t tmpctl; 3853285612Sdelphij 385454359Sroberto tmpctl.parseformat.parse_format = parsetime->parse_format; 385554359Sroberto 385654359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 385754359Sroberto { 385854359Sroberto ERR(ERR_INTERNAL) 385954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 386054359Sroberto } 386154359Sroberto else 386254359Sroberto { 386354359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 386454359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 386554359Sroberto CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 386654359Sroberto } 386754359Sroberto parse->lastformat = parsetime->parse_format; 386854359Sroberto } 386954359Sroberto 387054359Sroberto /* 387154359Sroberto * now, any changes ? 387254359Sroberto */ 3873182007Sroberto if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3874182007Sroberto ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 387554359Sroberto { 387654359Sroberto char tmp1[200]; 387754359Sroberto char tmp2[200]; 387854359Sroberto /* 3879182007Sroberto * something happend - except for PPS events 388054359Sroberto */ 3881285612Sdelphij 3882182007Sroberto (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3883182007Sroberto (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 3884285612Sdelphij 388554359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 388654359Sroberto msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 388754359Sroberto CLK_UNIT(parse->peer), tmp2, tmp1); 388854359Sroberto } 388954359Sroberto 389054359Sroberto /* 3891182007Sroberto * carry on PPS information if still usable 3892182007Sroberto */ 3893182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3894182007Sroberto { 3895182007Sroberto parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3896182007Sroberto parsetime->parse_ptime = parse->timedata.parse_ptime; 3897182007Sroberto } 3898182007Sroberto 3899182007Sroberto /* 390054359Sroberto * remember for future 390154359Sroberto */ 3902182007Sroberto parse->timedata = *parsetime; 390354359Sroberto 390454359Sroberto /* 390554359Sroberto * check to see, whether the clock did a complete powerup or lost PZF signal 390654359Sroberto * and post correct events for current condition 390754359Sroberto */ 390854359Sroberto if (PARSE_POWERUP(parsetime->parse_state)) 390954359Sroberto { 391054359Sroberto /* 391154359Sroberto * this is bad, as we have completely lost synchronisation 391254359Sroberto * well this is a problem with the receiver here 391354359Sroberto * for PARSE Meinberg DCF77 receivers the lost synchronisation 391454359Sroberto * is true as it is the powerup state and the time is taken 391554359Sroberto * from a crude real time clock chip 3916285612Sdelphij * for the PZF/GPS series this is only partly true, as 391754359Sroberto * PARSE_POWERUP only means that the pseudo random 391854359Sroberto * phase shift sequence cannot be found. this is only 391954359Sroberto * bad, if we have never seen the clock in the SYNC 392054359Sroberto * state, where the PHASE and EPOCH are correct. 392154359Sroberto * for reporting events the above business does not 392254359Sroberto * really matter, but we can use the time code 392354359Sroberto * even in the POWERUP state after having seen 392454359Sroberto * the clock in the synchronized state (PZF class 392554359Sroberto * receivers) unless we have had a telegram disruption 392654359Sroberto * after having seen the clock in the SYNC state. we 392754359Sroberto * thus require having seen the clock in SYNC state 392854359Sroberto * *after* having missed telegrams (noresponse) from 392954359Sroberto * the clock. one problem remains: we might use erroneously 393054359Sroberto * POWERUP data if the disruption is shorter than 1 polling 393154359Sroberto * interval. fortunately powerdowns last usually longer than 64 393254359Sroberto * seconds and the receiver is at least 2 minutes in the 393354359Sroberto * POWERUP or NOSYNC state before switching to SYNC 3934285612Sdelphij * for GPS receivers this can mean antenna problems and other causes. 3935285612Sdelphij * the additional grace period can be enables by a clock 3936285612Sdelphij * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set. 393754359Sroberto */ 393854359Sroberto parse_event(parse, CEVNT_FAULT); 393954359Sroberto NLOG(NLOG_CLOCKSTATUS) 394054359Sroberto ERR(ERR_BADSTATUS) 3941285612Sdelphij msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS", 394254359Sroberto CLK_UNIT(parse->peer)); 394354359Sroberto } 394454359Sroberto else 394554359Sroberto { 394654359Sroberto /* 394754359Sroberto * we have two states left 394854359Sroberto * 394954359Sroberto * SYNC: 395054359Sroberto * this state means that the EPOCH (timecode) and PHASE 395154359Sroberto * information has be read correctly (at least two 395254359Sroberto * successive PARSE timecodes were received correctly) 395354359Sroberto * this is the best possible state - full trust 395454359Sroberto * 395554359Sroberto * NOSYNC: 395654359Sroberto * The clock should be on phase with respect to the second 395754359Sroberto * signal, but the timecode has not been received correctly within 395854359Sroberto * at least the last two minutes. this is a sort of half baked state 395954359Sroberto * for PARSE Meinberg DCF77 clocks this is bad news (clock running 396054359Sroberto * without timecode confirmation) 396154359Sroberto * PZF 535 has also no time confirmation, but the phase should be 396254359Sroberto * very precise as the PZF signal can be decoded 396354359Sroberto */ 396454359Sroberto 396554359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 396654359Sroberto { 396754359Sroberto /* 396854359Sroberto * currently completely synchronized - best possible state 396954359Sroberto */ 397054359Sroberto parse->lastsync = current_time; 397154359Sroberto clear_err(parse, ERR_BADSTATUS); 397254359Sroberto } 397354359Sroberto else 397454359Sroberto { 397554359Sroberto /* 397654359Sroberto * we have had some problems receiving the time code 397754359Sroberto */ 397854359Sroberto parse_event(parse, CEVNT_PROP); 397954359Sroberto NLOG(NLOG_CLOCKSTATUS) 398054359Sroberto ERR(ERR_BADSTATUS) 398154359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 398254359Sroberto CLK_UNIT(parse->peer)); 398354359Sroberto } 398454359Sroberto } 398554359Sroberto 398654359Sroberto fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 3987285612Sdelphij 398854359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 398954359Sroberto { 399054359Sroberto rectime = parsetime->parse_stime.fp; 399154359Sroberto off = reftime = parsetime->parse_time.fp; 3992285612Sdelphij 399354359Sroberto L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 399454359Sroberto 399554359Sroberto#ifdef DEBUG 399654359Sroberto if (debug > 3) 399754359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 399854359Sroberto CLK_UNIT(parse->peer), 399954359Sroberto prettydate(&reftime), 400054359Sroberto prettydate(&rectime), 400154359Sroberto lfptoa(&off,6)); 400254359Sroberto#endif 400354359Sroberto } 400454359Sroberto 400554359Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 400654359Sroberto { 400754359Sroberto l_fp offset; 4008182007Sroberto double ppsphaseadjust = parse->ppsphaseadjust; 400954359Sroberto 4010182007Sroberto#ifdef HAVE_PPSAPI 401154359Sroberto /* 4012182007Sroberto * set fudge = 0.0 if already included in PPS time stamps 4013182007Sroberto */ 4014285612Sdelphij if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 4015182007Sroberto { 4016182007Sroberto ppsphaseadjust = 0.0; 4017182007Sroberto } 4018182007Sroberto#endif 4019182007Sroberto 4020182007Sroberto /* 402154359Sroberto * we have a PPS signal - much better than the RS232 stuff (we hope) 402254359Sroberto */ 402354359Sroberto offset = parsetime->parse_ptime.fp; 402454359Sroberto 402554359Sroberto#ifdef DEBUG 402654359Sroberto if (debug > 3) 402754359Sroberto printf("PARSE receiver #%d: PPStime %s\n", 402854359Sroberto CLK_UNIT(parse->peer), 402954359Sroberto prettydate(&offset)); 403054359Sroberto#endif 403154359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 403254359Sroberto { 4033285612Sdelphij if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) && 4034285612Sdelphij M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf)) 403554359Sroberto { 4036182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 4037285612Sdelphij 403854359Sroberto /* 403954359Sroberto * RS232 offsets within [-0.5..0.5[ - take PPS offsets 404054359Sroberto */ 404154359Sroberto 404254359Sroberto if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 404354359Sroberto { 404454359Sroberto reftime = off = offset; 4045285612Sdelphij if (reftime.l_uf & 0x80000000) 404654359Sroberto reftime.l_ui++; 404754359Sroberto reftime.l_uf = 0; 404856746Sroberto 4049285612Sdelphij 405054359Sroberto /* 405154359Sroberto * implied on second offset 405254359Sroberto */ 405354359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4054285612Sdelphij off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 405554359Sroberto } 405654359Sroberto else 405754359Sroberto { 405854359Sroberto /* 405954359Sroberto * time code describes pulse 406054359Sroberto */ 406154359Sroberto reftime = off = parsetime->parse_time.fp; 406254359Sroberto 406354359Sroberto L_SUB(&off, &offset); /* true offset */ 406454359Sroberto } 406554359Sroberto } 406654359Sroberto /* 406754359Sroberto * take RS232 offset when PPS when out of bounds 406854359Sroberto */ 406954359Sroberto } 407054359Sroberto else 407154359Sroberto { 4072182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 407354359Sroberto /* 407454359Sroberto * Well, no time code to guide us - assume on second pulse 407554359Sroberto * and pray, that we are within [-0.5..0.5[ 407654359Sroberto */ 407754359Sroberto off = offset; 407854359Sroberto reftime = offset; 4079285612Sdelphij if (reftime.l_uf & 0x80000000) 408054359Sroberto reftime.l_ui++; 408154359Sroberto reftime.l_uf = 0; 408254359Sroberto /* 408354359Sroberto * implied on second offset 408454359Sroberto */ 408554359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4086285612Sdelphij off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 408754359Sroberto } 408854359Sroberto } 408954359Sroberto else 409054359Sroberto { 409154359Sroberto if (!PARSE_TIMECODE(parsetime->parse_state)) 409254359Sroberto { 409354359Sroberto /* 409454359Sroberto * Well, no PPS, no TIMECODE, no more work ... 409554359Sroberto */ 409654359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 409754359Sroberto parse->parse_type->cl_message) 409854359Sroberto parse->parse_type->cl_message(parse, parsetime); 409954359Sroberto return; 410054359Sroberto } 410154359Sroberto } 410254359Sroberto 410354359Sroberto#ifdef DEBUG 410454359Sroberto if (debug > 3) 410554359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 410654359Sroberto CLK_UNIT(parse->peer), 410754359Sroberto prettydate(&reftime), 410854359Sroberto prettydate(&rectime), 410954359Sroberto lfptoa(&off,6)); 411054359Sroberto#endif 411154359Sroberto 411254359Sroberto 411354359Sroberto rectime = reftime; 411454359Sroberto L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 4115285612Sdelphij 411654359Sroberto#ifdef DEBUG 411754359Sroberto if (debug > 3) 411854359Sroberto printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 411954359Sroberto CLK_UNIT(parse->peer), 412054359Sroberto prettydate(&reftime), 412154359Sroberto prettydate(&rectime)); 412254359Sroberto#endif 412354359Sroberto 412454359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 412554359Sroberto parse->parse_type->cl_message) 412654359Sroberto parse->parse_type->cl_message(parse, parsetime); 412754359Sroberto 412854359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 412954359Sroberto { 413054359Sroberto /* 413154359Sroberto * log OK status 413254359Sroberto */ 413354359Sroberto parse_event(parse, CEVNT_NOMINAL); 413454359Sroberto } 413554359Sroberto 413654359Sroberto clear_err(parse, ERR_BADIO); 413754359Sroberto clear_err(parse, ERR_BADDATA); 413854359Sroberto clear_err(parse, ERR_NODATA); 413954359Sroberto clear_err(parse, ERR_INTERNAL); 4140285612Sdelphij 414154359Sroberto /* 414254359Sroberto * and now stick it into the clock machine 414354359Sroberto * samples are only valid iff lastsync is not too old and 414454359Sroberto * we have seen the clock in sync at least once 414554359Sroberto * after the last time we didn't see an expected data telegram 4146182007Sroberto * at startup being not in sync is also bad just like 4147285612Sdelphij * POWERUP state unless PARSE_F_POWERUPTRUST is set 414854359Sroberto * see the clock states section above for more reasoning 414954359Sroberto */ 4150285612Sdelphij if (((current_time - parse->lastsync) > parse->maxunsync) || 4151285612Sdelphij (parse->lastsync < parse->lastmissed) || 4152182007Sroberto ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 4153285612Sdelphij (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) && 4154285612Sdelphij PARSE_POWERUP(parsetime->parse_state))) 415554359Sroberto { 415654359Sroberto parse->generic->leap = LEAP_NOTINSYNC; 4157182007Sroberto parse->lastsync = 0; /* wait for full sync again */ 415854359Sroberto } 415954359Sroberto else 416054359Sroberto { 416154359Sroberto if (PARSE_LEAPADD(parsetime->parse_state)) 416254359Sroberto { 416354359Sroberto /* 416454359Sroberto * we pick this state also for time code that pass leap warnings 416554359Sroberto * without direction information (as earth is currently slowing 416654359Sroberto * down). 416754359Sroberto */ 416854359Sroberto parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 416954359Sroberto } 417054359Sroberto else 417154359Sroberto if (PARSE_LEAPDEL(parsetime->parse_state)) 417254359Sroberto { 417354359Sroberto parse->generic->leap = LEAP_DELSECOND; 417454359Sroberto } 417554359Sroberto else 417654359Sroberto { 417754359Sroberto parse->generic->leap = LEAP_NOWARNING; 417854359Sroberto } 417954359Sroberto } 4180182007Sroberto 4181182007Sroberto if (parse->generic->leap != LEAP_NOTINSYNC) 4182182007Sroberto { 4183182007Sroberto /* 4184182007Sroberto * only good/trusted samples are interesting 4185182007Sroberto */ 4186182007Sroberto#ifdef DEBUG 4187285612Sdelphij if (debug > 2) 4188285612Sdelphij { 4189285612Sdelphij printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 4190182007Sroberto CLK_UNIT(parse->peer), 4191182007Sroberto prettydate(&reftime), 4192182007Sroberto prettydate(&rectime), 4193182007Sroberto fudge); 4194182007Sroberto } 4195182007Sroberto#endif 4196182007Sroberto parse->generic->lastref = reftime; 4197285612Sdelphij 4198182007Sroberto refclock_process_offset(parse->generic, reftime, rectime, fudge); 4199182007Sroberto 4200285612Sdelphij#ifdef HAVE_PPSAPI 4201182007Sroberto /* 4202182007Sroberto * pass PPS information on to PPS clock 4203182007Sroberto */ 4204182007Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4205285612Sdelphij { 4206285612Sdelphij parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS); 4207182007Sroberto parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4208182007Sroberto } 4209285612Sdelphij#endif 4210182007Sroberto } else { 4211285612Sdelphij parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4212285612Sdelphij parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS); 4213182007Sroberto } 4214182007Sroberto 421554359Sroberto /* 4216285612Sdelphij * ready, unless the machine wants a sample or 4217182007Sroberto * we are in fast startup mode (peer->dist > MAXDISTANCE) 421854359Sroberto */ 4219182007Sroberto if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 422054359Sroberto return; 422154359Sroberto 422254359Sroberto parse->pollneeddata = 0; 422354359Sroberto 4224182007Sroberto parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4225182007Sroberto 422654359Sroberto refclock_receive(parse->peer); 422754359Sroberto} 4228285612Sdelphij 422954359Sroberto/**=========================================================================== 423054359Sroberto ** special code for special clocks 423154359Sroberto **/ 423254359Sroberto 423354359Srobertostatic void 423454359Srobertomk_utcinfo( 4235316069Sdelphij char *t, /* pointer to the output string buffer */ 4236316069Sdelphij uint16_t wnt, 4237316069Sdelphij uint16_t wnlsf, 423854359Sroberto int dn, 423954359Sroberto int dtls, 4240182007Sroberto int dtlsf, 4241316069Sdelphij int size /* size of the output string buffer */ 424254359Sroberto ) 424354359Sroberto{ 4244285612Sdelphij /* 4245285612Sdelphij * The week number transmitted by the GPS satellites for the leap date 4246285612Sdelphij * is truncated to 8 bits only. If the nearest leap second date is off 4247285612Sdelphij * the current date by more than +/- 128 weeks then conversion to a 4248285612Sdelphij * calendar date is ambiguous. On the other hand, if a leap second is 4249285612Sdelphij * currently being announced (i.e. dtlsf != dtls) then the week number 4250285612Sdelphij * wnlsf is close enough, and we can unambiguously determine the date 4251285612Sdelphij * for which the leap second is scheduled. 4252285612Sdelphij */ 4253285612Sdelphij if ( dtlsf != dtls ) 4254285612Sdelphij { 4255285612Sdelphij time_t t_ls; 4256285612Sdelphij struct tm *tm; 4257316069Sdelphij int nc; 4258285612Sdelphij 4259285612Sdelphij if (wnlsf < GPSWRAP) 4260285612Sdelphij wnlsf += GPSWEEKS; 4261316069Sdelphij /* 'wnt' not used here: would need the same treatment as 'wnlsf */ 4262285612Sdelphij 4263285612Sdelphij t_ls = (time_t) wnlsf * SECSPERWEEK 4264285612Sdelphij + (time_t) dn * SECSPERDAY 4265285612Sdelphij + GPS_SEC_BIAS - 1; 4266285612Sdelphij 4267285612Sdelphij tm = gmtime( &t_ls ); 4268316069Sdelphij if (tm == NULL) /* gmtime() failed */ 4269285612Sdelphij { 4270285612Sdelphij snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" ); 4271285612Sdelphij return; 4272285612Sdelphij } 4273285612Sdelphij 4274316069Sdelphij nc = snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s", 4275285612Sdelphij dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" ); 4276316069Sdelphij if (nc < 0) 4277316069Sdelphij nc = strlen(t); 4278316069Sdelphij else if (nc > size) 4279316069Sdelphij nc = size; 4280316069Sdelphij 4281316069Sdelphij snprintf( t + nc, size - nc, " at UTC midnight at the end of %s, %04i-%02i-%02i", 4282285612Sdelphij daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday ); 4283285612Sdelphij } 4284285612Sdelphij else 4285316069Sdelphij { 4286285612Sdelphij snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls ); 4287316069Sdelphij } 4288285612Sdelphij 428954359Sroberto} 429054359Sroberto 429154359Sroberto#ifdef CLOCK_MEINBERG 429254359Sroberto/**=========================================================================== 4293285612Sdelphij ** Meinberg GPS receiver support 429454359Sroberto **/ 429554359Sroberto 429654359Sroberto/*------------------------------------------------------------ 4297285612Sdelphij * gps16x_message - process messages from Meinberg GPS receiver 429854359Sroberto */ 429954359Srobertostatic void 430054359Srobertogps16x_message( 430154359Sroberto struct parseunit *parse, 430254359Sroberto parsetime_t *parsetime 430354359Sroberto ) 430454359Sroberto{ 4305182007Sroberto if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 430654359Sroberto { 430754359Sroberto GPS_MSG_HDR header; 430854359Sroberto unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 4309285612Sdelphij 431054359Sroberto#ifdef DEBUG 431154359Sroberto if (debug > 2) 431254359Sroberto { 431354359Sroberto char msgbuffer[600]; 4314285612Sdelphij 431554359Sroberto mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 431654359Sroberto printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 431754359Sroberto CLK_UNIT(parse->peer), 431854359Sroberto parsetime->parse_msglen, 431954359Sroberto msgbuffer); 432054359Sroberto } 432154359Sroberto#endif 432254359Sroberto get_mbg_header(&bufp, &header); 4323285612Sdelphij if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 4324285612Sdelphij (header.len == 0 || 4325285612Sdelphij (header.len < sizeof(parsetime->parse_msg) && 4326285612Sdelphij header.data_csum == mbg_csum(bufp, header.len)))) 432754359Sroberto { 432854359Sroberto /* 432954359Sroberto * clean message 433054359Sroberto */ 4331285612Sdelphij switch (header.cmd) 433254359Sroberto { 433354359Sroberto case GPS_SW_REV: 433454359Sroberto { 433554359Sroberto char buffer[64]; 433654359Sroberto SW_REV gps_sw_rev; 4337285612Sdelphij 433854359Sroberto get_mbg_sw_rev(&bufp, &gps_sw_rev); 4339182007Sroberto snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 434054359Sroberto (gps_sw_rev.code >> 8) & 0xFF, 434154359Sroberto gps_sw_rev.code & 0xFF, 434254359Sroberto gps_sw_rev.name[0] ? " " : "", 434354359Sroberto gps_sw_rev.name); 4344182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 434554359Sroberto } 434654359Sroberto break; 434754359Sroberto 4348285612Sdelphij case GPS_BVAR_STAT: 434954359Sroberto { 435054359Sroberto static struct state 435154359Sroberto { 4352285612Sdelphij BVAR_STAT flag; /* status flag */ 4353285612Sdelphij const char *string; /* bit name */ 435454359Sroberto } states[] = 435554359Sroberto { 4356285612Sdelphij { BVAR_CFGH_INVALID, "Configuration/Health" }, 4357285612Sdelphij { BVAR_ALM_NOT_COMPLETE, "Almanachs" }, 4358285612Sdelphij { BVAR_UTC_INVALID, "UTC Correction" }, 4359285612Sdelphij { BVAR_IONO_INVALID, "Ionospheric Correction" }, 4360285612Sdelphij { BVAR_RCVR_POS_INVALID, "Receiver Position" }, 4361285612Sdelphij { 0, "" } 436254359Sroberto }; 4363285612Sdelphij BVAR_STAT status; 436454359Sroberto struct state *s = states; 436554359Sroberto char buffer[512]; 436654359Sroberto char *p, *b; 4367285612Sdelphij 4368285612Sdelphij status = (BVAR_STAT) get_lsb_short(&bufp); 4369285612Sdelphij p = b = buffer; 4370285612Sdelphij p = ap(buffer, sizeof(buffer), p, 4371285612Sdelphij "meinberg_gps_status=\"[0x%04x] ", 4372285612Sdelphij status); 4373285612Sdelphij 437454359Sroberto if (status) 437554359Sroberto { 4376285612Sdelphij p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: "); 4377285612Sdelphij b = p; 437854359Sroberto while (s->flag) 437954359Sroberto { 438054359Sroberto if (status & s->flag) 438154359Sroberto { 438254359Sroberto if (p != b) 438354359Sroberto { 4384285612Sdelphij p = ap(buffer, sizeof(buffer), p, ", "); 438554359Sroberto } 4386285612Sdelphij 4387285612Sdelphij p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string); 438854359Sroberto } 438954359Sroberto s++; 439054359Sroberto } 4391285612Sdelphij p = ap(buffer, sizeof(buffer), p, "\""); 439254359Sroberto } 439354359Sroberto else 439454359Sroberto { 4395285612Sdelphij p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\""); 439654359Sroberto } 4397285612Sdelphij 4398182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 439954359Sroberto } 440054359Sroberto break; 440154359Sroberto 440254359Sroberto case GPS_POS_XYZ: 440354359Sroberto { 440454359Sroberto XYZ xyz; 440554359Sroberto char buffer[256]; 4406285612Sdelphij 440754359Sroberto get_mbg_xyz(&bufp, xyz); 4408182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 440954359Sroberto mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 441054359Sroberto mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 441154359Sroberto mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 4412285612Sdelphij 441354359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 441454359Sroberto } 441554359Sroberto break; 4416285612Sdelphij 441754359Sroberto case GPS_POS_LLA: 441854359Sroberto { 441954359Sroberto LLA lla; 442054359Sroberto char buffer[256]; 4421285612Sdelphij 442254359Sroberto get_mbg_lla(&bufp, lla); 4423285612Sdelphij 4424182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 442554359Sroberto mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 4426285612Sdelphij mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 442754359Sroberto mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 4428285612Sdelphij 442954359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 443054359Sroberto } 443154359Sroberto break; 4432285612Sdelphij 443354359Sroberto case GPS_TZDL: 443454359Sroberto break; 4435285612Sdelphij 443654359Sroberto case GPS_PORT_PARM: 443754359Sroberto break; 4438285612Sdelphij 443954359Sroberto case GPS_SYNTH: 444054359Sroberto break; 4441285612Sdelphij 444254359Sroberto case GPS_ANT_INFO: 444354359Sroberto { 444454359Sroberto ANT_INFO antinfo; 4445182007Sroberto char buffer[512]; 4446285612Sdelphij char *p, *q; 4447285612Sdelphij 444854359Sroberto get_mbg_antinfo(&bufp, &antinfo); 4449285612Sdelphij p = buffer; 4450285612Sdelphij p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\""); 445154359Sroberto switch (antinfo.status) 445254359Sroberto { 4453285612Sdelphij case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected 4454285612Sdelphij p = ap(buffer, sizeof(buffer), 4455285612Sdelphij p, "<OK>"); 445654359Sroberto break; 4457285612Sdelphij 4458285612Sdelphij case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set 4459285612Sdelphij q = ap(buffer, sizeof(buffer), 4460285612Sdelphij p, "DISCONNECTED since "); 446154359Sroberto NLOG(NLOG_CLOCKSTATUS) 446254359Sroberto ERR(ERR_BADSTATUS) 446354359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 446454359Sroberto CLK_UNIT(parse->peer), p); 4465285612Sdelphij 4466285612Sdelphij p = q; 4467285612Sdelphij mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 446854359Sroberto *p = '\0'; 446954359Sroberto break; 4470285612Sdelphij 4471285612Sdelphij case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid 4472285612Sdelphij p = ap(buffer, sizeof(buffer), 4473285612Sdelphij p, "SYNC AFTER RECONNECT on "); 4474285612Sdelphij mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0); 4475285612Sdelphij p = ap(buffer, sizeof(buffer), 4476285612Sdelphij p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ", 447754359Sroberto (antinfo.delta_t < 0) ? '-' : '+', 4478285612Sdelphij (long) ABS(antinfo.delta_t) / 10000, 4479285612Sdelphij (long) ABS(antinfo.delta_t) % 10000); 4480285612Sdelphij mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 448154359Sroberto *p = '\0'; 448254359Sroberto break; 4483285612Sdelphij 448454359Sroberto default: 4485285612Sdelphij p = ap(buffer, sizeof(buffer), 4486285612Sdelphij p, "bad status 0x%04x", 4487285612Sdelphij antinfo.status); 448854359Sroberto break; 448954359Sroberto } 4490285612Sdelphij 4491285612Sdelphij p = ap(buffer, sizeof(buffer), p, "\""); 4492285612Sdelphij 4493285612Sdelphij set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 449454359Sroberto } 449554359Sroberto break; 4496285612Sdelphij 449754359Sroberto case GPS_UCAP: 449854359Sroberto break; 4499285612Sdelphij 450054359Sroberto case GPS_CFGH: 450154359Sroberto { 450254359Sroberto CFGH cfgh; 4503182007Sroberto char buffer[512]; 4504182007Sroberto char *p; 4505285612Sdelphij 450654359Sroberto get_mbg_cfgh(&bufp, &cfgh); 450754359Sroberto if (cfgh.valid) 450854359Sroberto { 4509285612Sdelphij const char *cp; 4510285612Sdelphij uint16_t tmp_val; 451154359Sroberto int i; 4512285612Sdelphij 451354359Sroberto p = buffer; 4514285612Sdelphij p = ap(buffer, sizeof(buffer), 4515285612Sdelphij p, "gps_tot_51=\""); 4516182007Sroberto mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4517285612Sdelphij p = ap(buffer, sizeof(buffer), 4518285612Sdelphij p, "\""); 4519285612Sdelphij set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4520285612Sdelphij 452154359Sroberto p = buffer; 4522285612Sdelphij p = ap(buffer, sizeof(buffer), 4523285612Sdelphij p, "gps_tot_63=\""); 4524182007Sroberto mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4525285612Sdelphij p = ap(buffer, sizeof(buffer), 4526285612Sdelphij p, "\""); 4527285612Sdelphij set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4528285612Sdelphij 452954359Sroberto p = buffer; 4530285612Sdelphij p = ap(buffer, sizeof(buffer), 4531285612Sdelphij p, "gps_t0a=\""); 4532182007Sroberto mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4533285612Sdelphij p = ap(buffer, sizeof(buffer), 4534285612Sdelphij p, "\""); 4535285612Sdelphij set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4536285612Sdelphij 4537285612Sdelphij for (i = 0; i < N_SVNO_GPS; i++) 453854359Sroberto { 453954359Sroberto p = buffer; 4540285612Sdelphij p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS); 4541285612Sdelphij 4542285612Sdelphij tmp_val = cfgh.health[i]; /* a 6 bit SV health code */ 4543285612Sdelphij p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val); 4544285612Sdelphij /* "All Ones" has a special meaning" */ 4545285612Sdelphij if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */ 4546285612Sdelphij cp = "SV UNAVAILABLE"; 4547285612Sdelphij else { 4548285612Sdelphij /* The MSB contains a summary of the 3 MSBs of the 8 bit health code, 4549285612Sdelphij * indicating if the data sent by the satellite is OK or not. */ 4550285612Sdelphij p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" ); 4551285612Sdelphij 4552285612Sdelphij /* The 5 LSBs contain the status of the different signals sent by the satellite. */ 4553285612Sdelphij switch (tmp_val & 0x1F) 4554285612Sdelphij { 4555285612Sdelphij case 0x00: cp = "SIGNAL OK"; break; 4556285612Sdelphij /* codes 0x01 through 0x1B indicate that one or more 4557285612Sdelphij * specific signal components are weak or dead. 4558285612Sdelphij * We don't decode this here in detail. */ 4559285612Sdelphij case 0x1C: cp = "SV IS TEMP OUT"; break; 4560285612Sdelphij case 0x1D: cp = "SV WILL BE TEMP OUT"; break; 4561285612Sdelphij default: cp = "TRANSMISSION PROBLEMS"; break; 4562285612Sdelphij } 456354359Sroberto } 4564285612Sdelphij p = ap(buffer, sizeof(buffer), p, "%s)", cp ); 4565285612Sdelphij 4566285612Sdelphij tmp_val = cfgh.cfg[i]; /* a 4 bit SV configuration/type code */ 4567285612Sdelphij p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val); 4568285612Sdelphij switch (tmp_val & 0x7) 456954359Sroberto { 4570285612Sdelphij case 0x00: cp = "(reserved)"; break; 4571285612Sdelphij case 0x01: cp = "BLOCK II/IIA/IIR"; break; 4572285612Sdelphij case 0x02: cp = "BLOCK IIR-M"; break; 4573285612Sdelphij case 0x03: cp = "BLOCK IIF"; break; 4574285612Sdelphij case 0x04: cp = "BLOCK III"; break; 4575285612Sdelphij default: cp = "unknown SV type"; break; 457654359Sroberto } 4577285612Sdelphij p = ap(buffer, sizeof(buffer), p, "%s", cp ); 4578285612Sdelphij if (tmp_val & 0x08) /* A-S is on, P-code is encrypted */ 4579285612Sdelphij p = ap( buffer, sizeof(buffer), p, ", A-S on" ); 4580285612Sdelphij 4581285612Sdelphij p = ap(buffer, sizeof(buffer), p, ")\""); 4582285612Sdelphij set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 458354359Sroberto } 458454359Sroberto } 458554359Sroberto } 458654359Sroberto break; 4587285612Sdelphij 458854359Sroberto case GPS_ALM: 458954359Sroberto break; 4590285612Sdelphij 459154359Sroberto case GPS_EPH: 459254359Sroberto break; 4593285612Sdelphij 459454359Sroberto case GPS_UTC: 459554359Sroberto { 459654359Sroberto UTC utc; 459754359Sroberto char buffer[512]; 459854359Sroberto char *p; 4599285612Sdelphij 460054359Sroberto p = buffer; 4601285612Sdelphij 460254359Sroberto get_mbg_utc(&bufp, &utc); 4603285612Sdelphij 460454359Sroberto if (utc.valid) 460554359Sroberto { 4606285612Sdelphij p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\""); 4607285612Sdelphij mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 460854359Sroberto p += strlen(p); 4609285612Sdelphij p = ap(buffer, sizeof(buffer), p, "\""); 461054359Sroberto } 461154359Sroberto else 461254359Sroberto { 4613285612Sdelphij p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\""); 461454359Sroberto } 4615285612Sdelphij set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 461654359Sroberto } 461754359Sroberto break; 4618285612Sdelphij 461954359Sroberto case GPS_IONO: 462054359Sroberto break; 4621285612Sdelphij 462254359Sroberto case GPS_ASCII_MSG: 462354359Sroberto { 462454359Sroberto ASCII_MSG gps_ascii_msg; 462554359Sroberto char buffer[128]; 4626285612Sdelphij 462754359Sroberto get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 4628285612Sdelphij 462954359Sroberto if (gps_ascii_msg.valid) 463054359Sroberto { 463154359Sroberto char buffer1[128]; 463254359Sroberto mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 4633285612Sdelphij 4634182007Sroberto snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 463554359Sroberto } 463654359Sroberto else 4637285612Sdelphij snprintf(buffer, sizeof(buffer), "gps_message=<NONE>"); 4638285612Sdelphij 4639285612Sdelphij set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 464054359Sroberto } 4641285612Sdelphij 464254359Sroberto break; 4643285612Sdelphij 464454359Sroberto default: 464554359Sroberto break; 464654359Sroberto } 464754359Sroberto } 464854359Sroberto else 464954359Sroberto { 4650285612Sdelphij msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), " 4651285612Sdelphij "data_len = %d, data_csum = 0x%x (expected 0x%x)", 465254359Sroberto CLK_UNIT(parse->peer), 4653285612Sdelphij header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 4654285612Sdelphij header.len, 4655285612Sdelphij header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0))); 465654359Sroberto } 465754359Sroberto } 4658285612Sdelphij 465954359Sroberto return; 466054359Sroberto} 466154359Sroberto 466254359Sroberto/*------------------------------------------------------------ 466354359Sroberto * gps16x_poll - query the reciver peridically 466454359Sroberto */ 466554359Srobertostatic void 466654359Srobertogps16x_poll( 466754359Sroberto struct peer *peer 466854359Sroberto ) 466954359Sroberto{ 4670285612Sdelphij struct parseunit *parse = peer->procptr->unitptr; 4671285612Sdelphij 4672285612Sdelphij static GPS_MSG_HDR sequence[] = 467354359Sroberto { 467454359Sroberto { GPS_SW_REV, 0, 0, 0 }, 4675285612Sdelphij { GPS_BVAR_STAT, 0, 0, 0 }, 467654359Sroberto { GPS_UTC, 0, 0, 0 }, 467754359Sroberto { GPS_ASCII_MSG, 0, 0, 0 }, 467854359Sroberto { GPS_ANT_INFO, 0, 0, 0 }, 467954359Sroberto { GPS_CFGH, 0, 0, 0 }, 468054359Sroberto { GPS_POS_XYZ, 0, 0, 0 }, 468154359Sroberto { GPS_POS_LLA, 0, 0, 0 }, 468254359Sroberto { (unsigned short)~0, 0, 0, 0 } 468354359Sroberto }; 4684285612Sdelphij 468554359Sroberto int rtc; 468654359Sroberto unsigned char cmd_buffer[64]; 468754359Sroberto unsigned char *outp = cmd_buffer; 468854359Sroberto GPS_MSG_HDR *header; 4689285612Sdelphij 469054359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 469154359Sroberto { 4692285612Sdelphij parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 469354359Sroberto } 469454359Sroberto 4695285612Sdelphij if (sequence[parse->localstate].cmd == (unsigned short)~0) 469654359Sroberto parse->localstate = 0; 4697285612Sdelphij 469854359Sroberto header = sequence + parse->localstate++; 4699285612Sdelphij 470054359Sroberto *outp++ = SOH; /* start command */ 4701285612Sdelphij 470254359Sroberto put_mbg_header(&outp, header); 470354359Sroberto outp = cmd_buffer + 1; 4704285612Sdelphij 4705285612Sdelphij header->hdr_csum = (short)mbg_csum(outp, 6); 470654359Sroberto put_mbg_header(&outp, header); 4707285612Sdelphij 470854359Sroberto#ifdef DEBUG 470954359Sroberto if (debug > 2) 471054359Sroberto { 471154359Sroberto char buffer[128]; 4712285612Sdelphij 471354359Sroberto mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 471454359Sroberto printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 471554359Sroberto CLK_UNIT(parse->peer), 471654359Sroberto parse->localstate - 1, 471754359Sroberto (int)(outp - cmd_buffer), 4718285612Sdelphij buffer); 471954359Sroberto } 472054359Sroberto#endif 4721285612Sdelphij 4722285612Sdelphij rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 4723285612Sdelphij 472454359Sroberto if (rtc < 0) 472554359Sroberto { 472654359Sroberto ERR(ERR_BADIO) 472754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 472854359Sroberto } 472954359Sroberto else 473054359Sroberto if (rtc != outp - cmd_buffer) 473154359Sroberto { 473254359Sroberto ERR(ERR_BADIO) 473354359Sroberto 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)); 473454359Sroberto } 473554359Sroberto 473654359Sroberto clear_err(parse, ERR_BADIO); 473754359Sroberto return; 473854359Sroberto} 473954359Sroberto 474054359Sroberto/*-------------------------------------------------- 474154359Sroberto * init routine - setup timer 474254359Sroberto */ 474354359Srobertostatic int 474454359Srobertogps16x_poll_init( 474554359Sroberto struct parseunit *parse 474654359Sroberto ) 474754359Sroberto{ 474854359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 474954359Sroberto { 4750285612Sdelphij parse->peer->procptr->action = gps16x_poll; 475154359Sroberto gps16x_poll(parse->peer); 475254359Sroberto } 475354359Sroberto 475454359Sroberto return 0; 475554359Sroberto} 475654359Sroberto 475754359Sroberto#else 475854359Srobertostatic void 475954359Srobertogps16x_message( 476054359Sroberto struct parseunit *parse, 476154359Sroberto parsetime_t *parsetime 476254359Sroberto ) 476354359Sroberto{} 476454359Srobertostatic int 476554359Srobertogps16x_poll_init( 476654359Sroberto struct parseunit *parse 476754359Sroberto ) 476854359Sroberto{ 476954359Sroberto return 1; 477054359Sroberto} 477154359Sroberto#endif /* CLOCK_MEINBERG */ 4772285612Sdelphij 477354359Sroberto/**=========================================================================== 477454359Sroberto ** clock polling support 477554359Sroberto **/ 477654359Sroberto 477754359Sroberto/*-------------------------------------------------- 477854359Sroberto * direct poll routine 477954359Sroberto */ 478054359Srobertostatic void 478154359Srobertopoll_dpoll( 478254359Sroberto struct parseunit *parse 478354359Sroberto ) 478454359Sroberto{ 4785285612Sdelphij long rtc; 478654359Sroberto const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 4787285612Sdelphij long ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 478854359Sroberto 4789285612Sdelphij rtc = write(parse->generic->io.fd, ps, ct); 479054359Sroberto if (rtc < 0) 479154359Sroberto { 479254359Sroberto ERR(ERR_BADIO) 479354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 479454359Sroberto } 479554359Sroberto else 479654359Sroberto if (rtc != ct) 479754359Sroberto { 479854359Sroberto ERR(ERR_BADIO) 4799285612Sdelphij msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 480054359Sroberto } 480154359Sroberto clear_err(parse, ERR_BADIO); 480254359Sroberto} 480354359Sroberto 480454359Sroberto/*-------------------------------------------------- 480554359Sroberto * periodic poll routine 480654359Sroberto */ 480754359Srobertostatic void 480854359Srobertopoll_poll( 480954359Sroberto struct peer *peer 481054359Sroberto ) 481154359Sroberto{ 4812285612Sdelphij struct parseunit *parse = peer->procptr->unitptr; 4813285612Sdelphij 481454359Sroberto if (parse->parse_type->cl_poll) 481554359Sroberto parse->parse_type->cl_poll(parse); 481654359Sroberto 481754359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 481854359Sroberto { 4819285612Sdelphij parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 482054359Sroberto } 482154359Sroberto} 482254359Sroberto 482354359Sroberto/*-------------------------------------------------- 482454359Sroberto * init routine - setup timer 482554359Sroberto */ 482654359Srobertostatic int 482754359Srobertopoll_init( 482854359Sroberto struct parseunit *parse 482954359Sroberto ) 483054359Sroberto{ 483154359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 483254359Sroberto { 4833285612Sdelphij parse->peer->procptr->action = poll_poll; 483454359Sroberto poll_poll(parse->peer); 483554359Sroberto } 483654359Sroberto 483754359Sroberto return 0; 483854359Sroberto} 4839285612Sdelphij 484054359Sroberto/**=========================================================================== 484154359Sroberto ** Trimble support 484254359Sroberto **/ 484354359Sroberto 484454359Sroberto/*------------------------------------------------------------- 484554359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init. 484654359Sroberto */ 484754359Srobertostatic int 484854359Srobertotrimbletaip_init( 484954359Sroberto struct parseunit *parse 485054359Sroberto ) 485154359Sroberto{ 485254359Sroberto#ifdef HAVE_TERMIOS 485354359Sroberto struct termios tio; 485454359Sroberto#endif 485554359Sroberto#ifdef HAVE_SYSV_TTYS 485654359Sroberto struct termio tio; 485754359Sroberto#endif 485854359Sroberto /* 485954359Sroberto * configure terminal line for trimble receiver 486054359Sroberto */ 486154359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 486254359Sroberto { 486354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 486454359Sroberto return 0; 486554359Sroberto } 486654359Sroberto else 486754359Sroberto { 486854359Sroberto tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 4869285612Sdelphij 487054359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 487154359Sroberto { 487254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 487354359Sroberto return 0; 487454359Sroberto } 487554359Sroberto } 487654359Sroberto return poll_init(parse); 487754359Sroberto} 487854359Sroberto 487954359Sroberto/*-------------------------------------------------- 488054359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble 488154359Sroberto */ 488254359Srobertostatic const char *taipinit[] = { 488354359Sroberto ">FPV00000000<", 488454359Sroberto ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 488554359Sroberto ">FTM00020001<", 488654359Sroberto (char *)0 488754359Sroberto}; 4888285612Sdelphij 488954359Srobertostatic void 489054359Srobertotrimbletaip_event( 489154359Sroberto struct parseunit *parse, 489254359Sroberto int event 489354359Sroberto ) 489454359Sroberto{ 489554359Sroberto switch (event) 489654359Sroberto { 489754359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 489854359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 489954359Sroberto { 490054359Sroberto const char **iv; 490154359Sroberto 490254359Sroberto iv = taipinit; 490354359Sroberto while (*iv) 490454359Sroberto { 4905285612Sdelphij int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv)); 490654359Sroberto if (rtc < 0) 490754359Sroberto { 490854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 490954359Sroberto return; 491054359Sroberto } 491154359Sroberto else 491254359Sroberto { 4913285612Sdelphij if (rtc != (int)strlen(*iv)) 491454359Sroberto { 491554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 491654359Sroberto CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 491754359Sroberto return; 491854359Sroberto } 491954359Sroberto } 492054359Sroberto iv++; 492154359Sroberto } 492254359Sroberto 492354359Sroberto NLOG(NLOG_CLOCKINFO) 492454359Sroberto ERR(ERR_BADIO) 492554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 492654359Sroberto CLK_UNIT(parse->peer)); 492754359Sroberto } 492854359Sroberto break; 492954359Sroberto 493054359Sroberto default: /* ignore */ 493154359Sroberto break; 493254359Sroberto } 493354359Sroberto} 493454359Sroberto 493554359Sroberto/* 493654359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module. 493754359Sroberto * It should support other Trimble receivers which use the Trimble Standard 493854359Sroberto * Interface Protocol (see below). 493954359Sroberto * 494054359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second 494154359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is 494254359Sroberto * coincident with the change of the GPS second. This is the same as 494354359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks 494454359Sroberto * specifically use a feature in the data message as a timing reference, but 494554359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter 494654359Sroberto * on the timing of the messages, so this driver only supports the use 494754359Sroberto * of the PPS pulse for accurate timing. Where it is determined that 494854359Sroberto * the offset is way off, when first starting up ntpd for example, 494954359Sroberto * the timing of the data stream is used until the offset becomes low enough 495056746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used. 495154359Sroberto * 495254359Sroberto * It can use either option for receiving PPS information - the 'ppsclock' 495354359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier 495454359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only 495554359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in 495654359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter 495754359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another 495854359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input, 495954359Sroberto * by whichever method, is handled in ntp_loopfilter.c 496054359Sroberto * 496154359Sroberto * The receiver uses a serial message protocol called Trimble Standard 496254359Sroberto * Interface Protocol (it can support others but this driver only supports 496354359Sroberto * TSIP). Messages in this protocol have the following form: 496454359Sroberto * 496554359Sroberto * <DLE><id> ... <data> ... <DLE><ETX> 496654359Sroberto * 496754359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 496854359Sroberto * on transmission and compressed back to one on reception. Otherwise 496954359Sroberto * the values of data bytes can be anything. The serial interface is RS-422 497054359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 497154359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single, 497254359Sroberto * and double datatypes. Integers are two bytes, sent most significant first. 497354359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent 497454359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point 497554359Sroberto * numbers (8 byte) sent sign & exponent first. 497654359Sroberto * The receiver supports a large set of messages, only a small subset of 497754359Sroberto * which are used here. From driver to receiver the following are used: 497854359Sroberto * 497954359Sroberto * ID Description 498054359Sroberto * 498154359Sroberto * 21 Request current time 498254359Sroberto * 22 Mode Select 498354359Sroberto * 2C Set/Request operating parameters 498454359Sroberto * 2F Request UTC info 498554359Sroberto * 35 Set/Request I/O options 498654359Sroberto 498754359Sroberto * From receiver to driver the following are recognised: 498854359Sroberto * 498954359Sroberto * ID Description 499054359Sroberto * 499154359Sroberto * 41 GPS Time 499254359Sroberto * 44 Satellite selection, PDOP, mode 499354359Sroberto * 46 Receiver health 499454359Sroberto * 4B Machine code/status 499554359Sroberto * 4C Report operating parameters (debug only) 499654359Sroberto * 4F UTC correction data (used to get leap second warnings) 499754359Sroberto * 55 I/O options (debug only) 499854359Sroberto * 499954359Sroberto * All others are accepted but ignored. 500054359Sroberto * 500154359Sroberto */ 500254359Sroberto 500354359Sroberto#define PI 3.1415926535898 /* lots of sig figs */ 500454359Sroberto#define D2R PI/180.0 500554359Sroberto 500654359Sroberto/*------------------------------------------------------------------- 500754359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 500854359Sroberto * interface to the receiver. 500954359Sroberto * 501054359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and 501154359Sroberto * float implementation dependend - these must be converted to portable 501254359Sroberto * versions ! 501354359Sroberto * 501454359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems 501554359Sroberto * with IEEE754 floats as native floats 501654359Sroberto */ 501754359Sroberto 501854359Srobertotypedef struct trimble 501954359Sroberto{ 502054359Sroberto u_long last_msg; /* last message received */ 5021182007Sroberto u_long last_reset; /* last time a reset was issued */ 502254359Sroberto u_char qtracking; /* query tracking status */ 502354359Sroberto u_long ctrack; /* current tracking set */ 502454359Sroberto u_long ltrack; /* last tracking set */ 502554359Sroberto} trimble_t; 502654359Sroberto 502754359Srobertounion uval { 502854359Sroberto u_char bd[8]; 502954359Sroberto int iv; 503054359Sroberto float fv; 503154359Sroberto double dv; 503254359Sroberto}; 5033285612Sdelphij 503454359Srobertostruct txbuf 503554359Sroberto{ 503654359Sroberto short idx; /* index to first unused byte */ 503754359Sroberto u_char *txt; /* pointer to actual data buffer */ 503854359Sroberto}; 503954359Sroberto 5040285612Sdelphijvoid sendcmd (struct txbuf *buf, int c); 5041285612Sdelphijvoid sendbyte (struct txbuf *buf, int b); 5042285612Sdelphijvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5043285612Sdelphijvoid sendint (struct txbuf *buf, int a); 5044285612Sdelphijvoid sendflt (struct txbuf *buf, double a); 5045285612Sdelphij 504654359Srobertovoid 504754359Srobertosendcmd( 504854359Sroberto struct txbuf *buf, 504954359Sroberto int c 505054359Sroberto ) 505154359Sroberto{ 505254359Sroberto buf->txt[0] = DLE; 505354359Sroberto buf->txt[1] = (u_char)c; 505454359Sroberto buf->idx = 2; 505554359Sroberto} 505654359Sroberto 5057285612Sdelphijvoid sendcmd (struct txbuf *buf, int c); 5058285612Sdelphijvoid sendbyte (struct txbuf *buf, int b); 5059285612Sdelphijvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5060285612Sdelphijvoid sendint (struct txbuf *buf, int a); 5061285612Sdelphijvoid sendflt (struct txbuf *buf, double a); 5062285612Sdelphij 506354359Srobertovoid 506454359Srobertosendbyte( 506554359Sroberto struct txbuf *buf, 506654359Sroberto int b 506754359Sroberto ) 506854359Sroberto{ 506954359Sroberto if (b == DLE) 507054359Sroberto buf->txt[buf->idx++] = DLE; 507154359Sroberto buf->txt[buf->idx++] = (u_char)b; 507254359Sroberto} 507354359Sroberto 507454359Srobertovoid 507554359Srobertosendetx( 507654359Sroberto struct txbuf *buf, 507754359Sroberto struct parseunit *parse 507854359Sroberto ) 507954359Sroberto{ 508054359Sroberto buf->txt[buf->idx++] = DLE; 508154359Sroberto buf->txt[buf->idx++] = ETX; 508254359Sroberto 508354359Sroberto if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 508454359Sroberto { 508554359Sroberto ERR(ERR_BADIO) 508654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 508754359Sroberto } 508854359Sroberto else 508954359Sroberto { 509054359Sroberto#ifdef DEBUG 509154359Sroberto if (debug > 2) 509254359Sroberto { 509354359Sroberto char buffer[256]; 5094285612Sdelphij 509554359Sroberto mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 509654359Sroberto printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 509754359Sroberto CLK_UNIT(parse->peer), 5098285612Sdelphij buf->idx, buffer); 509954359Sroberto } 510054359Sroberto#endif 510154359Sroberto clear_err(parse, ERR_BADIO); 510254359Sroberto } 510354359Sroberto} 510454359Sroberto 5105285612Sdelphijvoid 510654359Srobertosendint( 510754359Sroberto struct txbuf *buf, 510854359Sroberto int a 510954359Sroberto ) 511054359Sroberto{ 511154359Sroberto /* send 16bit int, msbyte first */ 511254359Sroberto sendbyte(buf, (u_char)((a>>8) & 0xff)); 511354359Sroberto sendbyte(buf, (u_char)(a & 0xff)); 511454359Sroberto} 511554359Sroberto 511654359Srobertovoid 511754359Srobertosendflt( 511854359Sroberto struct txbuf *buf, 511954359Sroberto double a 512054359Sroberto ) 512154359Sroberto{ 512254359Sroberto int i; 512354359Sroberto union uval uval; 512454359Sroberto 5125285612Sdelphij uval.fv = (float) a; 512654359Sroberto#ifdef WORDS_BIGENDIAN 512754359Sroberto for (i=0; i<=3; i++) 512854359Sroberto#else 512954359Sroberto for (i=3; i>=0; i--) 513054359Sroberto#endif 513154359Sroberto sendbyte(buf, uval.bd[i]); 513254359Sroberto} 513354359Sroberto 513454359Sroberto#define TRIM_POS_OPT 0x13 /* output position with high precision */ 513554359Sroberto#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 513654359Sroberto 513754359Sroberto/*-------------------------------------------------- 513854359Sroberto * trimble TSIP setup routine 513954359Sroberto */ 514054359Srobertostatic int 514154359Srobertotrimbletsip_setup( 514254359Sroberto struct parseunit *parse, 514354359Sroberto const char *reason 514456746Sroberto ) 514554359Sroberto{ 514654359Sroberto u_char buffer[256]; 514754359Sroberto struct txbuf buf; 5148182007Sroberto trimble_t *t = parse->localdata; 514954359Sroberto 5150182007Sroberto if (t && t->last_reset && 5151182007Sroberto ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 5152182007Sroberto return 1; /* not yet */ 5153182007Sroberto } 5154182007Sroberto 5155182007Sroberto if (t) 5156182007Sroberto t->last_reset = current_time; 5157285612Sdelphij 515854359Sroberto buf.txt = buffer; 5159285612Sdelphij 516054359Sroberto sendcmd(&buf, CMD_CVERSION); /* request software versions */ 516156746Sroberto sendetx(&buf, parse); 5162285612Sdelphij 516354359Sroberto sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 516456746Sroberto sendbyte(&buf, 4); /* static */ 516556746Sroberto sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 516656746Sroberto sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 516756746Sroberto sendflt(&buf, 12.0); /* PDOP mask = 12 */ 516856746Sroberto sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 516956746Sroberto sendetx(&buf, parse); 5170285612Sdelphij 517154359Sroberto sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 5172182007Sroberto sendbyte(&buf, 1); /* time transfer mode */ 517356746Sroberto sendetx(&buf, parse); 5174285612Sdelphij 517554359Sroberto sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 517656746Sroberto sendetx(&buf, parse); 5177285612Sdelphij 517854359Sroberto sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 517956746Sroberto sendbyte(&buf, 0x2); /* binary mode */ 518056746Sroberto sendetx(&buf, parse); 5181285612Sdelphij 518254359Sroberto sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 518354359Sroberto sendbyte(&buf, TRIM_POS_OPT); /* position output */ 518454359Sroberto sendbyte(&buf, 0x00); /* no velocity output */ 518554359Sroberto sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 518654359Sroberto sendbyte(&buf, 0x00); /* no raw measurements */ 518756746Sroberto sendetx(&buf, parse); 5188285612Sdelphij 518954359Sroberto sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 519054359Sroberto sendetx(&buf, parse); 519154359Sroberto 519254359Sroberto NLOG(NLOG_CLOCKINFO) 519354359Sroberto ERR(ERR_BADIO) 519454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 519554359Sroberto 519654359Sroberto return 0; 519754359Sroberto} 519854359Sroberto 519954359Sroberto/*-------------------------------------------------- 520054359Sroberto * TRIMBLE TSIP check routine 520154359Sroberto */ 520254359Srobertostatic void 520354359Srobertotrimble_check( 520454359Sroberto struct peer *peer 520554359Sroberto ) 520654359Sroberto{ 5207285612Sdelphij struct parseunit *parse = peer->procptr->unitptr; 520854359Sroberto trimble_t *t = parse->localdata; 520954359Sroberto u_char buffer[256]; 521054359Sroberto struct txbuf buf; 521154359Sroberto buf.txt = buffer; 5212285612Sdelphij 521354359Sroberto if (t) 521454359Sroberto { 521554359Sroberto if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 521654359Sroberto (void)trimbletsip_setup(parse, "message timeout"); 521754359Sroberto } 5218182007Sroberto 521954359Sroberto poll_poll(parse->peer); /* emit query string and re-arm timer */ 5220285612Sdelphij 5221182007Sroberto if (t && t->qtracking) 522254359Sroberto { 522354359Sroberto u_long oldsats = t->ltrack & ~t->ctrack; 5224285612Sdelphij 522554359Sroberto t->qtracking = 0; 522654359Sroberto t->ltrack = t->ctrack; 5227285612Sdelphij 522854359Sroberto if (oldsats) 522954359Sroberto { 523054359Sroberto int i; 5231285612Sdelphij 5232182007Sroberto for (i = 0; oldsats; i++) { 523354359Sroberto if (oldsats & (1 << i)) 523454359Sroberto { 523554359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 523654359Sroberto sendbyte(&buf, i+1); /* old sat */ 523754359Sroberto sendetx(&buf, parse); 523854359Sroberto } 5239182007Sroberto oldsats &= ~(1 << i); 5240182007Sroberto } 524154359Sroberto } 5242285612Sdelphij 524354359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 524454359Sroberto sendbyte(&buf, 0x00); /* current tracking set */ 524554359Sroberto sendetx(&buf, parse); 524654359Sroberto } 524754359Sroberto} 524854359Sroberto 524954359Sroberto/*-------------------------------------------------- 525054359Sroberto * TRIMBLE TSIP end routine 525154359Sroberto */ 525254359Srobertostatic void 525354359Srobertotrimbletsip_end( 525454359Sroberto struct parseunit *parse 525554359Sroberto ) 525654359Sroberto{ trimble_t *t = parse->localdata; 5257285612Sdelphij 525854359Sroberto if (t) 525954359Sroberto { 526054359Sroberto free(t); 5261285612Sdelphij parse->localdata = NULL; 526254359Sroberto } 5263285612Sdelphij parse->peer->procptr->nextaction = 0; 5264285612Sdelphij parse->peer->procptr->action = NULL; 526554359Sroberto} 526654359Sroberto 526754359Sroberto/*-------------------------------------------------- 526854359Sroberto * TRIMBLE TSIP init routine 526954359Sroberto */ 527054359Srobertostatic int 527154359Srobertotrimbletsip_init( 527254359Sroberto struct parseunit *parse 527354359Sroberto ) 527454359Sroberto{ 527554359Sroberto#if defined(VEOL) || defined(VEOL2) 527654359Sroberto#ifdef HAVE_TERMIOS 527754359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 527854359Sroberto#endif 527954359Sroberto#ifdef HAVE_SYSV_TTYS 528054359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 528154359Sroberto#endif 528254359Sroberto /* 528354359Sroberto * allocate local data area 528454359Sroberto */ 528554359Sroberto if (!parse->localdata) 528654359Sroberto { 528754359Sroberto trimble_t *t; 5288285612Sdelphij 528954359Sroberto t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 5290285612Sdelphij 529154359Sroberto if (t) 529254359Sroberto { 529354359Sroberto memset((char *)t, 0, sizeof(trimble_t)); 529454359Sroberto t->last_msg = current_time; 529554359Sroberto } 529654359Sroberto } 529754359Sroberto 5298285612Sdelphij parse->peer->procptr->action = trimble_check; 5299285612Sdelphij parse->peer->procptr->nextaction = current_time; 530054359Sroberto 530154359Sroberto /* 530254359Sroberto * configure terminal line for ICANON mode with VEOL characters 530354359Sroberto */ 530454359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 530554359Sroberto { 530654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 530754359Sroberto return 0; 530854359Sroberto } 530954359Sroberto else 531054359Sroberto { 531154359Sroberto if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 531254359Sroberto { 531354359Sroberto#ifdef VEOL 531454359Sroberto tio.c_cc[VEOL] = ETX; 531554359Sroberto#endif 531654359Sroberto#ifdef VEOL2 531754359Sroberto tio.c_cc[VEOL2] = DLE; 531854359Sroberto#endif 531956746Sroberto } 532054359Sroberto 532154359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 532254359Sroberto { 532354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 532454359Sroberto return 0; 532554359Sroberto } 532654359Sroberto } 532754359Sroberto#endif 532854359Sroberto return trimbletsip_setup(parse, "initial startup"); 532954359Sroberto} 533054359Sroberto 533154359Sroberto/*------------------------------------------------------------ 533254359Sroberto * trimbletsip_event - handle Trimble events 533354359Sroberto * simple evente handler - attempt to re-initialize receiver 533454359Sroberto */ 533554359Srobertostatic void 533654359Srobertotrimbletsip_event( 533754359Sroberto struct parseunit *parse, 533854359Sroberto int event 533954359Sroberto ) 534054359Sroberto{ 534154359Sroberto switch (event) 534254359Sroberto { 534354359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 534454359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 534554359Sroberto (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 534654359Sroberto break; 534754359Sroberto 534854359Sroberto default: /* ignore */ 534954359Sroberto break; 535054359Sroberto } 535154359Sroberto} 535254359Sroberto 535354359Sroberto/* 535454359Sroberto * getflt, getint convert fields in the incoming data into the 535554359Sroberto * appropriate type of item 535654359Sroberto * 535754359Sroberto * CAVEAT: these routines are currently definitely byte order dependent 535854359Sroberto * and assume Representation(float) == IEEE754 535954359Sroberto * These functions MUST be converted to portable versions (especially 536054359Sroberto * converting the float representation into ntp_fp formats in order 536154359Sroberto * to avoid floating point operations at all! 536254359Sroberto */ 536354359Sroberto 536454359Srobertostatic float 536554359Srobertogetflt( 536654359Sroberto u_char *bp 536754359Sroberto ) 536854359Sroberto{ 536954359Sroberto union uval uval; 5370285612Sdelphij 537154359Sroberto#ifdef WORDS_BIGENDIAN 537254359Sroberto uval.bd[0] = *bp++; 537354359Sroberto uval.bd[1] = *bp++; 537454359Sroberto uval.bd[2] = *bp++; 537554359Sroberto uval.bd[3] = *bp; 537654359Sroberto#else /* ! WORDS_BIGENDIAN */ 537754359Sroberto uval.bd[3] = *bp++; 537854359Sroberto uval.bd[2] = *bp++; 537954359Sroberto uval.bd[1] = *bp++; 538054359Sroberto uval.bd[0] = *bp; 538154359Sroberto#endif /* ! WORDS_BIGENDIAN */ 538254359Sroberto return uval.fv; 538354359Sroberto} 538454359Sroberto 538554359Srobertostatic double 538654359Srobertogetdbl( 538754359Sroberto u_char *bp 538854359Sroberto ) 538954359Sroberto{ 539054359Sroberto union uval uval; 5391285612Sdelphij 539254359Sroberto#ifdef WORDS_BIGENDIAN 539354359Sroberto uval.bd[0] = *bp++; 539454359Sroberto uval.bd[1] = *bp++; 539554359Sroberto uval.bd[2] = *bp++; 539654359Sroberto uval.bd[3] = *bp++; 539754359Sroberto uval.bd[4] = *bp++; 539854359Sroberto uval.bd[5] = *bp++; 539954359Sroberto uval.bd[6] = *bp++; 540054359Sroberto uval.bd[7] = *bp; 540154359Sroberto#else /* ! WORDS_BIGENDIAN */ 540254359Sroberto uval.bd[7] = *bp++; 540354359Sroberto uval.bd[6] = *bp++; 540454359Sroberto uval.bd[5] = *bp++; 540554359Sroberto uval.bd[4] = *bp++; 540654359Sroberto uval.bd[3] = *bp++; 540754359Sroberto uval.bd[2] = *bp++; 540854359Sroberto uval.bd[1] = *bp++; 540954359Sroberto uval.bd[0] = *bp; 541054359Sroberto#endif /* ! WORDS_BIGENDIAN */ 541154359Sroberto return uval.dv; 541254359Sroberto} 541354359Sroberto 541454359Srobertostatic int 541554359Srobertogetshort( 541654359Sroberto unsigned char *p 541754359Sroberto ) 541854359Sroberto{ 5419285612Sdelphij return (int) get_msb_short(&p); 542054359Sroberto} 542154359Sroberto 542254359Sroberto/*-------------------------------------------------- 542354359Sroberto * trimbletsip_message - process trimble messages 542454359Sroberto */ 542554359Sroberto#define RTOD (180.0 / 3.1415926535898) 542654359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 542754359Sroberto 542854359Srobertostatic void 542954359Srobertotrimbletsip_message( 543054359Sroberto struct parseunit *parse, 543154359Sroberto parsetime_t *parsetime 543254359Sroberto ) 543354359Sroberto{ 543454359Sroberto unsigned char *buffer = parsetime->parse_msg; 543554359Sroberto unsigned int size = parsetime->parse_msglen; 5436285612Sdelphij 543754359Sroberto if ((size < 4) || 543854359Sroberto (buffer[0] != DLE) || 543954359Sroberto (buffer[size-1] != ETX) || 544054359Sroberto (buffer[size-2] != DLE)) 544154359Sroberto { 544254359Sroberto#ifdef DEBUG 544354359Sroberto if (debug > 2) { 5444285612Sdelphij size_t i; 544554359Sroberto 544654359Sroberto printf("TRIMBLE BAD packet, size %d:\n ", size); 544754359Sroberto for (i = 0; i < size; i++) { 544854359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 544954359Sroberto if (i%16 == 15) printf("\n\t"); 545054359Sroberto } 545154359Sroberto printf("\n"); 545254359Sroberto } 545354359Sroberto#endif 545454359Sroberto return; 545554359Sroberto } 545654359Sroberto else 545754359Sroberto { 5458285612Sdelphij u_short var_flag; 545954359Sroberto trimble_t *tr = parse->localdata; 546054359Sroberto unsigned int cmd = buffer[1]; 546154359Sroberto char pbuffer[200]; 546254359Sroberto char *t = pbuffer; 546354359Sroberto cmd_info_t *s; 5464285612Sdelphij 546554359Sroberto#ifdef DEBUG 546654359Sroberto if (debug > 3) { 5467285612Sdelphij size_t i; 546854359Sroberto 546954359Sroberto printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 547054359Sroberto for (i = 0; i < size; i++) { 547154359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 547254359Sroberto if (i%16 == 15) printf("\n\t"); 547354359Sroberto } 547454359Sroberto printf("\n"); 547554359Sroberto } 547654359Sroberto#endif 547754359Sroberto 547854359Sroberto if (tr) 547954359Sroberto tr->last_msg = current_time; 5480285612Sdelphij 548154359Sroberto s = trimble_convert(cmd, trimble_rcmds); 5482285612Sdelphij 548354359Sroberto if (s) 548454359Sroberto { 5485285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname); 548654359Sroberto } 548754359Sroberto else 548854359Sroberto { 5489182007Sroberto DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 549054359Sroberto return; 549154359Sroberto } 549254359Sroberto 5493285612Sdelphij var_flag = (u_short) s->varmode; 549454359Sroberto 549554359Sroberto switch(cmd) 549654359Sroberto { 549754359Sroberto case CMD_RCURTIME: 5498285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f", 5499182007Sroberto getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5500182007Sroberto getflt((unsigned char *)&mb(6))); 550154359Sroberto break; 5502285612Sdelphij 550354359Sroberto case CMD_RBEST4: 5504285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 550554359Sroberto switch (mb(0) & 0xF) 550654359Sroberto { 550754359Sroberto default: 5508285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, 5509285612Sdelphij "0x%x", mb(0) & 0x7); 551054359Sroberto break; 551154359Sroberto 551254359Sroberto case 1: 5513285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "0D"); 551454359Sroberto break; 5515285612Sdelphij 551654359Sroberto case 3: 5517285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 551854359Sroberto break; 5519285612Sdelphij 552054359Sroberto case 4: 5521285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 552254359Sroberto break; 552354359Sroberto } 552454359Sroberto if (mb(0) & 0x10) 5525285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 552654359Sroberto else 5527285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5528285612Sdelphij 5529285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 553054359Sroberto mb(1), mb(2), mb(3), mb(4), 553154359Sroberto getflt((unsigned char *)&mb(5)), 553254359Sroberto getflt((unsigned char *)&mb(9)), 553354359Sroberto getflt((unsigned char *)&mb(13)), 553454359Sroberto getflt((unsigned char *)&mb(17))); 553554359Sroberto 553654359Sroberto break; 5537285612Sdelphij 553854359Sroberto case CMD_RVERSION: 5539285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)", 554054359Sroberto mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 554154359Sroberto break; 5542285612Sdelphij 554354359Sroberto case CMD_RRECVHEALTH: 554454359Sroberto { 554554359Sroberto static const char *msgs[] = 554654359Sroberto { 554754359Sroberto "Battery backup failed", 554854359Sroberto "Signal processor error", 554954359Sroberto "Alignment error, channel or chip 1", 555054359Sroberto "Alignment error, channel or chip 2", 555154359Sroberto "Antenna feed line fault", 555254359Sroberto "Excessive ref freq. error", 555354359Sroberto "<BIT 6>", 555454359Sroberto "<BIT 7>" 555554359Sroberto }; 5556285612Sdelphij 555754359Sroberto int i, bits; 5558285612Sdelphij 555954359Sroberto switch (mb(0) & 0xFF) 556054359Sroberto { 556154359Sroberto default: 5562285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF); 556354359Sroberto break; 556454359Sroberto case 0x00: 5565285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes"); 556654359Sroberto break; 556754359Sroberto case 0x01: 5568285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet"); 556954359Sroberto break; 557054359Sroberto case 0x03: 5571285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high"); 557254359Sroberto break; 557354359Sroberto case 0x08: 5574285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites"); 557554359Sroberto break; 557654359Sroberto case 0x09: 5577285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite"); 557854359Sroberto break; 557954359Sroberto case 0x0A: 5580285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites"); 558154359Sroberto break; 558254359Sroberto case 0x0B: 5583285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites"); 558454359Sroberto break; 558554359Sroberto case 0x0C: 5586285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable"); 558754359Sroberto break; 558854359Sroberto } 558954359Sroberto 5590285612Sdelphij bits = mb(1) & 0xFF; 559154359Sroberto 559254359Sroberto for (i = 0; i < 8; i++) 559354359Sroberto if (bits & (0x1<<i)) 559454359Sroberto { 5595285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 559654359Sroberto } 559754359Sroberto } 559854359Sroberto break; 5599285612Sdelphij 560054359Sroberto case CMD_RMESSAGE: 5601182007Sroberto mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 560254359Sroberto break; 5603285612Sdelphij 560454359Sroberto case CMD_RMACHSTAT: 560554359Sroberto { 560654359Sroberto static const char *msgs[] = 560754359Sroberto { 560854359Sroberto "Synthesizer Fault", 560954359Sroberto "Battery Powered Time Clock Fault", 561054359Sroberto "A-to-D Converter Fault", 561154359Sroberto "The almanac stored in the receiver is not complete and current", 561254359Sroberto "<BIT 4>", 561354359Sroberto "<BIT 5", 561454359Sroberto "<BIT 6>", 561554359Sroberto "<BIT 7>" 561654359Sroberto }; 5617285612Sdelphij 561854359Sroberto int i, bits; 561954359Sroberto 5620285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF); 562154359Sroberto bits = mb(1) & 0xFF; 5622285612Sdelphij 562354359Sroberto for (i = 0; i < 8; i++) 562454359Sroberto if (bits & (0x1<<i)) 562554359Sroberto { 5626285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 562754359Sroberto } 562854359Sroberto 5629285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 563054359Sroberto } 563154359Sroberto break; 5632285612Sdelphij 563354359Sroberto case CMD_ROPERPARAM: 5634285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f", 563554359Sroberto mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 563654359Sroberto getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 563754359Sroberto break; 5638285612Sdelphij 563954359Sroberto case CMD_RUTCPARAM: 564054359Sroberto { 564154359Sroberto float t0t = getflt((unsigned char *)&mb(14)); 5642285612Sdelphij short wnt = (short) getshort((unsigned char *)&mb(18)); 5643285612Sdelphij short dtls = (short) getshort((unsigned char *)&mb(12)); 5644285612Sdelphij short wnlsf = (short) getshort((unsigned char *)&mb(20)); 5645285612Sdelphij short dn = (short) getshort((unsigned char *)&mb(22)); 5646285612Sdelphij short dtlsf = (short) getshort((unsigned char *)&mb(24)); 564754359Sroberto 564854359Sroberto if ((int)t0t != 0) 5649285612Sdelphij { 5650285612Sdelphij mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 5651285612Sdelphij } 565254359Sroberto else 5653285612Sdelphij { 5654285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>"); 5655285612Sdelphij } 565654359Sroberto } 565754359Sroberto break; 565854359Sroberto 565954359Sroberto case CMD_RSAT1BIAS: 5660285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs", 566154359Sroberto getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 566254359Sroberto break; 566354359Sroberto 566454359Sroberto case CMD_RIOOPTIONS: 566554359Sroberto { 5666285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x", 566754359Sroberto mb(0), mb(1), mb(2), mb(3)); 566854359Sroberto if (mb(0) != TRIM_POS_OPT || 566954359Sroberto mb(2) != TRIM_TIME_OPT) 567054359Sroberto { 567154359Sroberto (void)trimbletsip_setup(parse, "bad io options"); 567254359Sroberto } 567354359Sroberto } 567454359Sroberto break; 5675285612Sdelphij 567654359Sroberto case CMD_RSPOSXYZ: 567754359Sroberto { 567854359Sroberto double x = getflt((unsigned char *)&mb(0)); 567954359Sroberto double y = getflt((unsigned char *)&mb(4)); 568054359Sroberto double z = getflt((unsigned char *)&mb(8)); 568154359Sroberto double f = getflt((unsigned char *)&mb(12)); 5682285612Sdelphij 568354359Sroberto if (f > 0.0) 5684285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 568554359Sroberto x, y, z, 568654359Sroberto f); 568754359Sroberto else 5688285612Sdelphij return; 568954359Sroberto } 569054359Sroberto break; 569154359Sroberto 569254359Sroberto case CMD_RSLLAPOS: 569354359Sroberto { 569454359Sroberto double lat = getflt((unsigned char *)&mb(0)); 569554359Sroberto double lng = getflt((unsigned char *)&mb(4)); 569654359Sroberto double f = getflt((unsigned char *)&mb(12)); 5697285612Sdelphij 569854359Sroberto if (f > 0.0) 5699285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm", 570054359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 570154359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 570254359Sroberto getflt((unsigned char *)&mb(8))); 570354359Sroberto else 5704285612Sdelphij return; 570554359Sroberto } 570654359Sroberto break; 570754359Sroberto 570854359Sroberto case CMD_RDOUBLEXYZ: 570954359Sroberto { 571054359Sroberto double x = getdbl((unsigned char *)&mb(0)); 571154359Sroberto double y = getdbl((unsigned char *)&mb(8)); 571254359Sroberto double z = getdbl((unsigned char *)&mb(16)); 5713285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm", 571454359Sroberto x, y, z); 571554359Sroberto } 571654359Sroberto break; 5717285612Sdelphij 571854359Sroberto case CMD_RDOUBLELLA: 571954359Sroberto { 572054359Sroberto double lat = getdbl((unsigned char *)&mb(0)); 572154359Sroberto double lng = getdbl((unsigned char *)&mb(8)); 5722285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm", 572354359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 572454359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 572554359Sroberto getdbl((unsigned char *)&mb(16))); 572654359Sroberto } 572754359Sroberto break; 572854359Sroberto 572954359Sroberto case CMD_RALLINVIEW: 573054359Sroberto { 573154359Sroberto int i, sats; 5732285612Sdelphij 5733285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 573454359Sroberto switch (mb(0) & 0x7) 573554359Sroberto { 573654359Sroberto default: 5737285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7); 573854359Sroberto break; 573954359Sroberto 574054359Sroberto case 3: 5741285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 574254359Sroberto break; 5743285612Sdelphij 574454359Sroberto case 4: 5745285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 574654359Sroberto break; 574754359Sroberto } 574854359Sroberto if (mb(0) & 0x8) 5749285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 575054359Sroberto else 5751285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5752285612Sdelphij 575354359Sroberto sats = (mb(0)>>4) & 0xF; 5754285612Sdelphij 5755285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 575654359Sroberto getflt((unsigned char *)&mb(1)), 575754359Sroberto getflt((unsigned char *)&mb(5)), 575854359Sroberto getflt((unsigned char *)&mb(9)), 575954359Sroberto getflt((unsigned char *)&mb(13)), 576054359Sroberto sats, (sats == 1) ? "" : "s"); 576154359Sroberto 576254359Sroberto for (i=0; i < sats; i++) 576354359Sroberto { 5764285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i)); 576554359Sroberto if (tr) 576654359Sroberto tr->ctrack |= (1 << (mb(17+i)-1)); 576754359Sroberto } 576854359Sroberto 576954359Sroberto if (tr) 5770285612Sdelphij { /* mark for tracking status query */ 577154359Sroberto tr->qtracking = 1; 577254359Sroberto } 577354359Sroberto } 577454359Sroberto break; 5775285612Sdelphij 577654359Sroberto case CMD_RSTATTRACK: 577754359Sroberto { 5778285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */ 577954359Sroberto if (getflt((unsigned char *)&mb(4)) < 0.0) 578054359Sroberto { 5781285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>"); 5782285612Sdelphij var_flag &= (u_short)(~DEF); 578354359Sroberto } 578454359Sroberto else 5785285612Sdelphij { 5786285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 578754359Sroberto (mb(1) & 0xFF)>>3, 578854359Sroberto mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 578954359Sroberto mb(3), 579054359Sroberto getflt((unsigned char *)&mb(4)), 579154359Sroberto getflt((unsigned char *)&mb(12)) * RTOD, 579254359Sroberto getflt((unsigned char *)&mb(16)) * RTOD); 579354359Sroberto if (mb(20)) 579454359Sroberto { 5795285612Sdelphij var_flag &= (u_short)(~DEF); 5796285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, ", OLD"); 579754359Sroberto } 579854359Sroberto if (mb(22)) 579954359Sroberto { 580054359Sroberto if (mb(22) == 1) 5801285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY"); 580254359Sroberto else 580354359Sroberto if (mb(22) == 2) 5804285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH"); 580554359Sroberto } 580654359Sroberto if (mb(23)) 5807285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data"); 580854359Sroberto } 580954359Sroberto } 581054359Sroberto break; 5811285612Sdelphij 581254359Sroberto default: 5813285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>"); 581454359Sroberto break; 581554359Sroberto } 5816182007Sroberto 5817285612Sdelphij t = ap(pbuffer, sizeof(pbuffer), t, "\""); 581854359Sroberto set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 581954359Sroberto } 582054359Sroberto} 582154359Sroberto 5822285612Sdelphij 582354359Sroberto/**============================================================ 582454359Sroberto ** RAWDCF support 582554359Sroberto **/ 582654359Sroberto 582754359Sroberto/*-------------------------------------------------- 582856746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers 582956746Sroberto * SET DTR line 583054359Sroberto */ 583154359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 583254359Srobertostatic int 583356746Srobertorawdcf_init_1( 583454359Sroberto struct parseunit *parse 583554359Sroberto ) 583654359Sroberto{ 583782498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 583854359Sroberto /* 583954359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 584054359Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 584154359Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 584254359Sroberto */ 584382498Sroberto int sl232; 584482498Sroberto 584582498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 584682498Sroberto { 584782498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 584882498Sroberto return 0; 584982498Sroberto } 585082498Sroberto 585154359Sroberto#ifdef TIOCM_DTR 585282498Sroberto sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 585354359Sroberto#else 585482498Sroberto sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 585554359Sroberto#endif 585654359Sroberto 585754359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 585854359Sroberto { 585956746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 586054359Sroberto } 586154359Sroberto return 0; 586254359Sroberto} 586354359Sroberto#else 586454359Srobertostatic int 5865132451Srobertorawdcfdtr_init_1( 586654359Sroberto struct parseunit *parse 586754359Sroberto ) 586854359Sroberto{ 586956746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 587054359Sroberto return 0; 587154359Sroberto} 587254359Sroberto#endif /* DTR initialisation type */ 587354359Sroberto 587454359Sroberto/*-------------------------------------------------- 587556746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers 587656746Sroberto * CLR DTR line, SET RTS line 587754359Sroberto */ 587856746Sroberto#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 587954359Srobertostatic int 588056746Srobertorawdcf_init_2( 588154359Sroberto struct parseunit *parse 588254359Sroberto ) 588354359Sroberto{ 588482498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 588554359Sroberto /* 588654359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 588756746Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 588856746Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 588954359Sroberto */ 589082498Sroberto int sl232; 589182498Sroberto 589282498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 589382498Sroberto { 589482498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 589582498Sroberto return 0; 589682498Sroberto } 589782498Sroberto 589854359Sroberto#ifdef TIOCM_RTS 589982498Sroberto sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 590054359Sroberto#else 590182498Sroberto sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 590254359Sroberto#endif 590354359Sroberto 590454359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 590554359Sroberto { 590656746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 590754359Sroberto } 590854359Sroberto return 0; 590954359Sroberto} 591054359Sroberto#else 591154359Srobertostatic int 591256746Srobertorawdcf_init_2( 591354359Sroberto struct parseunit *parse 591454359Sroberto ) 591554359Sroberto{ 591656746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 591754359Sroberto return 0; 591854359Sroberto} 591956746Sroberto#endif /* DTR initialisation type */ 592054359Sroberto 592154359Sroberto#else /* defined(REFCLOCK) && defined(PARSE) */ 5922285612SdelphijNONEMPTY_TRANSLATION_UNIT 592354359Sroberto#endif /* defined(REFCLOCK) && defined(PARSE) */ 592454359Sroberto 592554359Sroberto/* 592654359Sroberto * History: 592754359Sroberto * 592854359Sroberto * refclock_parse.c,v 5929285612Sdelphij * Revision 4.81 2009/05/01 10:15:29 kardel 5930285612Sdelphij * use new refclock_ppsapi interface 5931285612Sdelphij * 5932182007Sroberto * Revision 4.80 2007/08/11 12:06:29 kardel 5933182007Sroberto * update comments wrt/ to PPS 5934182007Sroberto * 5935182007Sroberto * Revision 4.79 2007/08/11 11:52:23 kardel 5936182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor 5937182007Sroberto * 5938182007Sroberto * Revision 4.78 2006/12/22 20:08:27 kardel 5939182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5940182007Sroberto * 5941182007Sroberto * Revision 4.77 2006/08/05 07:44:49 kardel 5942182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5943182007Sroberto * 5944182007Sroberto * Revision 4.76 2006/06/22 18:40:47 kardel 5945182007Sroberto * clean up signedness (gcc 4) 5946182007Sroberto * 5947182007Sroberto * Revision 4.75 2006/06/22 16:58:10 kardel 5948182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5949182007Sroberto * the PPS offset. Fix sign of offset passed to kernel. 5950182007Sroberto * 5951182007Sroberto * Revision 4.74 2006/06/18 21:18:37 kardel 5952182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref 5953182007Sroberto * 5954182007Sroberto * Revision 4.73 2006/05/26 14:23:46 kardel 5955182007Sroberto * cleanup of copyright info 5956182007Sroberto * 5957182007Sroberto * Revision 4.72 2006/05/26 14:19:43 kardel 5958182007Sroberto * cleanup of ioctl cruft 5959182007Sroberto * 5960182007Sroberto * Revision 4.71 2006/05/26 14:15:57 kardel 5961182007Sroberto * delay adding refclock to async refclock io after all initializations 5962182007Sroberto * 5963182007Sroberto * Revision 4.70 2006/05/25 18:20:50 kardel 5964182007Sroberto * bug #619 5965182007Sroberto * terminate parse io engine after de-registering 5966182007Sroberto * from refclock io engine 5967182007Sroberto * 5968182007Sroberto * Revision 4.69 2006/05/25 17:28:02 kardel 5969182007Sroberto * complete refclock io structure initialization *before* inserting it into the 5970182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619) 5971182007Sroberto * 5972182007Sroberto * Revision 4.68 2006/05/01 17:02:51 kardel 5973182007Sroberto * copy receiver method also for newlwy created receive buffers 5974182007Sroberto * 5975182007Sroberto * Revision 4.67 2006/05/01 14:37:29 kardel 5976182007Sroberto * If an input buffer parses into more than one message do insert the 5977182007Sroberto * parsed message in a new input buffer instead of processing it 5978182007Sroberto * directly. This avoids deed complicated processing in signal 5979182007Sroberto * handling. 5980182007Sroberto * 5981182007Sroberto * Revision 4.66 2006/03/18 00:45:30 kardel 5982182007Sroberto * coverity fixes found in NetBSD coverity scan 5983182007Sroberto * 5984182007Sroberto * Revision 4.65 2006/01/26 06:08:33 kardel 5985182007Sroberto * output errno on PPS setup failure 5986182007Sroberto * 5987182007Sroberto * Revision 4.64 2005/11/09 20:44:47 kardel 5988182007Sroberto * utilize full PPS timestamp resolution from PPS API 5989182007Sroberto * 5990182007Sroberto * Revision 4.63 2005/10/07 22:10:25 kardel 5991182007Sroberto * bounded buffer implementation 5992182007Sroberto * 5993182007Sroberto * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 5994182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 5995182007Sroberto * replace almost all str* and *printf functions be their buffer bounded 5996182007Sroberto * counterparts 5997182007Sroberto * 5998182007Sroberto * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 5999182007Sroberto * limit re-set rate of trimble clocks 6000182007Sroberto * 6001182007Sroberto * Revision 4.62 2005/08/06 17:40:00 kardel 6002182007Sroberto * cleanup size handling wrt/ to buffer boundaries 6003182007Sroberto * 6004182007Sroberto * Revision 4.61 2005/07/27 21:16:19 kardel 6005182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 6006182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of 6007182007Sroberto * the DCF77 clocks. 6008182007Sroberto * 6009182007Sroberto * Revision 4.60 2005/07/17 21:14:44 kardel 6010182007Sroberto * change contents of version string to include the RCS/CVS Id 6011182007Sroberto * 6012182007Sroberto * Revision 4.59 2005/07/06 06:56:38 kardel 6013182007Sroberto * syntax error 6014182007Sroberto * 6015182007Sroberto * Revision 4.58 2005/07/04 13:10:40 kardel 6016182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup 6017182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 6018182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and 6019182007Sroberto * varying structure element sizes 6020182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers 6021182007Sroberto * 6022182007Sroberto * Revision 4.57 2005/06/25 09:25:19 kardel 6023182007Sroberto * sort out log output sequence 6024182007Sroberto * 6025182007Sroberto * Revision 4.56 2005/06/14 21:47:27 kardel 6026182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel) 6027182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 6028182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state 6029182007Sroberto * 6030182007Sroberto * Revision 4.55 2005/06/02 21:28:31 kardel 6031182007Sroberto * clarify trust logic 6032182007Sroberto * 6033182007Sroberto * Revision 4.54 2005/06/02 17:06:49 kardel 6034182007Sroberto * change status reporting to use fixed refclock_report() 6035182007Sroberto * 6036182007Sroberto * Revision 4.53 2005/06/02 16:33:31 kardel 6037182007Sroberto * fix acceptance of clocks unsync clocks right at start 6038182007Sroberto * 6039182007Sroberto * Revision 4.52 2005/05/26 21:55:06 kardel 6040182007Sroberto * cleanup status reporting 6041182007Sroberto * 6042182007Sroberto * Revision 4.51 2005/05/26 19:19:14 kardel 6043182007Sroberto * implement fast refclock startup 6044182007Sroberto * 6045182007Sroberto * Revision 4.50 2005/04/16 20:51:35 kardel 6046285612Sdelphij * set hardpps_enable = 1 when binding a kernel PPS source 6047182007Sroberto * 6048182007Sroberto * Revision 4.49 2005/04/16 17:29:26 kardel 6049182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks 6050182007Sroberto * 6051182007Sroberto * Revision 4.48 2005/04/16 16:22:27 kardel 6052182007Sroberto * bk sync 20050415 ntp-dev 6053182007Sroberto * 6054182007Sroberto * Revision 4.47 2004/11/29 10:42:48 kardel 6055182007Sroberto * bk sync ntp-dev 20041129 6056182007Sroberto * 6057182007Sroberto * Revision 4.46 2004/11/29 10:26:29 kardel 6058182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 6059182007Sroberto * 6060182007Sroberto * Revision 4.45 2004/11/14 20:53:20 kardel 6061182007Sroberto * clear PPS flags after using them 6062182007Sroberto * 6063182007Sroberto * Revision 4.44 2004/11/14 15:29:41 kardel 6064182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style 6065182007Sroberto * 6066182007Sroberto * Revision 4.43 2001/05/26 22:53:16 kardel 6067182007Sroberto * 20010526 reconcilation 6068182007Sroberto * 6069182007Sroberto * Revision 4.42 2000/05/14 15:31:51 kardel 6070182007Sroberto * PPSAPI && RAWDCF modemline support 6071182007Sroberto * 6072182007Sroberto * Revision 4.41 2000/04/09 19:50:45 kardel 6073182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1 6074182007Sroberto * 6075182007Sroberto * Revision 4.40 2000/04/09 15:27:55 kardel 6076182007Sroberto * modem line fiddle in rawdcf_init_2 6077182007Sroberto * 6078182007Sroberto * Revision 4.39 2000/03/18 09:16:55 kardel 6079182007Sroberto * PPSAPI integration 6080182007Sroberto * 6081182007Sroberto * Revision 4.38 2000/03/05 20:25:06 kardel 6082182007Sroberto * support PPSAPI 6083182007Sroberto * 6084182007Sroberto * Revision 4.37 2000/03/05 20:11:14 kardel 6085182007Sroberto * 4.0.99g reconcilation 6086182007Sroberto * 608756746Sroberto * Revision 4.36 1999/11/28 17:18:20 kardel 608856746Sroberto * disabled burst mode 608956746Sroberto * 609056746Sroberto * Revision 4.35 1999/11/28 09:14:14 kardel 609156746Sroberto * RECON_4_0_98F 609256746Sroberto * 609356746Sroberto * Revision 4.34 1999/05/14 06:08:05 kardel 609456746Sroberto * store current_time in a suitable container (u_long) 609556746Sroberto * 609656746Sroberto * Revision 4.33 1999/05/13 21:48:38 kardel 609756746Sroberto * double the no response timeout interval 609856746Sroberto * 609956746Sroberto * Revision 4.32 1999/05/13 20:09:13 kardel 610056746Sroberto * complain only about missing polls after a full poll interval 610156746Sroberto * 610256746Sroberto * Revision 4.31 1999/05/13 19:59:32 kardel 610356746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF 610456746Sroberto * 610556746Sroberto * Revision 4.30 1999/02/28 20:36:43 kardel 610656746Sroberto * fixed printf fmt 610756746Sroberto * 610854359Sroberto * Revision 4.29 1999/02/28 19:58:23 kardel 610954359Sroberto * updated copyright information 611054359Sroberto * 611154359Sroberto * Revision 4.28 1999/02/28 19:01:50 kardel 611254359Sroberto * improved debug out on sent Meinberg messages 611354359Sroberto * 611454359Sroberto * Revision 4.27 1999/02/28 18:05:55 kardel 611554359Sroberto * no linux/ppsclock.h stuff 611654359Sroberto * 611754359Sroberto * Revision 4.26 1999/02/28 15:27:27 kardel 611854359Sroberto * wharton clock integration 611954359Sroberto * 612054359Sroberto * Revision 4.25 1999/02/28 14:04:46 kardel 612154359Sroberto * added missing double quotes to UTC information string 612254359Sroberto * 612354359Sroberto * Revision 4.24 1999/02/28 12:06:50 kardel 612454359Sroberto * (parse_control): using gmprettydate instead of prettydate() 612554359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information 612654359Sroberto * (gps16x_message): changed to use mk_utcinfo() 612754359Sroberto * (trimbletsip_message): changed to use mk_utcinfo() 612854359Sroberto * ignoring position information in unsynchronized mode 612954359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 613054359Sroberto * 613154359Sroberto * Revision 4.23 1999/02/23 19:47:53 kardel 613254359Sroberto * fixed #endifs 613354359Sroberto * (stream_receive): fixed formats 613454359Sroberto * 613554359Sroberto * Revision 4.22 1999/02/22 06:21:02 kardel 613654359Sroberto * use new autoconfig symbols 613754359Sroberto * 613854359Sroberto * Revision 4.21 1999/02/21 12:18:13 kardel 613954359Sroberto * 4.91f reconcilation 614054359Sroberto * 614154359Sroberto * Revision 4.20 1999/02/21 10:53:36 kardel 614254359Sroberto * initial Linux PPSkit version 614354359Sroberto * 614454359Sroberto * Revision 4.19 1999/02/07 09:10:45 kardel 614554359Sroberto * clarify STREAMS mitigation rules in comment 614654359Sroberto * 614754359Sroberto * Revision 4.18 1998/12/20 23:45:34 kardel 614854359Sroberto * fix types and warnings 614954359Sroberto * 615054359Sroberto * Revision 4.17 1998/11/15 21:24:51 kardel 615154359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG 615254359Sroberto * is not defined 615354359Sroberto * 615454359Sroberto * Revision 4.16 1998/11/15 20:28:17 kardel 615554359Sroberto * Release 4.0.73e13 reconcilation 615654359Sroberto * 615754359Sroberto * Revision 4.15 1998/08/22 21:56:08 kardel 615854359Sroberto * fixed IO handling for non-STREAM IO 615954359Sroberto * 616054359Sroberto * Revision 4.14 1998/08/16 19:00:48 kardel 616154359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 616254359Sroberto * made uval a local variable (killed one of the last globals) 616354359Sroberto * (sendetx): added logging of messages when in debug mode 616454359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization 616554359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation 616654359Sroberto * (trimbletsip_message): extended message interpretation 616754359Sroberto * (getdbl): fixed data conversion 616854359Sroberto * 616954359Sroberto * Revision 4.13 1998/08/09 22:29:13 kardel 617054359Sroberto * Trimble TSIP support 617154359Sroberto * 617254359Sroberto * Revision 4.12 1998/07/11 10:05:34 kardel 617354359Sroberto * Release 4.0.73d reconcilation 617454359Sroberto * 617554359Sroberto * Revision 4.11 1998/06/14 21:09:42 kardel 617654359Sroberto * Sun acc cleanup 617754359Sroberto * 617854359Sroberto * Revision 4.10 1998/06/13 12:36:45 kardel 617954359Sroberto * signed/unsigned, name clashes 618054359Sroberto * 618154359Sroberto * Revision 4.9 1998/06/12 15:30:00 kardel 618254359Sroberto * prototype fixes 618354359Sroberto * 618454359Sroberto * Revision 4.8 1998/06/12 11:19:42 kardel 618554359Sroberto * added direct input processing routine for refclocks in 618654359Sroberto * order to avaiod that single character io gobbles up all 618754359Sroberto * receive buffers and drops input data. (Problem started 618854359Sroberto * with fast machines so a character a buffer was possible 618954359Sroberto * one of the few cases where faster machines break existing 619054359Sroberto * allocation algorithms) 619154359Sroberto * 619254359Sroberto * Revision 4.7 1998/06/06 18:35:20 kardel 619354359Sroberto * (parse_start): added BURST mode initialisation 619454359Sroberto * 619554359Sroberto * Revision 4.6 1998/05/27 06:12:46 kardel 619654359Sroberto * RAWDCF_BASEDELAY default added 619754359Sroberto * old comment removed 619854359Sroberto * casts for ioctl() 619954359Sroberto * 620054359Sroberto * Revision 4.5 1998/05/25 22:05:09 kardel 620154359Sroberto * RAWDCF_SETDTR option removed 620254359Sroberto * clock type 14 attempts to set DTR for 620354359Sroberto * power supply of RAWDCF receivers 620454359Sroberto * 620554359Sroberto * Revision 4.4 1998/05/24 16:20:47 kardel 620654359Sroberto * updated comments referencing Meinberg clocks 620754359Sroberto * added RAWDCF clock with DTR set option as type 14 620854359Sroberto * 620954359Sroberto * Revision 4.3 1998/05/24 10:48:33 kardel 621054359Sroberto * calibrated CONRAD RAWDCF default fudge factor 621154359Sroberto * 621254359Sroberto * Revision 4.2 1998/05/24 09:59:35 kardel 621354359Sroberto * corrected version information (ntpq support) 621454359Sroberto * 621554359Sroberto * Revision 4.1 1998/05/24 09:52:31 kardel 621654359Sroberto * use fixed format only (new IO model) 621754359Sroberto * output debug to stdout instead of msyslog() 621854359Sroberto * don't include >"< in ASCII output in order not to confuse 621954359Sroberto * ntpq parsing 622054359Sroberto * 622154359Sroberto * Revision 4.0 1998/04/10 19:52:11 kardel 622254359Sroberto * Start 4.0 release version numbering 622354359Sroberto * 622454359Sroberto * Revision 1.2 1998/04/10 19:28:04 kardel 622554359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 622654359Sroberto * derived from 3.105.1.2 from V3 tree 622754359Sroberto * 622854359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 622954359Sroberto * 623054359Sroberto */ 6231