154359Sroberto/* 2290000Sglebius * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 354359Sroberto * 4290000Sglebius * 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 * 18290000Sglebius * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org> 19290000Sglebius * 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 51290000Sglebius#include "ntp_types.h" 52290000Sglebius 5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) 5454359Sroberto 5554359Sroberto/* 5654359Sroberto * This driver currently provides the support for 57290000Sglebius * - Meinberg receiver DCF77 PZF535 (TCXO version) (DCF) 58290000Sglebius * - Meinberg receiver DCF77 PZF535 (OCXO version) (DCF) 59290000Sglebius * - 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) 66290000Sglebius * - WHARTON 400A Series clock (DCF) 6754359Sroberto * 68290000Sglebius * - Meinberg GPS receivers (GPS) 6954359Sroberto * - Trimble (TSIP and TAIP protocol) (GPS) 7054359Sroberto * 7154359Sroberto * - RCC8000 MSF Receiver (MSF) 72290000Sglebius * - VARITEXT clock (MSF) 7354359Sroberto */ 7454359Sroberto 7554359Sroberto/* 7654359Sroberto * Meinberg receivers are usually connected via a 77290000Sglebius * 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: 83290000Sglebius * output time code every second 84290000Sglebius * Baud rate 9600 7E2S 8554359Sroberto * 86290000Sglebius * 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 94290000Sglebius * oldest GPS receiver, GPS16x. For newer receiver types 95290000Sglebius * the output string format can be configured at the device, 96290000Sglebius * 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" 103290000Sglebius#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 127290000Sglebius# 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" 149290000Sglebius# 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 161290000Sglebius# define BUFFER_SIZE(_BUF, _PTR) ((int)((_BUF) + sizeof(_BUF) - (_PTR))) 162290000Sglebius# 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 */ 167290000Sglebius#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 186290000Sglebius/* 187290000Sglebius * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF 188290000Sglebius * then some more parse-specific variables are flagged to be printed with 189290000Sglebius * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF 190290000Sglebius * should be defined as 0. 191290000Sglebius */ 192290000Sglebius#if 0 193290000Sglebius# define COND_DEF DEF // enable this for testing 194290000Sglebius#else 195290000Sglebius# define COND_DEF 0 // enable this by default 196290000Sglebius#endif 197290000Sglebius 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 209290000Sglebiusstatic 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 215290000Sglebiusstatic int parse_start (int, struct peer *); 216290000Sglebiusstatic void parse_shutdown (int, struct peer *); 217290000Sglebiusstatic void parse_poll (int, struct peer *); 218290000Sglebiusstatic 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 */ 252290000Sglebius int (*bd_init) (struct parseunit *); /* initialize */ 253290000Sglebius void (*bd_end) (struct parseunit *); /* end */ 254290000Sglebius int (*bd_setcs) (struct parseunit *, parsectl_t *); /* set character size */ 255290000Sglebius int (*bd_disable) (struct parseunit *); /* disable */ 256290000Sglebius int (*bd_enable) (struct parseunit *); /* enable */ 257290000Sglebius int (*bd_getfmt) (struct parseunit *, parsectl_t *); /* get format */ 258290000Sglebius int (*bd_setfmt) (struct parseunit *, parsectl_t *); /* setfmt */ 259290000Sglebius int (*bd_timecode) (struct parseunit *, parsectl_t *); /* get time code */ 260290000Sglebius void (*bd_receive) (struct recvbuf *); /* receive operation */ 261290000Sglebius 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/* 273290000Sglebius * special handling flags 27454359Sroberto */ 275290000Sglebius#define PARSE_F_PPSONSECOND 0x00000001 /* PPS pulses are on second */ 276290000Sglebius#define PARSE_F_POWERUPTRUST 0x00000100 /* POWERUP state ist trusted for */ 277290000Sglebius /* 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 */ 399290000Sglebius 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 */ 426290000Sglebius 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 442290000Sglebiusstatic void poll_dpoll (struct parseunit *); 443290000Sglebiusstatic void poll_poll (struct peer *); 444290000Sglebiusstatic 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 467290000Sglebius#define NOCLOCK_ROOTDELAY 0.0 468290000Sglebius#define NOCLOCK_BASEDELAY 0.0 469290000Sglebius#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 475290000Sglebius#define NOCLOCK_ID "TILT" 476290000Sglebius#define NOCLOCK_POLL NO_POLL 477290000Sglebius#define NOCLOCK_INIT NO_INIT 478290000Sglebius#define NOCLOCK_END NO_END 479290000Sglebius#define NOCLOCK_DATA NO_LCLDATA 480290000Sglebius#define NOCLOCK_FORMAT "" 481290000Sglebius#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 482290000Sglebius#define NOCLOCK_SAMPLES 0 483290000Sglebius#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/* 553290000Sglebius * Meinberg GPS receivers 55454359Sroberto */ 555290000Sglebiusstatic void gps16x_message (struct parseunit *, parsetime_t *); 556290000Sglebiusstatic 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) */ 560290000Sglebius#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 */ 696290000Sglebiusstatic int rawdcf_init_1 (struct parseunit *); 69756746Sroberto#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 698290000Sglebius#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 */ 705290000Sglebiusstatic int rawdcf_init_2 (struct parseunit *); 70656746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 707290000Sglebius#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 }; 721290000Sglebiusstatic int trimbletaip_init (struct parseunit *); 722290000Sglebiusstatic 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) }; 728290000Sglebiusstatic int trimbletsip_init (struct parseunit *); 729290000Sglebiusstatic void trimbletsip_end (struct parseunit *); 730290000Sglebiusstatic void trimbletsip_message (struct parseunit *, parsetime_t *); 731290000Sglebiusstatic 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 762290000Sglebius#define TRIMBLETAIP_EVENT trimbletaip_event 76354359Sroberto 764290000Sglebius#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/* 821290000Sglebius * 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 876290000Sglebius/* 877290000Sglebius * SEL240x Satellite Sychronized Clock 878290000Sglebius */ 879290000Sglebius#define SEL240X_POLLRATE 0 /* only true direct polling */ 880290000Sglebius#define SEL240X_POLLCMD "BUB8" 881290000Sglebius#define SEL240X_CMDSIZE 4 882290000Sglebius 883290000Sglebiusstatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE, 884290000Sglebius SEL240X_POLLCMD, 885290000Sglebius SEL240X_CMDSIZE }; 886290000Sglebius#define SEL240X_FLAGS (PARSE_F_PPSONSECOND) 887290000Sglebius#define SEL240X_POLL poll_dpoll 888290000Sglebius#define SEL240X_INIT poll_init 889290000Sglebius#define SEL240X_END 0 890290000Sglebius#define SEL240X_DATA ((void *)(&sel240x_pollinfo)) 891290000Sglebius#define SEL240X_ROOTDELAY 0.0 892290000Sglebius#define SEL240X_BASEDELAY 0.0 893290000Sglebius#define SEL240X_ID GPS_ID 894290000Sglebius#define SEL240X_DESCRIPTION "SEL240x Satellite Synchronized Clock" 895290000Sglebius#define SEL240X_FORMAT "SEL B8" 896290000Sglebius#define SEL240X_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours */ 897290000Sglebius#define SEL240X_SPEED (B9600) 898290000Sglebius#define SEL240X_CFLAG (CS8|CREAD|CLOCAL) 899290000Sglebius#define SEL240X_IFLAG (IGNBRK|IGNPAR) 900290000Sglebius#define SEL240X_OFLAG (0) 901290000Sglebius#define SEL240X_LFLAG (0) 902290000Sglebius#define SEL240X_SAMPLES 5 903290000Sglebius#define SEL240X_KEEP 3 904290000Sglebius 90554359Srobertostatic struct parse_clockinfo 90654359Sroberto{ 907290000Sglebius u_long cl_flags; /* operation flags (PPS interpretation, trust handling) */ 908290000Sglebius void (*cl_poll) (struct parseunit *); /* active poll routine */ 909290000Sglebius int (*cl_init) (struct parseunit *); /* active poll init routine */ 910290000Sglebius void (*cl_event) (struct parseunit *, int); /* special event handling (e.g. reset clock) */ 911290000Sglebius void (*cl_end) (struct parseunit *); /* active poll end routine */ 912290000Sglebius 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, 1217290000Sglebius 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 }, 1401290000Sglebius { /* mode 20, like mode 14 but driven by 75 baud */ 1402290000Sglebius RAWDCF_FLAGS, 1403290000Sglebius NO_POLL, 1404290000Sglebius RAWDCFDTRSET_INIT, 1405290000Sglebius NO_EVENT, 1406290000Sglebius NO_END, 1407290000Sglebius NO_MESSAGE, 1408290000Sglebius NO_LCLDATA, 1409290000Sglebius RAWDCF_ROOTDELAY, 1410290000Sglebius RAWDCF_BASEDELAY, 1411290000Sglebius DCF_A_ID, 1412290000Sglebius RAWDCFDTRSET75_DESCRIPTION, 1413290000Sglebius RAWDCF_FORMAT, 1414290000Sglebius DCF_TYPE, 1415290000Sglebius RAWDCF_MAXUNSYNC, 1416290000Sglebius B75, 1417290000Sglebius RAWDCF_CFLAG, 1418290000Sglebius RAWDCF_IFLAG, 1419290000Sglebius RAWDCF_OFLAG, 1420290000Sglebius RAWDCF_LFLAG, 1421290000Sglebius RAWDCF_SAMPLES, 1422290000Sglebius RAWDCF_KEEP 1423290000Sglebius }, 1424290000Sglebius { /* mode 21, like mode 16 but driven by 75 baud 1425290000Sglebius - RAWDCF RTS set, DTR clr */ 1426290000Sglebius RAWDCF_FLAGS, 1427290000Sglebius NO_POLL, 1428290000Sglebius RAWDCFDTRCLRRTSSET_INIT, 1429290000Sglebius NO_EVENT, 1430290000Sglebius NO_END, 1431290000Sglebius NO_MESSAGE, 1432290000Sglebius NO_LCLDATA, 1433290000Sglebius RAWDCF_ROOTDELAY, 1434290000Sglebius RAWDCF_BASEDELAY, 1435290000Sglebius DCF_A_ID, 1436290000Sglebius RAWDCFDTRCLRRTSSET75_DESCRIPTION, 1437290000Sglebius RAWDCF_FORMAT, 1438290000Sglebius DCF_TYPE, 1439290000Sglebius RAWDCF_MAXUNSYNC, 1440290000Sglebius B75, 1441290000Sglebius RAWDCF_CFLAG, 1442290000Sglebius RAWDCF_IFLAG, 1443290000Sglebius RAWDCF_OFLAG, 1444290000Sglebius RAWDCF_LFLAG, 1445290000Sglebius RAWDCF_SAMPLES, 1446290000Sglebius RAWDCF_KEEP 1447290000Sglebius }, 1448290000Sglebius { /* mode 22 - like 2 with POWERUP trust */ 1449290000Sglebius MBG_FLAGS | PARSE_F_POWERUPTRUST, 1450290000Sglebius NO_POLL, 1451290000Sglebius NO_INIT, 1452290000Sglebius NO_EVENT, 1453290000Sglebius NO_END, 1454290000Sglebius NO_MESSAGE, 1455290000Sglebius NO_LCLDATA, 1456290000Sglebius DCFUA31_ROOTDELAY, 1457290000Sglebius DCFUA31_BASEDELAY, 1458290000Sglebius DCF_A_ID, 1459290000Sglebius DCFUA31_DESCRIPTION, 1460290000Sglebius DCFUA31_FORMAT, 1461290000Sglebius DCF_TYPE, 1462290000Sglebius DCFUA31_MAXUNSYNC, 1463290000Sglebius DCFUA31_SPEED, 1464290000Sglebius DCFUA31_CFLAG, 1465290000Sglebius DCFUA31_IFLAG, 1466290000Sglebius DCFUA31_OFLAG, 1467290000Sglebius DCFUA31_LFLAG, 1468290000Sglebius DCFUA31_SAMPLES, 1469290000Sglebius DCFUA31_KEEP 1470290000Sglebius }, 1471290000Sglebius { /* mode 23 - like 7 with POWERUP trust */ 1472290000Sglebius MBG_FLAGS | PARSE_F_POWERUPTRUST, 1473290000Sglebius GPS16X_POLL, 1474290000Sglebius GPS16X_INIT, 1475290000Sglebius NO_EVENT, 1476290000Sglebius GPS16X_END, 1477290000Sglebius GPS16X_MESSAGE, 1478290000Sglebius GPS16X_DATA, 1479290000Sglebius GPS16X_ROOTDELAY, 1480290000Sglebius GPS16X_BASEDELAY, 1481290000Sglebius GPS16X_ID, 1482290000Sglebius GPS16X_DESCRIPTION, 1483290000Sglebius GPS16X_FORMAT, 1484290000Sglebius GPS_TYPE, 1485290000Sglebius GPS16X_MAXUNSYNC, 1486290000Sglebius GPS16X_SPEED, 1487290000Sglebius GPS16X_CFLAG, 1488290000Sglebius GPS16X_IFLAG, 1489290000Sglebius GPS16X_OFLAG, 1490290000Sglebius GPS16X_LFLAG, 1491290000Sglebius GPS16X_SAMPLES, 1492290000Sglebius GPS16X_KEEP 1493290000Sglebius }, 1494290000Sglebius { /* mode 24 */ 1495290000Sglebius SEL240X_FLAGS, 1496290000Sglebius SEL240X_POLL, 1497290000Sglebius SEL240X_INIT, 1498290000Sglebius NO_EVENT, 1499290000Sglebius SEL240X_END, 1500290000Sglebius NO_MESSAGE, 1501290000Sglebius SEL240X_DATA, 1502290000Sglebius SEL240X_ROOTDELAY, 1503290000Sglebius SEL240X_BASEDELAY, 1504290000Sglebius SEL240X_ID, 1505290000Sglebius SEL240X_DESCRIPTION, 1506290000Sglebius SEL240X_FORMAT, 1507290000Sglebius GPS_TYPE, 1508290000Sglebius SEL240X_MAXUNSYNC, 1509290000Sglebius SEL240X_SPEED, 1510290000Sglebius SEL240X_CFLAG, 1511290000Sglebius SEL240X_IFLAG, 1512290000Sglebius SEL240X_OFLAG, 1513290000Sglebius SEL240X_LFLAG, 1514290000Sglebius SEL240X_SAMPLES, 1515290000Sglebius SEL240X_KEEP 1516290000Sglebius }, 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 1537290000Sglebiusstatic void parse_event (struct parseunit *, int); 1538290000Sglebiusstatic void parse_process (struct parseunit *, parsetime_t *); 1539290000Sglebiusstatic void clear_err (struct parseunit *, u_long); 1540290000Sglebiusstatic int list_err (struct parseunit *, u_long); 1541290000Sglebiusstatic 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 { 1554290000Sglebius 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++; 1593290000Sglebius 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 } 1617290000Sglebius 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, 1633293894Sglebius size_t blen, 163454359Sroberto const char *src, 1635293894Sglebius size_t srclen, 163654359Sroberto int hex 163754359Sroberto ) 163854359Sroberto{ 1639290000Sglebius static const char ellipsis[] = "..."; 164054359Sroberto char *b = buffer; 1641290000Sglebius char *endb = NULL; 164254359Sroberto 164354359Sroberto if (blen < 4) 1644290000Sglebius return NULL; /* don't bother with mini buffers */ 164554359Sroberto 1646290000Sglebius 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 " */ 1655290000Sglebius 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 { 1675290000Sglebius memcpy(buffer, "\\\\", 2); 167654359Sroberto buffer += 2; 167754359Sroberto blen -= 2; 167854359Sroberto src++; 167954359Sroberto } 168054359Sroberto else 168154359Sroberto { 1682290000Sglebius 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 ... */ 1689290000Sglebius 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 1721290000Sglebiusstatic int ppsclock_init (struct parseunit *); 1722290000Sglebiusstatic int stream_init (struct parseunit *); 1723290000Sglebiusstatic void stream_end (struct parseunit *); 1724290000Sglebiusstatic int stream_enable (struct parseunit *); 1725290000Sglebiusstatic int stream_disable (struct parseunit *); 1726290000Sglebiusstatic int stream_setcs (struct parseunit *, parsectl_t *); 1727290000Sglebiusstatic int stream_getfmt (struct parseunit *, parsectl_t *); 1728290000Sglebiusstatic int stream_setfmt (struct parseunit *, parsectl_t *); 1729290000Sglebiusstatic int stream_timecode (struct parseunit *, parsectl_t *); 1730290000Sglebiusstatic void stream_receive (struct recvbuf *); 173154359Sroberto#endif 173254359Sroberto 1733290000Sglebiusstatic int local_init (struct parseunit *); 1734290000Sglebiusstatic void local_end (struct parseunit *); 1735290000Sglebiusstatic int local_nop (struct parseunit *); 1736290000Sglebiusstatic int local_setcs (struct parseunit *, parsectl_t *); 1737290000Sglebiusstatic int local_getfmt (struct parseunit *, parsectl_t *); 1738290000Sglebiusstatic int local_setfmt (struct parseunit *, parsectl_t *); 1739290000Sglebiusstatic int local_timecode (struct parseunit *, parsectl_t *); 1740290000Sglebiusstatic void local_receive (struct recvbuf *); 1741290000Sglebiusstatic int local_input (struct recvbuf *); 1742290000Sglebius 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, 1788290000Sglebius NULL, 1789290000Sglebius NULL, 1790290000Sglebius NULL, 1791290000Sglebius NULL, 1792290000Sglebius NULL, 1793290000Sglebius NULL, 1794290000Sglebius NULL, 1795290000Sglebius NULL, 1796290000Sglebius NULL, 1797290000Sglebius 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"; 1813290000Sglebius 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; 1902290000Sglebius 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; 1925290000Sglebius 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; 1949290000Sglebius 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; 1974290000Sglebius 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; 1997290000Sglebius 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; 2022290000Sglebius 202354359Sroberto strioc.ic_cmd = PARSEIOC_TIMECODE; 202454359Sroberto strioc.ic_timout = 0; 202554359Sroberto strioc.ic_dp = (char *)tcl; 202654359Sroberto strioc.ic_len = sizeof (*tcl); 2027290000Sglebius 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{ 2046290000Sglebius struct parseunit * parse; 204754359Sroberto parsetime_t parsetime; 204854359Sroberto 2049290000Sglebius 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); 2062290000Sglebius 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 2088290000Sglebius parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv); 208954359Sroberto 209054359Sroberto if (PARSE_TIMECODE(parsetime.parse_state)) 209154359Sroberto { 2092290000Sglebius parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv); 209354359Sroberto } 209454359Sroberto 209554359Sroberto if (PARSE_PPS(parsetime.parse_state)) 2096290000Sglebius { 2097290000Sglebius parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv); 2098290000Sglebius } 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{ 2195290000Sglebius struct parseunit * parse; 2196290000Sglebius 219754359Sroberto int count; 219854359Sroberto unsigned char *s; 219954359Sroberto timestamp_t ts; 220054359Sroberto 2201290000Sglebius 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; 2228290000Sglebius 2229182007Sroberto pps_timeout.tv_sec = 0; 2230182007Sroberto pps_timeout.tv_nsec = 0; 2231182007Sroberto 2232290000Sglebius 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 2249290000Sglebius parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970); 2250182007Sroberto 2251290000Sglebius 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 } 2260290000Sglebius parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC); 2261182007Sroberto 2262290000Sglebius parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2263182007Sroberto#ifdef DEBUG 2264182007Sroberto if (debug > 3) 2265182007Sroberto { 2266182007Sroberto printf( 2267301301Sdelphij "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n", 2268301301Sdelphij (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( 2280301301Sdelphij "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2281301301Sdelphij (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( 2294301301Sdelphij "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n", 2295301301Sdelphij (long)rbufp->fd, 2296182007Sroberto errno); 2297182007Sroberto } 2298182007Sroberto } 2299182007Sroberto#endif 2300182007Sroberto } 2301182007Sroberto#else 230254359Sroberto#ifdef TIOCDCDTIMESTAMP 230354359Sroberto struct timeval dcd_time; 2304290000Sglebius 2305182007Sroberto if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 230654359Sroberto { 230754359Sroberto l_fp tstmp; 2308290000Sglebius 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; 2376290000Sglebius#ifndef HAVE_IO_COMPLETION_PORT 2377182007Sroberto buf->srcadr = rbufp->srcadr; 2378290000Sglebius#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; 2383290000Sglebius parse->generic->io.recvcount++; 2384290000Sglebius packets_received++; 2385182007Sroberto add_full_recv_buffer(buf); 2386290000Sglebius#ifdef HAVE_IO_COMPLETION_PORT 2387290000Sglebius SetEvent(WaitableIoEventHandle); 2388290000Sglebius#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{ 2414290000Sglebius struct parseunit * parse; 241554359Sroberto parsetime_t parsetime; 241654359Sroberto 2417290000Sglebius 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); 2430290000Sglebius 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 2479290000Sglebiusstatic NTP_PRINTF(4, 5) char * 2480290000Sglebiusap(char *buffer, size_t len, char *pos, const char *fmt, ...) 2481290000Sglebius{ 2482290000Sglebius va_list va; 2483290000Sglebius int l; 2484290000Sglebius size_t rem = len - (pos - buffer); 2485290000Sglebius 2486290000Sglebius if (rem == 0) 2487290000Sglebius return pos; 2488290000Sglebius 2489290000Sglebius va_start(va, fmt); 2490290000Sglebius l = vsnprintf(pos, rem, fmt, va); 2491290000Sglebius va_end(va); 2492290000Sglebius 2493290000Sglebius if (l != -1) { 2494290000Sglebius rem--; 2495290000Sglebius if (rem >= (size_t)l) 2496290000Sglebius pos += l; 2497290000Sglebius else 2498290000Sglebius pos += rem; 2499290000Sglebius } 2500290000Sglebius 2501290000Sglebius return pos; 2502290000Sglebius} 2503290000Sglebius 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" }, 2528290000Sglebius { PARSEB_CALLBIT, "CALL BIT" }, 252956746Sroberto { PARSEB_TIMECODE, "TIME CODE" }, 253056746Sroberto { PARSEB_PPS, "PPS" }, 253156746Sroberto { PARSEB_POSITION, "POSITION" }, 2532290000Sglebius { 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" }, 2543290000Sglebius { PARSEB_S_CALLBIT, "CALLBIT" }, 254454359Sroberto { PARSEB_S_POSITION, "POSITION" }, 2545290000Sglebius { 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) 2559290000Sglebius t = ap(buffer, size, t, "; "); 2560290000Sglebius t = ap(buffer, size, t, "%s", flagstrings[i].name); 256154359Sroberto } 256254359Sroberto i++; 256354359Sroberto } 256454359Sroberto 2565290000Sglebius if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION)) 256654359Sroberto { 2567182007Sroberto if (s != t) 2568290000Sglebius t = ap(buffer, size, t, "; "); 256954359Sroberto 2570290000Sglebius t = ap(buffer, size, t, "("); 257154359Sroberto 2572290000Sglebius s = t; 257354359Sroberto 257454359Sroberto i = 0; 257554359Sroberto while (sflagstrings[i].bit) 257654359Sroberto { 257754359Sroberto if (sflagstrings[i].bit & lstate) 257854359Sroberto { 257954359Sroberto if (t != s) 258054359Sroberto { 2581290000Sglebius t = ap(buffer, size, t, "; "); 258254359Sroberto } 2583290000Sglebius 2584290000Sglebius t = ap(buffer, size, t, "%s", 2585290000Sglebius sflagstrings[i].name); 258654359Sroberto } 258754359Sroberto i++; 258854359Sroberto } 2589290000Sglebius t = ap(buffer, size, t, ")"); 2590290000Sglebius /* t is unused here, but if we don't track it and 2591290000Sglebius * need it later, that's a bug waiting to happen. 2592290000Sglebius */ 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" }, 2620290000Sglebius { 0, NULL } 262154359Sroberto }; 262254359Sroberto int i; 2623290000Sglebius char *t; 262454359Sroberto 2625290000Sglebius t = buffer; 262654359Sroberto *buffer = '\0'; 262754359Sroberto 262854359Sroberto i = 0; 262954359Sroberto while (flagstrings[i].bit) 263054359Sroberto { 263154359Sroberto if (flagstrings[i].bit & lstate) 263254359Sroberto { 2633290000Sglebius if (t != buffer) 2634290000Sglebius t = ap(buffer, size, t, "; "); 2635290000Sglebius 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" }, 2665290000Sglebius { (unsigned)~0L, NULL } 266654359Sroberto }; 266754359Sroberto int i; 266854359Sroberto 266954359Sroberto i = 0; 2670290000Sglebius 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'; 2698290000Sglebius t = buffer; 269954359Sroberto 270054359Sroberto if ((tmp = delta / (60*60*24)) != 0) 270154359Sroberto { 2702290000Sglebius 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 2711290000Sglebius t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d", 2712290000Sglebius (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{ 2792290000Sglebius struct parseunit *parse = NULL; 279354359Sroberto 2794182007Sroberto if (peer && peer->procptr) 2795290000Sglebius parse = peer->procptr->unitptr; 2796182007Sroberto 2797182007Sroberto if (!parse) 279854359Sroberto { 2799182007Sroberto /* nothing to clean up */ 280054359Sroberto return; 280154359Sroberto } 280254359Sroberto 2803290000Sglebius 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 { 2812290000Sglebius (void)time_pps_destroy(parse->atom.handle); 2813182007Sroberto } 2814182007Sroberto#endif 2815182007Sroberto if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2816290000Sglebius (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 } 2828290000Sglebius 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); 2841290000Sglebius 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 2867290000Sglebius if (mode == PARSE_HARDPPS_ENABLE) 2868182007Sroberto { 2869182007Sroberto if (parse->flags & PARSE_CLEAR) 2870182007Sroberto i = PPS_CAPTURECLEAR; 2871182007Sroberto else 2872182007Sroberto i = PPS_CAPTUREASSERT; 2873182007Sroberto } 2874290000Sglebius 2875290000Sglebius 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) 2887290000Sglebius 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{ 2902290000Sglebius int cap, mode_ppsoffset; 2903290000Sglebius const char *cp; 2904182007Sroberto 2905290000Sglebius parse->flags &= (u_char) (~PARSE_PPSCLOCK); 2906290000Sglebius 2907290000Sglebius /* 2908290000Sglebius * collect PPSAPI offset capability - should move into generic handling 2909290000Sglebius */ 2910290000Sglebius 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)); 2913290000Sglebius 2914182007Sroberto return 0; 2915182007Sroberto } 2916182007Sroberto 2917290000Sglebius /* 2918290000Sglebius * initialize generic PPSAPI interface 2919290000Sglebius * 2920290000Sglebius * we leave out CLK_FLAG3 as time_pps_kcbind() 2921290000Sglebius * is handled here for now. Ideally this should also 2922290000Sglebius * be part of the generic PPSAPI interface 2923290000Sglebius */ 2924290000Sglebius 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"; 2933290000Sglebius mode_ppsoffset = PPS_OFFSETCLEAR; 2934182007Sroberto } else { 2935182007Sroberto cp = "ASSERT"; 2936290000Sglebius mode_ppsoffset = PPS_OFFSETASSERT; 2937182007Sroberto } 2938182007Sroberto 2939182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2940182007Sroberto CLK_UNIT(parse->peer), cp); 2941182007Sroberto 2942290000Sglebius 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); 2945290000Sglebius mode_ppsoffset = 0; 2946182007Sroberto } else { 2947290000Sglebius if (mode_ppsoffset == PPS_OFFSETCLEAR) 2948290000Sglebius { 2949290000Sglebius parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2950290000Sglebius parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2951182007Sroberto } 2952290000Sglebius 2953290000Sglebius if (mode_ppsoffset == PPS_OFFSETASSERT) 2954290000Sglebius { 2955290000Sglebius parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2956290000Sglebius parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2957182007Sroberto } 2958182007Sroberto } 2959182007Sroberto 2960290000Sglebius parse->atom.pps_params.mode |= mode_ppsoffset; 2961182007Sroberto 2962290000Sglebius 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 */ 3004290000Sglebius 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 3011290000Sglebius 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 3027290000Sglebius#ifndef O_NONBLOCK 3028290000Sglebius#define O_NONBLOCK 0 302954359Sroberto#endif 303054359Sroberto 3031290000Sglebius fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3032290000Sglebius 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 3039290000Sglebius 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); 3063290000Sglebius 306454359Sroberto parse->parse_type = &parse_clockinfo[type]; 3065290000Sglebius 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; 3078290000Sglebius 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); 3085290000Sglebius 308654359Sroberto parse->generic->io.fd = fd232; 3087290000Sglebius 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 3130290000Sglebius tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag; 3131290000Sglebius tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag; 3132290000Sglebius tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag; 3133290000Sglebius tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag; 313454359Sroberto 3135290000Sglebius 313654359Sroberto#ifdef HAVE_TERMIOS 3137290000Sglebius if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) || 3138290000Sglebius (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 */ 3153290000Sglebius 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; 3198290000Sglebius 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 { 3213290000Sglebius 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 */ 3235290000Sglebius parse->generic->io.srcclock = peer; 323654359Sroberto parse->generic->io.datalen = 0; 3237290000Sglebius 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 */ 3245290000Sglebius } 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 3284290000Sglebius strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 3285290000Sglebius tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer); 3286290000Sglebius 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 } 3293290000Sglebius 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 } 3320290000Sglebius 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, 3378290000Sglebius const struct refclockstat *in 3379182007Sroberto ) 3380182007Sroberto{ 3381182007Sroberto if (in) 3382182007Sroberto { 3383182007Sroberto if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3384182007Sroberto { 3385290000Sglebius u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4; 3386290000Sglebius 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 } 3394290000Sglebius 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 } 3402290000Sglebius 3403182007Sroberto if (in->haveflags & CLK_HAVETIME2) 3404182007Sroberto { 3405182007Sroberto parse->generic->fudgetime2 = in->fudgetime2; 3406290000Sglebius 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{ 3439290000Sglebius 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 3454290000Sglebius if (parse->pollneeddata && 3455290000Sglebius ((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); 3463290000Sglebius 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, 3491290000Sglebius const struct refclockstat *in, 349254359Sroberto struct refclockstat *out, 349354359Sroberto struct peer *peer 349454359Sroberto ) 349554359Sroberto{ 3496290000Sglebius 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); 3521290000Sglebius 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); 3568290000Sglebius tt = ap(start, 128, tt, "refclock_time=\""); 356954359Sroberto 3570182007Sroberto if (parse->timedata.parse_time.fp.l_ui == 0) 357154359Sroberto { 3572290000Sglebius tt = ap(start, 128, tt, "<UNDEFINED>\""); 357354359Sroberto } 357454359Sroberto else 357554359Sroberto { 3576290000Sglebius tt = ap(start, 128, tt, "%s\"", 3577290000Sglebius 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); 3588290000Sglebius 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 3596290000Sglebius (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 359754359Sroberto 3598290000Sglebius tt += strlen(tt); 359954359Sroberto 3600290000Sglebius tt = ap(start, 512, tt, "\""); 3601290000Sglebius 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 } 3607290000Sglebius 360854359Sroberto tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 3609290000Sglebius 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 { 3617290000Sglebius int count = tmpctl.parseformat.parse_count - 1; 361854359Sroberto 3619290000Sglebius start = tt = add_var(&out->kv_list, 80, RO|DEF); 3620290000Sglebius tt = ap(start, 80, tt, "refclock_format=\""); 3621290000Sglebius 3622290000Sglebius if (count > 0) { 3623290000Sglebius tt = ap(start, 80, tt, "%*.*s", 3624290000Sglebius count, 3625290000Sglebius count, 3626290000Sglebius tmpctl.parseformat.parse_buffer); 3627290000Sglebius } 3628290000Sglebius 3629290000Sglebius tt = ap(start, 80, tt, "\""); 363054359Sroberto } 363154359Sroberto 363254359Sroberto /* 363354359Sroberto * gather state statistics 363454359Sroberto */ 363554359Sroberto 363654359Sroberto start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3637290000Sglebius tt = ap(start, LEN_STATES, tt, "refclock_states=\""); 363854359Sroberto 363954359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 364054359Sroberto { 364154359Sroberto u_long s_time; 364254359Sroberto u_long d = current_time - parse->generic->timestarted; 364354359Sroberto u_long percent; 364454359Sroberto 364554359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 364654359Sroberto 364754359Sroberto while (((u_long)(~0) / 10000) < percent) 364854359Sroberto { 364954359Sroberto percent /= 10; 365054359Sroberto d /= 10; 365154359Sroberto } 3652290000Sglebius 365354359Sroberto if (d) 365454359Sroberto percent = (percent * 10000) / d; 365554359Sroberto else 365654359Sroberto percent = 10000; 365754359Sroberto 365854359Sroberto if (s_time) 365954359Sroberto { 366054359Sroberto char item[80]; 366154359Sroberto int count; 3662290000Sglebius 3663182007Sroberto snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 366454359Sroberto sum ? "; " : "", 366554359Sroberto (parse->generic->currentstatus == i) ? "*" : "", 366654359Sroberto clockstatus((unsigned int)i), 366754359Sroberto l_mktime(s_time), 366854359Sroberto (int)(percent / 100), (int)(percent % 100)); 3669290000Sglebius if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start))) 367054359Sroberto { 3671290000Sglebius tt = ap(start, LEN_STATES, tt, 3672290000Sglebius "%s", item); 367354359Sroberto } 367454359Sroberto sum += s_time; 367554359Sroberto } 367654359Sroberto } 3677290000Sglebius 3678290000Sglebius tt = ap(start, LEN_STATES, tt, 3679290000Sglebius "; running time: %s\"", l_mktime(sum)); 3680290000Sglebius 368154359Sroberto tt = add_var(&out->kv_list, 32, RO); 3682182007Sroberto snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 3683290000Sglebius 368454359Sroberto tt = add_var(&out->kv_list, 80, RO); 3685182007Sroberto snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 368654359Sroberto 368754359Sroberto tt = add_var(&out->kv_list, 128, RO); 3688182007Sroberto snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 3689290000Sglebius 369054359Sroberto { 369154359Sroberto struct ctl_var *k; 3692290000Sglebius 369354359Sroberto k = parse->kv; 369454359Sroberto while (k && !(k->flags & EOV)) 369554359Sroberto { 369654359Sroberto set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 369754359Sroberto k++; 369854359Sroberto } 369954359Sroberto } 3700290000Sglebius 3701290000Sglebius out->lencode = (u_short) strlen(outstatus); 370254359Sroberto out->p_lastcode = outstatus; 370354359Sroberto } 370454359Sroberto} 370554359Sroberto 370654359Sroberto/**=========================================================================== 370754359Sroberto ** processing routines 370854359Sroberto **/ 370954359Sroberto 371054359Sroberto/*-------------------------------------------------- 371154359Sroberto * event handling - note that nominal events will also be posted 3712182007Sroberto * keep track of state dwelling times 371354359Sroberto */ 371454359Srobertostatic void 371554359Srobertoparse_event( 371654359Sroberto struct parseunit *parse, 371754359Sroberto int event 371854359Sroberto ) 371954359Sroberto{ 372054359Sroberto if (parse->generic->currentstatus != (u_char) event) 372154359Sroberto { 372254359Sroberto parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 372354359Sroberto parse->lastchange = current_time; 372454359Sroberto 372554359Sroberto if (parse->parse_type->cl_event) 372654359Sroberto parse->parse_type->cl_event(parse, event); 3727290000Sglebius 3728182007Sroberto if (event == CEVNT_NOMINAL) 372954359Sroberto { 373054359Sroberto NLOG(NLOG_CLOCKSTATUS) 373154359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 373254359Sroberto CLK_UNIT(parse->peer)); 373354359Sroberto } 373454359Sroberto 3735182007Sroberto refclock_report(parse->peer, event); 373654359Sroberto } 373754359Sroberto} 373854359Sroberto 373954359Sroberto/*-------------------------------------------------- 374054359Sroberto * process a PARSE time sample 374154359Sroberto */ 374254359Srobertostatic void 374354359Srobertoparse_process( 374454359Sroberto struct parseunit *parse, 374554359Sroberto parsetime_t *parsetime 374654359Sroberto ) 374754359Sroberto{ 374854359Sroberto l_fp off, rectime, reftime; 374954359Sroberto double fudge; 3750290000Sglebius 3751290000Sglebius /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */ 3752290000Sglebius ZERO(off); 3753290000Sglebius 375454359Sroberto /* 375554359Sroberto * check for changes in conversion status 375654359Sroberto * (only one for each new status !) 375754359Sroberto */ 375854359Sroberto if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 375954359Sroberto ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3760182007Sroberto (parse->timedata.parse_status != parsetime->parse_status)) 376154359Sroberto { 376254359Sroberto char buffer[400]; 3763290000Sglebius 376454359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 376554359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3766182007Sroberto CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 3767290000Sglebius 376854359Sroberto if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 376954359Sroberto { 377054359Sroberto /* 377154359Sroberto * tell more about the story - list time code 377254359Sroberto * there is a slight change for a race condition and 377354359Sroberto * the time code might be overwritten by the next packet 377454359Sroberto */ 377554359Sroberto parsectl_t tmpctl; 3776290000Sglebius 377754359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 377854359Sroberto { 377954359Sroberto ERR(ERR_INTERNAL) 378054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 378154359Sroberto } 378254359Sroberto else 378354359Sroberto { 378454359Sroberto ERR(ERR_BADDATA) 3785182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 378654359Sroberto CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); 378754359Sroberto } 3788290000Sglebius /* copy status to show only changes in case of failures */ 3789290000Sglebius parse->timedata.parse_status = parsetime->parse_status; 379054359Sroberto } 379154359Sroberto } 379254359Sroberto 379354359Sroberto /* 379454359Sroberto * examine status and post appropriate events 379554359Sroberto */ 379654359Sroberto if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 379754359Sroberto { 379854359Sroberto /* 379954359Sroberto * got bad data - tell the rest of the system 380054359Sroberto */ 380154359Sroberto switch (parsetime->parse_status & CVT_MASK) 380254359Sroberto { 380354359Sroberto case CVT_NONE: 380454359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 380554359Sroberto parse->parse_type->cl_message) 380654359Sroberto parse->parse_type->cl_message(parse, parsetime); 3807182007Sroberto /* 3808182007Sroberto * save PPS information that comes piggyback 3809182007Sroberto */ 3810182007Sroberto if (PARSE_PPS(parsetime->parse_state)) 3811182007Sroberto { 3812182007Sroberto parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3813182007Sroberto parse->timedata.parse_ptime = parsetime->parse_ptime; 3814182007Sroberto } 381554359Sroberto break; /* well, still waiting - timeout is handled at higher levels */ 3816290000Sglebius 381754359Sroberto case CVT_FAIL: 381854359Sroberto if (parsetime->parse_status & CVT_BADFMT) 381954359Sroberto { 382054359Sroberto parse_event(parse, CEVNT_BADREPLY); 382154359Sroberto } 382254359Sroberto else 382354359Sroberto if (parsetime->parse_status & CVT_BADDATE) 382454359Sroberto { 382554359Sroberto parse_event(parse, CEVNT_BADDATE); 382654359Sroberto } 382754359Sroberto else 382854359Sroberto if (parsetime->parse_status & CVT_BADTIME) 382954359Sroberto { 383054359Sroberto parse_event(parse, CEVNT_BADTIME); 383154359Sroberto } 383254359Sroberto else 383354359Sroberto { 383454359Sroberto parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 383554359Sroberto } 383654359Sroberto } 383754359Sroberto return; /* skip the rest - useless */ 383854359Sroberto } 383954359Sroberto 384054359Sroberto /* 384154359Sroberto * check for format changes 384254359Sroberto * (in case somebody has swapped clocks 8-) 384354359Sroberto */ 384454359Sroberto if (parse->lastformat != parsetime->parse_format) 384554359Sroberto { 384654359Sroberto parsectl_t tmpctl; 3847290000Sglebius 384854359Sroberto tmpctl.parseformat.parse_format = parsetime->parse_format; 384954359Sroberto 385054359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 385154359Sroberto { 385254359Sroberto ERR(ERR_INTERNAL) 385354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 385454359Sroberto } 385554359Sroberto else 385654359Sroberto { 385754359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 385854359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 385954359Sroberto CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 386054359Sroberto } 386154359Sroberto parse->lastformat = parsetime->parse_format; 386254359Sroberto } 386354359Sroberto 386454359Sroberto /* 386554359Sroberto * now, any changes ? 386654359Sroberto */ 3867182007Sroberto if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3868182007Sroberto ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 386954359Sroberto { 387054359Sroberto char tmp1[200]; 387154359Sroberto char tmp2[200]; 387254359Sroberto /* 3873182007Sroberto * something happend - except for PPS events 387454359Sroberto */ 3875290000Sglebius 3876182007Sroberto (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3877182007Sroberto (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 3878290000Sglebius 387954359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 388054359Sroberto msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 388154359Sroberto CLK_UNIT(parse->peer), tmp2, tmp1); 388254359Sroberto } 388354359Sroberto 388454359Sroberto /* 3885182007Sroberto * carry on PPS information if still usable 3886182007Sroberto */ 3887182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3888182007Sroberto { 3889182007Sroberto parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3890182007Sroberto parsetime->parse_ptime = parse->timedata.parse_ptime; 3891182007Sroberto } 3892182007Sroberto 3893182007Sroberto /* 389454359Sroberto * remember for future 389554359Sroberto */ 3896182007Sroberto parse->timedata = *parsetime; 389754359Sroberto 389854359Sroberto /* 389954359Sroberto * check to see, whether the clock did a complete powerup or lost PZF signal 390054359Sroberto * and post correct events for current condition 390154359Sroberto */ 390254359Sroberto if (PARSE_POWERUP(parsetime->parse_state)) 390354359Sroberto { 390454359Sroberto /* 390554359Sroberto * this is bad, as we have completely lost synchronisation 390654359Sroberto * well this is a problem with the receiver here 390754359Sroberto * for PARSE Meinberg DCF77 receivers the lost synchronisation 390854359Sroberto * is true as it is the powerup state and the time is taken 390954359Sroberto * from a crude real time clock chip 3910290000Sglebius * for the PZF/GPS series this is only partly true, as 391154359Sroberto * PARSE_POWERUP only means that the pseudo random 391254359Sroberto * phase shift sequence cannot be found. this is only 391354359Sroberto * bad, if we have never seen the clock in the SYNC 391454359Sroberto * state, where the PHASE and EPOCH are correct. 391554359Sroberto * for reporting events the above business does not 391654359Sroberto * really matter, but we can use the time code 391754359Sroberto * even in the POWERUP state after having seen 391854359Sroberto * the clock in the synchronized state (PZF class 391954359Sroberto * receivers) unless we have had a telegram disruption 392054359Sroberto * after having seen the clock in the SYNC state. we 392154359Sroberto * thus require having seen the clock in SYNC state 392254359Sroberto * *after* having missed telegrams (noresponse) from 392354359Sroberto * the clock. one problem remains: we might use erroneously 392454359Sroberto * POWERUP data if the disruption is shorter than 1 polling 392554359Sroberto * interval. fortunately powerdowns last usually longer than 64 392654359Sroberto * seconds and the receiver is at least 2 minutes in the 392754359Sroberto * POWERUP or NOSYNC state before switching to SYNC 3928290000Sglebius * for GPS receivers this can mean antenna problems and other causes. 3929290000Sglebius * the additional grace period can be enables by a clock 3930290000Sglebius * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set. 393154359Sroberto */ 393254359Sroberto parse_event(parse, CEVNT_FAULT); 393354359Sroberto NLOG(NLOG_CLOCKSTATUS) 393454359Sroberto ERR(ERR_BADSTATUS) 3935290000Sglebius msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS", 393654359Sroberto CLK_UNIT(parse->peer)); 393754359Sroberto } 393854359Sroberto else 393954359Sroberto { 394054359Sroberto /* 394154359Sroberto * we have two states left 394254359Sroberto * 394354359Sroberto * SYNC: 394454359Sroberto * this state means that the EPOCH (timecode) and PHASE 394554359Sroberto * information has be read correctly (at least two 394654359Sroberto * successive PARSE timecodes were received correctly) 394754359Sroberto * this is the best possible state - full trust 394854359Sroberto * 394954359Sroberto * NOSYNC: 395054359Sroberto * The clock should be on phase with respect to the second 395154359Sroberto * signal, but the timecode has not been received correctly within 395254359Sroberto * at least the last two minutes. this is a sort of half baked state 395354359Sroberto * for PARSE Meinberg DCF77 clocks this is bad news (clock running 395454359Sroberto * without timecode confirmation) 395554359Sroberto * PZF 535 has also no time confirmation, but the phase should be 395654359Sroberto * very precise as the PZF signal can be decoded 395754359Sroberto */ 395854359Sroberto 395954359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 396054359Sroberto { 396154359Sroberto /* 396254359Sroberto * currently completely synchronized - best possible state 396354359Sroberto */ 396454359Sroberto parse->lastsync = current_time; 396554359Sroberto clear_err(parse, ERR_BADSTATUS); 396654359Sroberto } 396754359Sroberto else 396854359Sroberto { 396954359Sroberto /* 397054359Sroberto * we have had some problems receiving the time code 397154359Sroberto */ 397254359Sroberto parse_event(parse, CEVNT_PROP); 397354359Sroberto NLOG(NLOG_CLOCKSTATUS) 397454359Sroberto ERR(ERR_BADSTATUS) 397554359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 397654359Sroberto CLK_UNIT(parse->peer)); 397754359Sroberto } 397854359Sroberto } 397954359Sroberto 398054359Sroberto fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 3981290000Sglebius 398254359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 398354359Sroberto { 398454359Sroberto rectime = parsetime->parse_stime.fp; 398554359Sroberto off = reftime = parsetime->parse_time.fp; 3986290000Sglebius 398754359Sroberto L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 398854359Sroberto 398954359Sroberto#ifdef DEBUG 399054359Sroberto if (debug > 3) 399154359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 399254359Sroberto CLK_UNIT(parse->peer), 399354359Sroberto prettydate(&reftime), 399454359Sroberto prettydate(&rectime), 399554359Sroberto lfptoa(&off,6)); 399654359Sroberto#endif 399754359Sroberto } 399854359Sroberto 399954359Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 400054359Sroberto { 400154359Sroberto l_fp offset; 4002182007Sroberto double ppsphaseadjust = parse->ppsphaseadjust; 400354359Sroberto 4004182007Sroberto#ifdef HAVE_PPSAPI 400554359Sroberto /* 4006182007Sroberto * set fudge = 0.0 if already included in PPS time stamps 4007182007Sroberto */ 4008290000Sglebius if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 4009182007Sroberto { 4010182007Sroberto ppsphaseadjust = 0.0; 4011182007Sroberto } 4012182007Sroberto#endif 4013182007Sroberto 4014182007Sroberto /* 401554359Sroberto * we have a PPS signal - much better than the RS232 stuff (we hope) 401654359Sroberto */ 401754359Sroberto offset = parsetime->parse_ptime.fp; 401854359Sroberto 401954359Sroberto#ifdef DEBUG 402054359Sroberto if (debug > 3) 402154359Sroberto printf("PARSE receiver #%d: PPStime %s\n", 402254359Sroberto CLK_UNIT(parse->peer), 402354359Sroberto prettydate(&offset)); 402454359Sroberto#endif 402554359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 402654359Sroberto { 4027290000Sglebius if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) && 4028290000Sglebius M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf)) 402954359Sroberto { 4030182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 4031290000Sglebius 403254359Sroberto /* 403354359Sroberto * RS232 offsets within [-0.5..0.5[ - take PPS offsets 403454359Sroberto */ 403554359Sroberto 403654359Sroberto if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 403754359Sroberto { 403854359Sroberto reftime = off = offset; 4039290000Sglebius if (reftime.l_uf & 0x80000000) 404054359Sroberto reftime.l_ui++; 404154359Sroberto reftime.l_uf = 0; 404256746Sroberto 4043290000Sglebius 404454359Sroberto /* 404554359Sroberto * implied on second offset 404654359Sroberto */ 404754359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4048290000Sglebius off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 404954359Sroberto } 405054359Sroberto else 405154359Sroberto { 405254359Sroberto /* 405354359Sroberto * time code describes pulse 405454359Sroberto */ 405554359Sroberto reftime = off = parsetime->parse_time.fp; 405654359Sroberto 405754359Sroberto L_SUB(&off, &offset); /* true offset */ 405854359Sroberto } 405954359Sroberto } 406054359Sroberto /* 406154359Sroberto * take RS232 offset when PPS when out of bounds 406254359Sroberto */ 406354359Sroberto } 406454359Sroberto else 406554359Sroberto { 4066182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 406754359Sroberto /* 406854359Sroberto * Well, no time code to guide us - assume on second pulse 406954359Sroberto * and pray, that we are within [-0.5..0.5[ 407054359Sroberto */ 407154359Sroberto off = offset; 407254359Sroberto reftime = offset; 4073290000Sglebius if (reftime.l_uf & 0x80000000) 407454359Sroberto reftime.l_ui++; 407554359Sroberto reftime.l_uf = 0; 407654359Sroberto /* 407754359Sroberto * implied on second offset 407854359Sroberto */ 407954359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4080290000Sglebius off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 408154359Sroberto } 408254359Sroberto } 408354359Sroberto else 408454359Sroberto { 408554359Sroberto if (!PARSE_TIMECODE(parsetime->parse_state)) 408654359Sroberto { 408754359Sroberto /* 408854359Sroberto * Well, no PPS, no TIMECODE, no more work ... 408954359Sroberto */ 409054359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 409154359Sroberto parse->parse_type->cl_message) 409254359Sroberto parse->parse_type->cl_message(parse, parsetime); 409354359Sroberto return; 409454359Sroberto } 409554359Sroberto } 409654359Sroberto 409754359Sroberto#ifdef DEBUG 409854359Sroberto if (debug > 3) 409954359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 410054359Sroberto CLK_UNIT(parse->peer), 410154359Sroberto prettydate(&reftime), 410254359Sroberto prettydate(&rectime), 410354359Sroberto lfptoa(&off,6)); 410454359Sroberto#endif 410554359Sroberto 410654359Sroberto 410754359Sroberto rectime = reftime; 410854359Sroberto L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 4109290000Sglebius 411054359Sroberto#ifdef DEBUG 411154359Sroberto if (debug > 3) 411254359Sroberto printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 411354359Sroberto CLK_UNIT(parse->peer), 411454359Sroberto prettydate(&reftime), 411554359Sroberto prettydate(&rectime)); 411654359Sroberto#endif 411754359Sroberto 411854359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 411954359Sroberto parse->parse_type->cl_message) 412054359Sroberto parse->parse_type->cl_message(parse, parsetime); 412154359Sroberto 412254359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 412354359Sroberto { 412454359Sroberto /* 412554359Sroberto * log OK status 412654359Sroberto */ 412754359Sroberto parse_event(parse, CEVNT_NOMINAL); 412854359Sroberto } 412954359Sroberto 413054359Sroberto clear_err(parse, ERR_BADIO); 413154359Sroberto clear_err(parse, ERR_BADDATA); 413254359Sroberto clear_err(parse, ERR_NODATA); 413354359Sroberto clear_err(parse, ERR_INTERNAL); 4134290000Sglebius 413554359Sroberto /* 413654359Sroberto * and now stick it into the clock machine 413754359Sroberto * samples are only valid iff lastsync is not too old and 413854359Sroberto * we have seen the clock in sync at least once 413954359Sroberto * after the last time we didn't see an expected data telegram 4140182007Sroberto * at startup being not in sync is also bad just like 4141290000Sglebius * POWERUP state unless PARSE_F_POWERUPTRUST is set 414254359Sroberto * see the clock states section above for more reasoning 414354359Sroberto */ 4144290000Sglebius if (((current_time - parse->lastsync) > parse->maxunsync) || 4145290000Sglebius (parse->lastsync < parse->lastmissed) || 4146182007Sroberto ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 4147290000Sglebius (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) && 4148290000Sglebius PARSE_POWERUP(parsetime->parse_state))) 414954359Sroberto { 415054359Sroberto parse->generic->leap = LEAP_NOTINSYNC; 4151182007Sroberto parse->lastsync = 0; /* wait for full sync again */ 415254359Sroberto } 415354359Sroberto else 415454359Sroberto { 415554359Sroberto if (PARSE_LEAPADD(parsetime->parse_state)) 415654359Sroberto { 415754359Sroberto /* 415854359Sroberto * we pick this state also for time code that pass leap warnings 415954359Sroberto * without direction information (as earth is currently slowing 416054359Sroberto * down). 416154359Sroberto */ 416254359Sroberto parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 416354359Sroberto } 416454359Sroberto else 416554359Sroberto if (PARSE_LEAPDEL(parsetime->parse_state)) 416654359Sroberto { 416754359Sroberto parse->generic->leap = LEAP_DELSECOND; 416854359Sroberto } 416954359Sroberto else 417054359Sroberto { 417154359Sroberto parse->generic->leap = LEAP_NOWARNING; 417254359Sroberto } 417354359Sroberto } 4174182007Sroberto 4175182007Sroberto if (parse->generic->leap != LEAP_NOTINSYNC) 4176182007Sroberto { 4177182007Sroberto /* 4178182007Sroberto * only good/trusted samples are interesting 4179182007Sroberto */ 4180182007Sroberto#ifdef DEBUG 4181290000Sglebius if (debug > 2) 4182290000Sglebius { 4183290000Sglebius printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 4184182007Sroberto CLK_UNIT(parse->peer), 4185182007Sroberto prettydate(&reftime), 4186182007Sroberto prettydate(&rectime), 4187182007Sroberto fudge); 4188182007Sroberto } 4189182007Sroberto#endif 4190182007Sroberto parse->generic->lastref = reftime; 4191290000Sglebius 4192182007Sroberto refclock_process_offset(parse->generic, reftime, rectime, fudge); 4193182007Sroberto 4194290000Sglebius#ifdef HAVE_PPSAPI 4195182007Sroberto /* 4196182007Sroberto * pass PPS information on to PPS clock 4197182007Sroberto */ 4198182007Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4199290000Sglebius { 4200290000Sglebius parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS); 4201182007Sroberto parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4202182007Sroberto } 4203290000Sglebius#endif 4204182007Sroberto } else { 4205290000Sglebius parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4206290000Sglebius parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS); 4207182007Sroberto } 4208182007Sroberto 420954359Sroberto /* 4210290000Sglebius * ready, unless the machine wants a sample or 4211182007Sroberto * we are in fast startup mode (peer->dist > MAXDISTANCE) 421254359Sroberto */ 4213182007Sroberto if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 421454359Sroberto return; 421554359Sroberto 421654359Sroberto parse->pollneeddata = 0; 421754359Sroberto 4218182007Sroberto parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4219182007Sroberto 422054359Sroberto refclock_receive(parse->peer); 422154359Sroberto} 4222290000Sglebius 422354359Sroberto/**=========================================================================== 422454359Sroberto ** special code for special clocks 422554359Sroberto **/ 422654359Sroberto 422754359Srobertostatic void 422854359Srobertomk_utcinfo( 4229290000Sglebius char *t, // pointer to the output string buffer 423054359Sroberto int wnt, 423154359Sroberto int wnlsf, 423254359Sroberto int dn, 423354359Sroberto int dtls, 4234182007Sroberto int dtlsf, 4235290000Sglebius int size // size of the output string buffer 423654359Sroberto ) 423754359Sroberto{ 4238290000Sglebius /* 4239290000Sglebius * The week number transmitted by the GPS satellites for the leap date 4240290000Sglebius * is truncated to 8 bits only. If the nearest leap second date is off 4241290000Sglebius * the current date by more than +/- 128 weeks then conversion to a 4242290000Sglebius * calendar date is ambiguous. On the other hand, if a leap second is 4243290000Sglebius * currently being announced (i.e. dtlsf != dtls) then the week number 4244290000Sglebius * wnlsf is close enough, and we can unambiguously determine the date 4245290000Sglebius * for which the leap second is scheduled. 4246290000Sglebius */ 4247290000Sglebius if ( dtlsf != dtls ) 4248290000Sglebius { 4249290000Sglebius time_t t_ls; 4250290000Sglebius struct tm *tm; 4251290000Sglebius int n = 0; 4252290000Sglebius 4253290000Sglebius if (wnlsf < GPSWRAP) 4254290000Sglebius wnlsf += GPSWEEKS; 4255290000Sglebius 4256290000Sglebius if (wnt < GPSWRAP) 4257290000Sglebius wnt += GPSWEEKS; 4258290000Sglebius 4259290000Sglebius t_ls = (time_t) wnlsf * SECSPERWEEK 4260290000Sglebius + (time_t) dn * SECSPERDAY 4261290000Sglebius + GPS_SEC_BIAS - 1; 4262290000Sglebius 4263290000Sglebius tm = gmtime( &t_ls ); 4264290000Sglebius if (tm == NULL) // gmtime() failed 4265290000Sglebius { 4266290000Sglebius snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" ); 4267290000Sglebius return; 4268290000Sglebius } 4269290000Sglebius 4270290000Sglebius n += snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s", 4271290000Sglebius dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" ); 4272290000Sglebius n += snprintf( t + n, size - n, " at UTC midnight at the end of %s, %04i-%02i-%02i", 4273290000Sglebius daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday ); 4274290000Sglebius } 4275290000Sglebius else 4276290000Sglebius snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls ); 4277290000Sglebius 427854359Sroberto} 427954359Sroberto 428054359Sroberto#ifdef CLOCK_MEINBERG 428154359Sroberto/**=========================================================================== 4282290000Sglebius ** Meinberg GPS receiver support 428354359Sroberto **/ 428454359Sroberto 428554359Sroberto/*------------------------------------------------------------ 4286290000Sglebius * gps16x_message - process messages from Meinberg GPS receiver 428754359Sroberto */ 428854359Srobertostatic void 428954359Srobertogps16x_message( 429054359Sroberto struct parseunit *parse, 429154359Sroberto parsetime_t *parsetime 429254359Sroberto ) 429354359Sroberto{ 4294182007Sroberto if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 429554359Sroberto { 429654359Sroberto GPS_MSG_HDR header; 429754359Sroberto unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 4298290000Sglebius 429954359Sroberto#ifdef DEBUG 430054359Sroberto if (debug > 2) 430154359Sroberto { 430254359Sroberto char msgbuffer[600]; 4303290000Sglebius 430454359Sroberto mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 430554359Sroberto printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 430654359Sroberto CLK_UNIT(parse->peer), 430754359Sroberto parsetime->parse_msglen, 430854359Sroberto msgbuffer); 430954359Sroberto } 431054359Sroberto#endif 431154359Sroberto get_mbg_header(&bufp, &header); 4312290000Sglebius if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 4313290000Sglebius (header.len == 0 || 4314290000Sglebius (header.len < sizeof(parsetime->parse_msg) && 4315290000Sglebius header.data_csum == mbg_csum(bufp, header.len)))) 431654359Sroberto { 431754359Sroberto /* 431854359Sroberto * clean message 431954359Sroberto */ 4320290000Sglebius switch (header.cmd) 432154359Sroberto { 432254359Sroberto case GPS_SW_REV: 432354359Sroberto { 432454359Sroberto char buffer[64]; 432554359Sroberto SW_REV gps_sw_rev; 4326290000Sglebius 432754359Sroberto get_mbg_sw_rev(&bufp, &gps_sw_rev); 4328182007Sroberto snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 432954359Sroberto (gps_sw_rev.code >> 8) & 0xFF, 433054359Sroberto gps_sw_rev.code & 0xFF, 433154359Sroberto gps_sw_rev.name[0] ? " " : "", 433254359Sroberto gps_sw_rev.name); 4333182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 433454359Sroberto } 433554359Sroberto break; 433654359Sroberto 4337290000Sglebius case GPS_BVAR_STAT: 433854359Sroberto { 433954359Sroberto static struct state 434054359Sroberto { 4341290000Sglebius BVAR_STAT flag; /* status flag */ 4342290000Sglebius const char *string; /* bit name */ 434354359Sroberto } states[] = 434454359Sroberto { 4345290000Sglebius { BVAR_CFGH_INVALID, "Configuration/Health" }, 4346290000Sglebius { BVAR_ALM_NOT_COMPLETE, "Almanachs" }, 4347290000Sglebius { BVAR_UTC_INVALID, "UTC Correction" }, 4348290000Sglebius { BVAR_IONO_INVALID, "Ionospheric Correction" }, 4349290000Sglebius { BVAR_RCVR_POS_INVALID, "Receiver Position" }, 4350290000Sglebius { 0, "" } 435154359Sroberto }; 4352290000Sglebius BVAR_STAT status; 435354359Sroberto struct state *s = states; 435454359Sroberto char buffer[512]; 435554359Sroberto char *p, *b; 4356290000Sglebius 4357290000Sglebius status = (BVAR_STAT) get_lsb_short(&bufp); 4358290000Sglebius p = b = buffer; 4359290000Sglebius p = ap(buffer, sizeof(buffer), p, 4360290000Sglebius "meinberg_gps_status=\"[0x%04x] ", 4361290000Sglebius status); 4362290000Sglebius 436354359Sroberto if (status) 436454359Sroberto { 4365290000Sglebius p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: "); 4366290000Sglebius b = p; 436754359Sroberto while (s->flag) 436854359Sroberto { 436954359Sroberto if (status & s->flag) 437054359Sroberto { 437154359Sroberto if (p != b) 437254359Sroberto { 4373290000Sglebius p = ap(buffer, sizeof(buffer), p, ", "); 437454359Sroberto } 4375290000Sglebius 4376290000Sglebius p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string); 437754359Sroberto } 437854359Sroberto s++; 437954359Sroberto } 4380290000Sglebius p = ap(buffer, sizeof(buffer), p, "\""); 438154359Sroberto } 438254359Sroberto else 438354359Sroberto { 4384290000Sglebius p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\""); 438554359Sroberto } 4386290000Sglebius 4387182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 438854359Sroberto } 438954359Sroberto break; 439054359Sroberto 439154359Sroberto case GPS_POS_XYZ: 439254359Sroberto { 439354359Sroberto XYZ xyz; 439454359Sroberto char buffer[256]; 4395290000Sglebius 439654359Sroberto get_mbg_xyz(&bufp, xyz); 4397182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 439854359Sroberto mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 439954359Sroberto mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 440054359Sroberto mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 4401290000Sglebius 440254359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 440354359Sroberto } 440454359Sroberto break; 4405290000Sglebius 440654359Sroberto case GPS_POS_LLA: 440754359Sroberto { 440854359Sroberto LLA lla; 440954359Sroberto char buffer[256]; 4410290000Sglebius 441154359Sroberto get_mbg_lla(&bufp, lla); 4412290000Sglebius 4413182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 441454359Sroberto mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 4415290000Sglebius mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 441654359Sroberto mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 4417290000Sglebius 441854359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 441954359Sroberto } 442054359Sroberto break; 4421290000Sglebius 442254359Sroberto case GPS_TZDL: 442354359Sroberto break; 4424290000Sglebius 442554359Sroberto case GPS_PORT_PARM: 442654359Sroberto break; 4427290000Sglebius 442854359Sroberto case GPS_SYNTH: 442954359Sroberto break; 4430290000Sglebius 443154359Sroberto case GPS_ANT_INFO: 443254359Sroberto { 443354359Sroberto ANT_INFO antinfo; 4434182007Sroberto char buffer[512]; 4435290000Sglebius char *p, *q; 4436290000Sglebius 443754359Sroberto get_mbg_antinfo(&bufp, &antinfo); 4438290000Sglebius p = buffer; 4439290000Sglebius p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\""); 444054359Sroberto switch (antinfo.status) 444154359Sroberto { 4442290000Sglebius case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected 4443290000Sglebius p = ap(buffer, sizeof(buffer), 4444290000Sglebius p, "<OK>"); 444554359Sroberto break; 4446290000Sglebius 4447290000Sglebius case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set 4448290000Sglebius q = ap(buffer, sizeof(buffer), 4449290000Sglebius p, "DISCONNECTED since "); 445054359Sroberto NLOG(NLOG_CLOCKSTATUS) 445154359Sroberto ERR(ERR_BADSTATUS) 445254359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 445354359Sroberto CLK_UNIT(parse->peer), p); 4454290000Sglebius 4455290000Sglebius p = q; 4456290000Sglebius mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 445754359Sroberto *p = '\0'; 445854359Sroberto break; 4459290000Sglebius 4460290000Sglebius case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid 4461290000Sglebius p = ap(buffer, sizeof(buffer), 4462290000Sglebius p, "SYNC AFTER RECONNECT on "); 4463290000Sglebius mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0); 4464290000Sglebius p = ap(buffer, sizeof(buffer), 4465290000Sglebius p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ", 446654359Sroberto (antinfo.delta_t < 0) ? '-' : '+', 4467290000Sglebius (long) ABS(antinfo.delta_t) / 10000, 4468290000Sglebius (long) ABS(antinfo.delta_t) % 10000); 4469290000Sglebius mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 447054359Sroberto *p = '\0'; 447154359Sroberto break; 4472290000Sglebius 447354359Sroberto default: 4474290000Sglebius p = ap(buffer, sizeof(buffer), 4475290000Sglebius p, "bad status 0x%04x", 4476290000Sglebius antinfo.status); 447754359Sroberto break; 447854359Sroberto } 4479290000Sglebius 4480290000Sglebius p = ap(buffer, sizeof(buffer), p, "\""); 4481290000Sglebius 4482290000Sglebius set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 448354359Sroberto } 448454359Sroberto break; 4485290000Sglebius 448654359Sroberto case GPS_UCAP: 448754359Sroberto break; 4488290000Sglebius 448954359Sroberto case GPS_CFGH: 449054359Sroberto { 449154359Sroberto CFGH cfgh; 4492182007Sroberto char buffer[512]; 4493182007Sroberto char *p; 4494290000Sglebius 449554359Sroberto get_mbg_cfgh(&bufp, &cfgh); 449654359Sroberto if (cfgh.valid) 449754359Sroberto { 4498290000Sglebius const char *cp; 4499290000Sglebius uint16_t tmp_val; 450054359Sroberto int i; 4501290000Sglebius 450254359Sroberto p = buffer; 4503290000Sglebius p = ap(buffer, sizeof(buffer), 4504290000Sglebius p, "gps_tot_51=\""); 4505182007Sroberto mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4506290000Sglebius p = ap(buffer, sizeof(buffer), 4507290000Sglebius p, "\""); 4508290000Sglebius set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4509290000Sglebius 451054359Sroberto p = buffer; 4511290000Sglebius p = ap(buffer, sizeof(buffer), 4512290000Sglebius p, "gps_tot_63=\""); 4513182007Sroberto mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4514290000Sglebius p = ap(buffer, sizeof(buffer), 4515290000Sglebius p, "\""); 4516290000Sglebius set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4517290000Sglebius 451854359Sroberto p = buffer; 4519290000Sglebius p = ap(buffer, sizeof(buffer), 4520290000Sglebius p, "gps_t0a=\""); 4521182007Sroberto mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4522290000Sglebius p = ap(buffer, sizeof(buffer), 4523290000Sglebius p, "\""); 4524290000Sglebius set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4525290000Sglebius 4526290000Sglebius for (i = 0; i < N_SVNO_GPS; i++) 452754359Sroberto { 452854359Sroberto p = buffer; 4529290000Sglebius p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS); 4530290000Sglebius 4531290000Sglebius tmp_val = cfgh.health[i]; /* a 6 bit SV health code */ 4532290000Sglebius p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val); 4533290000Sglebius /* "All Ones" has a special meaning" */ 4534290000Sglebius if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */ 4535290000Sglebius cp = "SV UNAVAILABLE"; 4536290000Sglebius else { 4537290000Sglebius /* The MSB contains a summary of the 3 MSBs of the 8 bit health code, 4538290000Sglebius * indicating if the data sent by the satellite is OK or not. */ 4539290000Sglebius p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" ); 4540290000Sglebius 4541290000Sglebius /* The 5 LSBs contain the status of the different signals sent by the satellite. */ 4542290000Sglebius switch (tmp_val & 0x1F) 4543290000Sglebius { 4544290000Sglebius case 0x00: cp = "SIGNAL OK"; break; 4545290000Sglebius /* codes 0x01 through 0x1B indicate that one or more 4546290000Sglebius * specific signal components are weak or dead. 4547290000Sglebius * We don't decode this here in detail. */ 4548290000Sglebius case 0x1C: cp = "SV IS TEMP OUT"; break; 4549290000Sglebius case 0x1D: cp = "SV WILL BE TEMP OUT"; break; 4550290000Sglebius default: cp = "TRANSMISSION PROBLEMS"; break; 4551290000Sglebius } 455254359Sroberto } 4553290000Sglebius p = ap(buffer, sizeof(buffer), p, "%s)", cp ); 4554290000Sglebius 4555290000Sglebius tmp_val = cfgh.cfg[i]; /* a 4 bit SV configuration/type code */ 4556290000Sglebius p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val); 4557290000Sglebius switch (tmp_val & 0x7) 455854359Sroberto { 4559290000Sglebius case 0x00: cp = "(reserved)"; break; 4560290000Sglebius case 0x01: cp = "BLOCK II/IIA/IIR"; break; 4561290000Sglebius case 0x02: cp = "BLOCK IIR-M"; break; 4562290000Sglebius case 0x03: cp = "BLOCK IIF"; break; 4563290000Sglebius case 0x04: cp = "BLOCK III"; break; 4564290000Sglebius default: cp = "unknown SV type"; break; 456554359Sroberto } 4566290000Sglebius p = ap(buffer, sizeof(buffer), p, "%s", cp ); 4567290000Sglebius if (tmp_val & 0x08) /* A-S is on, P-code is encrypted */ 4568290000Sglebius p = ap( buffer, sizeof(buffer), p, ", A-S on" ); 4569290000Sglebius 4570290000Sglebius p = ap(buffer, sizeof(buffer), p, ")\""); 4571290000Sglebius set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 457254359Sroberto } 457354359Sroberto } 457454359Sroberto } 457554359Sroberto break; 4576290000Sglebius 457754359Sroberto case GPS_ALM: 457854359Sroberto break; 4579290000Sglebius 458054359Sroberto case GPS_EPH: 458154359Sroberto break; 4582290000Sglebius 458354359Sroberto case GPS_UTC: 458454359Sroberto { 458554359Sroberto UTC utc; 458654359Sroberto char buffer[512]; 458754359Sroberto char *p; 4588290000Sglebius 458954359Sroberto p = buffer; 4590290000Sglebius 459154359Sroberto get_mbg_utc(&bufp, &utc); 4592290000Sglebius 459354359Sroberto if (utc.valid) 459454359Sroberto { 4595290000Sglebius p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\""); 4596290000Sglebius mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 459754359Sroberto p += strlen(p); 4598290000Sglebius p = ap(buffer, sizeof(buffer), p, "\""); 459954359Sroberto } 460054359Sroberto else 460154359Sroberto { 4602290000Sglebius p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\""); 460354359Sroberto } 4604290000Sglebius set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 460554359Sroberto } 460654359Sroberto break; 4607290000Sglebius 460854359Sroberto case GPS_IONO: 460954359Sroberto break; 4610290000Sglebius 461154359Sroberto case GPS_ASCII_MSG: 461254359Sroberto { 461354359Sroberto ASCII_MSG gps_ascii_msg; 461454359Sroberto char buffer[128]; 4615290000Sglebius 461654359Sroberto get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 4617290000Sglebius 461854359Sroberto if (gps_ascii_msg.valid) 461954359Sroberto { 462054359Sroberto char buffer1[128]; 462154359Sroberto mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 4622290000Sglebius 4623182007Sroberto snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 462454359Sroberto } 462554359Sroberto else 4626290000Sglebius snprintf(buffer, sizeof(buffer), "gps_message=<NONE>"); 4627290000Sglebius 4628290000Sglebius set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 462954359Sroberto } 4630290000Sglebius 463154359Sroberto break; 4632290000Sglebius 463354359Sroberto default: 463454359Sroberto break; 463554359Sroberto } 463654359Sroberto } 463754359Sroberto else 463854359Sroberto { 4639290000Sglebius msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), " 4640290000Sglebius "data_len = %d, data_csum = 0x%x (expected 0x%x)", 464154359Sroberto CLK_UNIT(parse->peer), 4642290000Sglebius header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 4643290000Sglebius header.len, 4644290000Sglebius header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0))); 464554359Sroberto } 464654359Sroberto } 4647290000Sglebius 464854359Sroberto return; 464954359Sroberto} 465054359Sroberto 465154359Sroberto/*------------------------------------------------------------ 465254359Sroberto * gps16x_poll - query the reciver peridically 465354359Sroberto */ 465454359Srobertostatic void 465554359Srobertogps16x_poll( 465654359Sroberto struct peer *peer 465754359Sroberto ) 465854359Sroberto{ 4659290000Sglebius struct parseunit *parse = peer->procptr->unitptr; 4660290000Sglebius 4661290000Sglebius static GPS_MSG_HDR sequence[] = 466254359Sroberto { 466354359Sroberto { GPS_SW_REV, 0, 0, 0 }, 4664290000Sglebius { GPS_BVAR_STAT, 0, 0, 0 }, 466554359Sroberto { GPS_UTC, 0, 0, 0 }, 466654359Sroberto { GPS_ASCII_MSG, 0, 0, 0 }, 466754359Sroberto { GPS_ANT_INFO, 0, 0, 0 }, 466854359Sroberto { GPS_CFGH, 0, 0, 0 }, 466954359Sroberto { GPS_POS_XYZ, 0, 0, 0 }, 467054359Sroberto { GPS_POS_LLA, 0, 0, 0 }, 467154359Sroberto { (unsigned short)~0, 0, 0, 0 } 467254359Sroberto }; 4673290000Sglebius 467454359Sroberto int rtc; 467554359Sroberto unsigned char cmd_buffer[64]; 467654359Sroberto unsigned char *outp = cmd_buffer; 467754359Sroberto GPS_MSG_HDR *header; 4678290000Sglebius 467954359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 468054359Sroberto { 4681290000Sglebius parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 468254359Sroberto } 468354359Sroberto 4684290000Sglebius if (sequence[parse->localstate].cmd == (unsigned short)~0) 468554359Sroberto parse->localstate = 0; 4686290000Sglebius 468754359Sroberto header = sequence + parse->localstate++; 4688290000Sglebius 468954359Sroberto *outp++ = SOH; /* start command */ 4690290000Sglebius 469154359Sroberto put_mbg_header(&outp, header); 469254359Sroberto outp = cmd_buffer + 1; 4693290000Sglebius 4694290000Sglebius header->hdr_csum = (short)mbg_csum(outp, 6); 469554359Sroberto put_mbg_header(&outp, header); 4696290000Sglebius 469754359Sroberto#ifdef DEBUG 469854359Sroberto if (debug > 2) 469954359Sroberto { 470054359Sroberto char buffer[128]; 4701290000Sglebius 470254359Sroberto mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 470354359Sroberto printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 470454359Sroberto CLK_UNIT(parse->peer), 470554359Sroberto parse->localstate - 1, 470654359Sroberto (int)(outp - cmd_buffer), 4707290000Sglebius buffer); 470854359Sroberto } 470954359Sroberto#endif 4710290000Sglebius 4711290000Sglebius rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 4712290000Sglebius 471354359Sroberto if (rtc < 0) 471454359Sroberto { 471554359Sroberto ERR(ERR_BADIO) 471654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 471754359Sroberto } 471854359Sroberto else 471954359Sroberto if (rtc != outp - cmd_buffer) 472054359Sroberto { 472154359Sroberto ERR(ERR_BADIO) 472254359Sroberto 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)); 472354359Sroberto } 472454359Sroberto 472554359Sroberto clear_err(parse, ERR_BADIO); 472654359Sroberto return; 472754359Sroberto} 472854359Sroberto 472954359Sroberto/*-------------------------------------------------- 473054359Sroberto * init routine - setup timer 473154359Sroberto */ 473254359Srobertostatic int 473354359Srobertogps16x_poll_init( 473454359Sroberto struct parseunit *parse 473554359Sroberto ) 473654359Sroberto{ 473754359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 473854359Sroberto { 4739290000Sglebius parse->peer->procptr->action = gps16x_poll; 474054359Sroberto gps16x_poll(parse->peer); 474154359Sroberto } 474254359Sroberto 474354359Sroberto return 0; 474454359Sroberto} 474554359Sroberto 474654359Sroberto#else 474754359Srobertostatic void 474854359Srobertogps16x_message( 474954359Sroberto struct parseunit *parse, 475054359Sroberto parsetime_t *parsetime 475154359Sroberto ) 475254359Sroberto{} 475354359Srobertostatic int 475454359Srobertogps16x_poll_init( 475554359Sroberto struct parseunit *parse 475654359Sroberto ) 475754359Sroberto{ 475854359Sroberto return 1; 475954359Sroberto} 476054359Sroberto#endif /* CLOCK_MEINBERG */ 4761290000Sglebius 476254359Sroberto/**=========================================================================== 476354359Sroberto ** clock polling support 476454359Sroberto **/ 476554359Sroberto 476654359Sroberto/*-------------------------------------------------- 476754359Sroberto * direct poll routine 476854359Sroberto */ 476954359Srobertostatic void 477054359Srobertopoll_dpoll( 477154359Sroberto struct parseunit *parse 477254359Sroberto ) 477354359Sroberto{ 4774290000Sglebius long rtc; 477554359Sroberto const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 4776290000Sglebius long ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 477754359Sroberto 4778290000Sglebius rtc = write(parse->generic->io.fd, ps, ct); 477954359Sroberto if (rtc < 0) 478054359Sroberto { 478154359Sroberto ERR(ERR_BADIO) 478254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 478354359Sroberto } 478454359Sroberto else 478554359Sroberto if (rtc != ct) 478654359Sroberto { 478754359Sroberto ERR(ERR_BADIO) 4788290000Sglebius msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 478954359Sroberto } 479054359Sroberto clear_err(parse, ERR_BADIO); 479154359Sroberto} 479254359Sroberto 479354359Sroberto/*-------------------------------------------------- 479454359Sroberto * periodic poll routine 479554359Sroberto */ 479654359Srobertostatic void 479754359Srobertopoll_poll( 479854359Sroberto struct peer *peer 479954359Sroberto ) 480054359Sroberto{ 4801290000Sglebius struct parseunit *parse = peer->procptr->unitptr; 4802290000Sglebius 480354359Sroberto if (parse->parse_type->cl_poll) 480454359Sroberto parse->parse_type->cl_poll(parse); 480554359Sroberto 480654359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 480754359Sroberto { 4808290000Sglebius parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 480954359Sroberto } 481054359Sroberto} 481154359Sroberto 481254359Sroberto/*-------------------------------------------------- 481354359Sroberto * init routine - setup timer 481454359Sroberto */ 481554359Srobertostatic int 481654359Srobertopoll_init( 481754359Sroberto struct parseunit *parse 481854359Sroberto ) 481954359Sroberto{ 482054359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 482154359Sroberto { 4822290000Sglebius parse->peer->procptr->action = poll_poll; 482354359Sroberto poll_poll(parse->peer); 482454359Sroberto } 482554359Sroberto 482654359Sroberto return 0; 482754359Sroberto} 4828290000Sglebius 482954359Sroberto/**=========================================================================== 483054359Sroberto ** Trimble support 483154359Sroberto **/ 483254359Sroberto 483354359Sroberto/*------------------------------------------------------------- 483454359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init. 483554359Sroberto */ 483654359Srobertostatic int 483754359Srobertotrimbletaip_init( 483854359Sroberto struct parseunit *parse 483954359Sroberto ) 484054359Sroberto{ 484154359Sroberto#ifdef HAVE_TERMIOS 484254359Sroberto struct termios tio; 484354359Sroberto#endif 484454359Sroberto#ifdef HAVE_SYSV_TTYS 484554359Sroberto struct termio tio; 484654359Sroberto#endif 484754359Sroberto /* 484854359Sroberto * configure terminal line for trimble receiver 484954359Sroberto */ 485054359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 485154359Sroberto { 485254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 485354359Sroberto return 0; 485454359Sroberto } 485554359Sroberto else 485654359Sroberto { 485754359Sroberto tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 4858290000Sglebius 485954359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 486054359Sroberto { 486154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 486254359Sroberto return 0; 486354359Sroberto } 486454359Sroberto } 486554359Sroberto return poll_init(parse); 486654359Sroberto} 486754359Sroberto 486854359Sroberto/*-------------------------------------------------- 486954359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble 487054359Sroberto */ 487154359Srobertostatic const char *taipinit[] = { 487254359Sroberto ">FPV00000000<", 487354359Sroberto ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 487454359Sroberto ">FTM00020001<", 487554359Sroberto (char *)0 487654359Sroberto}; 4877290000Sglebius 487854359Srobertostatic void 487954359Srobertotrimbletaip_event( 488054359Sroberto struct parseunit *parse, 488154359Sroberto int event 488254359Sroberto ) 488354359Sroberto{ 488454359Sroberto switch (event) 488554359Sroberto { 488654359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 488754359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 488854359Sroberto { 488954359Sroberto const char **iv; 489054359Sroberto 489154359Sroberto iv = taipinit; 489254359Sroberto while (*iv) 489354359Sroberto { 4894290000Sglebius int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv)); 489554359Sroberto if (rtc < 0) 489654359Sroberto { 489754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 489854359Sroberto return; 489954359Sroberto } 490054359Sroberto else 490154359Sroberto { 4902290000Sglebius if (rtc != (int)strlen(*iv)) 490354359Sroberto { 490454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 490554359Sroberto CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 490654359Sroberto return; 490754359Sroberto } 490854359Sroberto } 490954359Sroberto iv++; 491054359Sroberto } 491154359Sroberto 491254359Sroberto NLOG(NLOG_CLOCKINFO) 491354359Sroberto ERR(ERR_BADIO) 491454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 491554359Sroberto CLK_UNIT(parse->peer)); 491654359Sroberto } 491754359Sroberto break; 491854359Sroberto 491954359Sroberto default: /* ignore */ 492054359Sroberto break; 492154359Sroberto } 492254359Sroberto} 492354359Sroberto 492454359Sroberto/* 492554359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module. 492654359Sroberto * It should support other Trimble receivers which use the Trimble Standard 492754359Sroberto * Interface Protocol (see below). 492854359Sroberto * 492954359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second 493054359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is 493154359Sroberto * coincident with the change of the GPS second. This is the same as 493254359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks 493354359Sroberto * specifically use a feature in the data message as a timing reference, but 493454359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter 493554359Sroberto * on the timing of the messages, so this driver only supports the use 493654359Sroberto * of the PPS pulse for accurate timing. Where it is determined that 493754359Sroberto * the offset is way off, when first starting up ntpd for example, 493854359Sroberto * the timing of the data stream is used until the offset becomes low enough 493956746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used. 494054359Sroberto * 494154359Sroberto * It can use either option for receiving PPS information - the 'ppsclock' 494254359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier 494354359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only 494454359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in 494554359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter 494654359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another 494754359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input, 494854359Sroberto * by whichever method, is handled in ntp_loopfilter.c 494954359Sroberto * 495054359Sroberto * The receiver uses a serial message protocol called Trimble Standard 495154359Sroberto * Interface Protocol (it can support others but this driver only supports 495254359Sroberto * TSIP). Messages in this protocol have the following form: 495354359Sroberto * 495454359Sroberto * <DLE><id> ... <data> ... <DLE><ETX> 495554359Sroberto * 495654359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 495754359Sroberto * on transmission and compressed back to one on reception. Otherwise 495854359Sroberto * the values of data bytes can be anything. The serial interface is RS-422 495954359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 496054359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single, 496154359Sroberto * and double datatypes. Integers are two bytes, sent most significant first. 496254359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent 496354359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point 496454359Sroberto * numbers (8 byte) sent sign & exponent first. 496554359Sroberto * The receiver supports a large set of messages, only a small subset of 496654359Sroberto * which are used here. From driver to receiver the following are used: 496754359Sroberto * 496854359Sroberto * ID Description 496954359Sroberto * 497054359Sroberto * 21 Request current time 497154359Sroberto * 22 Mode Select 497254359Sroberto * 2C Set/Request operating parameters 497354359Sroberto * 2F Request UTC info 497454359Sroberto * 35 Set/Request I/O options 497554359Sroberto 497654359Sroberto * From receiver to driver the following are recognised: 497754359Sroberto * 497854359Sroberto * ID Description 497954359Sroberto * 498054359Sroberto * 41 GPS Time 498154359Sroberto * 44 Satellite selection, PDOP, mode 498254359Sroberto * 46 Receiver health 498354359Sroberto * 4B Machine code/status 498454359Sroberto * 4C Report operating parameters (debug only) 498554359Sroberto * 4F UTC correction data (used to get leap second warnings) 498654359Sroberto * 55 I/O options (debug only) 498754359Sroberto * 498854359Sroberto * All others are accepted but ignored. 498954359Sroberto * 499054359Sroberto */ 499154359Sroberto 499254359Sroberto#define PI 3.1415926535898 /* lots of sig figs */ 499354359Sroberto#define D2R PI/180.0 499454359Sroberto 499554359Sroberto/*------------------------------------------------------------------- 499654359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 499754359Sroberto * interface to the receiver. 499854359Sroberto * 499954359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and 500054359Sroberto * float implementation dependend - these must be converted to portable 500154359Sroberto * versions ! 500254359Sroberto * 500354359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems 500454359Sroberto * with IEEE754 floats as native floats 500554359Sroberto */ 500654359Sroberto 500754359Srobertotypedef struct trimble 500854359Sroberto{ 500954359Sroberto u_long last_msg; /* last message received */ 5010182007Sroberto u_long last_reset; /* last time a reset was issued */ 501154359Sroberto u_char qtracking; /* query tracking status */ 501254359Sroberto u_long ctrack; /* current tracking set */ 501354359Sroberto u_long ltrack; /* last tracking set */ 501454359Sroberto} trimble_t; 501554359Sroberto 501654359Srobertounion uval { 501754359Sroberto u_char bd[8]; 501854359Sroberto int iv; 501954359Sroberto float fv; 502054359Sroberto double dv; 502154359Sroberto}; 5022290000Sglebius 502354359Srobertostruct txbuf 502454359Sroberto{ 502554359Sroberto short idx; /* index to first unused byte */ 502654359Sroberto u_char *txt; /* pointer to actual data buffer */ 502754359Sroberto}; 502854359Sroberto 5029290000Sglebiusvoid sendcmd (struct txbuf *buf, int c); 5030290000Sglebiusvoid sendbyte (struct txbuf *buf, int b); 5031290000Sglebiusvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5032290000Sglebiusvoid sendint (struct txbuf *buf, int a); 5033290000Sglebiusvoid sendflt (struct txbuf *buf, double a); 5034290000Sglebius 503554359Srobertovoid 503654359Srobertosendcmd( 503754359Sroberto struct txbuf *buf, 503854359Sroberto int c 503954359Sroberto ) 504054359Sroberto{ 504154359Sroberto buf->txt[0] = DLE; 504254359Sroberto buf->txt[1] = (u_char)c; 504354359Sroberto buf->idx = 2; 504454359Sroberto} 504554359Sroberto 5046290000Sglebiusvoid sendcmd (struct txbuf *buf, int c); 5047290000Sglebiusvoid sendbyte (struct txbuf *buf, int b); 5048290000Sglebiusvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5049290000Sglebiusvoid sendint (struct txbuf *buf, int a); 5050290000Sglebiusvoid sendflt (struct txbuf *buf, double a); 5051290000Sglebius 505254359Srobertovoid 505354359Srobertosendbyte( 505454359Sroberto struct txbuf *buf, 505554359Sroberto int b 505654359Sroberto ) 505754359Sroberto{ 505854359Sroberto if (b == DLE) 505954359Sroberto buf->txt[buf->idx++] = DLE; 506054359Sroberto buf->txt[buf->idx++] = (u_char)b; 506154359Sroberto} 506254359Sroberto 506354359Srobertovoid 506454359Srobertosendetx( 506554359Sroberto struct txbuf *buf, 506654359Sroberto struct parseunit *parse 506754359Sroberto ) 506854359Sroberto{ 506954359Sroberto buf->txt[buf->idx++] = DLE; 507054359Sroberto buf->txt[buf->idx++] = ETX; 507154359Sroberto 507254359Sroberto if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 507354359Sroberto { 507454359Sroberto ERR(ERR_BADIO) 507554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 507654359Sroberto } 507754359Sroberto else 507854359Sroberto { 507954359Sroberto#ifdef DEBUG 508054359Sroberto if (debug > 2) 508154359Sroberto { 508254359Sroberto char buffer[256]; 5083290000Sglebius 508454359Sroberto mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 508554359Sroberto printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 508654359Sroberto CLK_UNIT(parse->peer), 5087290000Sglebius buf->idx, buffer); 508854359Sroberto } 508954359Sroberto#endif 509054359Sroberto clear_err(parse, ERR_BADIO); 509154359Sroberto } 509254359Sroberto} 509354359Sroberto 5094290000Sglebiusvoid 509554359Srobertosendint( 509654359Sroberto struct txbuf *buf, 509754359Sroberto int a 509854359Sroberto ) 509954359Sroberto{ 510054359Sroberto /* send 16bit int, msbyte first */ 510154359Sroberto sendbyte(buf, (u_char)((a>>8) & 0xff)); 510254359Sroberto sendbyte(buf, (u_char)(a & 0xff)); 510354359Sroberto} 510454359Sroberto 510554359Srobertovoid 510654359Srobertosendflt( 510754359Sroberto struct txbuf *buf, 510854359Sroberto double a 510954359Sroberto ) 511054359Sroberto{ 511154359Sroberto int i; 511254359Sroberto union uval uval; 511354359Sroberto 5114290000Sglebius uval.fv = (float) a; 511554359Sroberto#ifdef WORDS_BIGENDIAN 511654359Sroberto for (i=0; i<=3; i++) 511754359Sroberto#else 511854359Sroberto for (i=3; i>=0; i--) 511954359Sroberto#endif 512054359Sroberto sendbyte(buf, uval.bd[i]); 512154359Sroberto} 512254359Sroberto 512354359Sroberto#define TRIM_POS_OPT 0x13 /* output position with high precision */ 512454359Sroberto#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 512554359Sroberto 512654359Sroberto/*-------------------------------------------------- 512754359Sroberto * trimble TSIP setup routine 512854359Sroberto */ 512954359Srobertostatic int 513054359Srobertotrimbletsip_setup( 513154359Sroberto struct parseunit *parse, 513254359Sroberto const char *reason 513356746Sroberto ) 513454359Sroberto{ 513554359Sroberto u_char buffer[256]; 513654359Sroberto struct txbuf buf; 5137182007Sroberto trimble_t *t = parse->localdata; 513854359Sroberto 5139182007Sroberto if (t && t->last_reset && 5140182007Sroberto ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 5141182007Sroberto return 1; /* not yet */ 5142182007Sroberto } 5143182007Sroberto 5144182007Sroberto if (t) 5145182007Sroberto t->last_reset = current_time; 5146290000Sglebius 514754359Sroberto buf.txt = buffer; 5148290000Sglebius 514954359Sroberto sendcmd(&buf, CMD_CVERSION); /* request software versions */ 515056746Sroberto sendetx(&buf, parse); 5151290000Sglebius 515254359Sroberto sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 515356746Sroberto sendbyte(&buf, 4); /* static */ 515456746Sroberto sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 515556746Sroberto sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 515656746Sroberto sendflt(&buf, 12.0); /* PDOP mask = 12 */ 515756746Sroberto sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 515856746Sroberto sendetx(&buf, parse); 5159290000Sglebius 516054359Sroberto sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 5161182007Sroberto sendbyte(&buf, 1); /* time transfer mode */ 516256746Sroberto sendetx(&buf, parse); 5163290000Sglebius 516454359Sroberto sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 516556746Sroberto sendetx(&buf, parse); 5166290000Sglebius 516754359Sroberto sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 516856746Sroberto sendbyte(&buf, 0x2); /* binary mode */ 516956746Sroberto sendetx(&buf, parse); 5170290000Sglebius 517154359Sroberto sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 517254359Sroberto sendbyte(&buf, TRIM_POS_OPT); /* position output */ 517354359Sroberto sendbyte(&buf, 0x00); /* no velocity output */ 517454359Sroberto sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 517554359Sroberto sendbyte(&buf, 0x00); /* no raw measurements */ 517656746Sroberto sendetx(&buf, parse); 5177290000Sglebius 517854359Sroberto sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 517954359Sroberto sendetx(&buf, parse); 518054359Sroberto 518154359Sroberto NLOG(NLOG_CLOCKINFO) 518254359Sroberto ERR(ERR_BADIO) 518354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 518454359Sroberto 518554359Sroberto return 0; 518654359Sroberto} 518754359Sroberto 518854359Sroberto/*-------------------------------------------------- 518954359Sroberto * TRIMBLE TSIP check routine 519054359Sroberto */ 519154359Srobertostatic void 519254359Srobertotrimble_check( 519354359Sroberto struct peer *peer 519454359Sroberto ) 519554359Sroberto{ 5196290000Sglebius struct parseunit *parse = peer->procptr->unitptr; 519754359Sroberto trimble_t *t = parse->localdata; 519854359Sroberto u_char buffer[256]; 519954359Sroberto struct txbuf buf; 520054359Sroberto buf.txt = buffer; 5201290000Sglebius 520254359Sroberto if (t) 520354359Sroberto { 520454359Sroberto if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 520554359Sroberto (void)trimbletsip_setup(parse, "message timeout"); 520654359Sroberto } 5207182007Sroberto 520854359Sroberto poll_poll(parse->peer); /* emit query string and re-arm timer */ 5209290000Sglebius 5210182007Sroberto if (t && t->qtracking) 521154359Sroberto { 521254359Sroberto u_long oldsats = t->ltrack & ~t->ctrack; 5213290000Sglebius 521454359Sroberto t->qtracking = 0; 521554359Sroberto t->ltrack = t->ctrack; 5216290000Sglebius 521754359Sroberto if (oldsats) 521854359Sroberto { 521954359Sroberto int i; 5220290000Sglebius 5221182007Sroberto for (i = 0; oldsats; i++) { 522254359Sroberto if (oldsats & (1 << i)) 522354359Sroberto { 522454359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 522554359Sroberto sendbyte(&buf, i+1); /* old sat */ 522654359Sroberto sendetx(&buf, parse); 522754359Sroberto } 5228182007Sroberto oldsats &= ~(1 << i); 5229182007Sroberto } 523054359Sroberto } 5231290000Sglebius 523254359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 523354359Sroberto sendbyte(&buf, 0x00); /* current tracking set */ 523454359Sroberto sendetx(&buf, parse); 523554359Sroberto } 523654359Sroberto} 523754359Sroberto 523854359Sroberto/*-------------------------------------------------- 523954359Sroberto * TRIMBLE TSIP end routine 524054359Sroberto */ 524154359Srobertostatic void 524254359Srobertotrimbletsip_end( 524354359Sroberto struct parseunit *parse 524454359Sroberto ) 524554359Sroberto{ trimble_t *t = parse->localdata; 5246290000Sglebius 524754359Sroberto if (t) 524854359Sroberto { 524954359Sroberto free(t); 5250290000Sglebius parse->localdata = NULL; 525154359Sroberto } 5252290000Sglebius parse->peer->procptr->nextaction = 0; 5253290000Sglebius parse->peer->procptr->action = NULL; 525454359Sroberto} 525554359Sroberto 525654359Sroberto/*-------------------------------------------------- 525754359Sroberto * TRIMBLE TSIP init routine 525854359Sroberto */ 525954359Srobertostatic int 526054359Srobertotrimbletsip_init( 526154359Sroberto struct parseunit *parse 526254359Sroberto ) 526354359Sroberto{ 526454359Sroberto#if defined(VEOL) || defined(VEOL2) 526554359Sroberto#ifdef HAVE_TERMIOS 526654359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 526754359Sroberto#endif 526854359Sroberto#ifdef HAVE_SYSV_TTYS 526954359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 527054359Sroberto#endif 527154359Sroberto /* 527254359Sroberto * allocate local data area 527354359Sroberto */ 527454359Sroberto if (!parse->localdata) 527554359Sroberto { 527654359Sroberto trimble_t *t; 5277290000Sglebius 527854359Sroberto t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 5279290000Sglebius 528054359Sroberto if (t) 528154359Sroberto { 528254359Sroberto memset((char *)t, 0, sizeof(trimble_t)); 528354359Sroberto t->last_msg = current_time; 528454359Sroberto } 528554359Sroberto } 528654359Sroberto 5287290000Sglebius parse->peer->procptr->action = trimble_check; 5288290000Sglebius parse->peer->procptr->nextaction = current_time; 528954359Sroberto 529054359Sroberto /* 529154359Sroberto * configure terminal line for ICANON mode with VEOL characters 529254359Sroberto */ 529354359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 529454359Sroberto { 529554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 529654359Sroberto return 0; 529754359Sroberto } 529854359Sroberto else 529954359Sroberto { 530054359Sroberto if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 530154359Sroberto { 530254359Sroberto#ifdef VEOL 530354359Sroberto tio.c_cc[VEOL] = ETX; 530454359Sroberto#endif 530554359Sroberto#ifdef VEOL2 530654359Sroberto tio.c_cc[VEOL2] = DLE; 530754359Sroberto#endif 530856746Sroberto } 530954359Sroberto 531054359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 531154359Sroberto { 531254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 531354359Sroberto return 0; 531454359Sroberto } 531554359Sroberto } 531654359Sroberto#endif 531754359Sroberto return trimbletsip_setup(parse, "initial startup"); 531854359Sroberto} 531954359Sroberto 532054359Sroberto/*------------------------------------------------------------ 532154359Sroberto * trimbletsip_event - handle Trimble events 532254359Sroberto * simple evente handler - attempt to re-initialize receiver 532354359Sroberto */ 532454359Srobertostatic void 532554359Srobertotrimbletsip_event( 532654359Sroberto struct parseunit *parse, 532754359Sroberto int event 532854359Sroberto ) 532954359Sroberto{ 533054359Sroberto switch (event) 533154359Sroberto { 533254359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 533354359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 533454359Sroberto (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 533554359Sroberto break; 533654359Sroberto 533754359Sroberto default: /* ignore */ 533854359Sroberto break; 533954359Sroberto } 534054359Sroberto} 534154359Sroberto 534254359Sroberto/* 534354359Sroberto * getflt, getint convert fields in the incoming data into the 534454359Sroberto * appropriate type of item 534554359Sroberto * 534654359Sroberto * CAVEAT: these routines are currently definitely byte order dependent 534754359Sroberto * and assume Representation(float) == IEEE754 534854359Sroberto * These functions MUST be converted to portable versions (especially 534954359Sroberto * converting the float representation into ntp_fp formats in order 535054359Sroberto * to avoid floating point operations at all! 535154359Sroberto */ 535254359Sroberto 535354359Srobertostatic float 535454359Srobertogetflt( 535554359Sroberto u_char *bp 535654359Sroberto ) 535754359Sroberto{ 535854359Sroberto union uval uval; 5359290000Sglebius 536054359Sroberto#ifdef WORDS_BIGENDIAN 536154359Sroberto uval.bd[0] = *bp++; 536254359Sroberto uval.bd[1] = *bp++; 536354359Sroberto uval.bd[2] = *bp++; 536454359Sroberto uval.bd[3] = *bp; 536554359Sroberto#else /* ! WORDS_BIGENDIAN */ 536654359Sroberto uval.bd[3] = *bp++; 536754359Sroberto uval.bd[2] = *bp++; 536854359Sroberto uval.bd[1] = *bp++; 536954359Sroberto uval.bd[0] = *bp; 537054359Sroberto#endif /* ! WORDS_BIGENDIAN */ 537154359Sroberto return uval.fv; 537254359Sroberto} 537354359Sroberto 537454359Srobertostatic double 537554359Srobertogetdbl( 537654359Sroberto u_char *bp 537754359Sroberto ) 537854359Sroberto{ 537954359Sroberto union uval uval; 5380290000Sglebius 538154359Sroberto#ifdef WORDS_BIGENDIAN 538254359Sroberto uval.bd[0] = *bp++; 538354359Sroberto uval.bd[1] = *bp++; 538454359Sroberto uval.bd[2] = *bp++; 538554359Sroberto uval.bd[3] = *bp++; 538654359Sroberto uval.bd[4] = *bp++; 538754359Sroberto uval.bd[5] = *bp++; 538854359Sroberto uval.bd[6] = *bp++; 538954359Sroberto uval.bd[7] = *bp; 539054359Sroberto#else /* ! WORDS_BIGENDIAN */ 539154359Sroberto uval.bd[7] = *bp++; 539254359Sroberto uval.bd[6] = *bp++; 539354359Sroberto uval.bd[5] = *bp++; 539454359Sroberto uval.bd[4] = *bp++; 539554359Sroberto uval.bd[3] = *bp++; 539654359Sroberto uval.bd[2] = *bp++; 539754359Sroberto uval.bd[1] = *bp++; 539854359Sroberto uval.bd[0] = *bp; 539954359Sroberto#endif /* ! WORDS_BIGENDIAN */ 540054359Sroberto return uval.dv; 540154359Sroberto} 540254359Sroberto 540354359Srobertostatic int 540454359Srobertogetshort( 540554359Sroberto unsigned char *p 540654359Sroberto ) 540754359Sroberto{ 5408290000Sglebius return (int) get_msb_short(&p); 540954359Sroberto} 541054359Sroberto 541154359Sroberto/*-------------------------------------------------- 541254359Sroberto * trimbletsip_message - process trimble messages 541354359Sroberto */ 541454359Sroberto#define RTOD (180.0 / 3.1415926535898) 541554359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 541654359Sroberto 541754359Srobertostatic void 541854359Srobertotrimbletsip_message( 541954359Sroberto struct parseunit *parse, 542054359Sroberto parsetime_t *parsetime 542154359Sroberto ) 542254359Sroberto{ 542354359Sroberto unsigned char *buffer = parsetime->parse_msg; 542454359Sroberto unsigned int size = parsetime->parse_msglen; 5425290000Sglebius 542654359Sroberto if ((size < 4) || 542754359Sroberto (buffer[0] != DLE) || 542854359Sroberto (buffer[size-1] != ETX) || 542954359Sroberto (buffer[size-2] != DLE)) 543054359Sroberto { 543154359Sroberto#ifdef DEBUG 543254359Sroberto if (debug > 2) { 5433290000Sglebius size_t i; 543454359Sroberto 543554359Sroberto printf("TRIMBLE BAD packet, size %d:\n ", size); 543654359Sroberto for (i = 0; i < size; i++) { 543754359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 543854359Sroberto if (i%16 == 15) printf("\n\t"); 543954359Sroberto } 544054359Sroberto printf("\n"); 544154359Sroberto } 544254359Sroberto#endif 544354359Sroberto return; 544454359Sroberto } 544554359Sroberto else 544654359Sroberto { 5447290000Sglebius u_short var_flag; 544854359Sroberto trimble_t *tr = parse->localdata; 544954359Sroberto unsigned int cmd = buffer[1]; 545054359Sroberto char pbuffer[200]; 545154359Sroberto char *t = pbuffer; 545254359Sroberto cmd_info_t *s; 5453290000Sglebius 545454359Sroberto#ifdef DEBUG 545554359Sroberto if (debug > 3) { 5456290000Sglebius size_t i; 545754359Sroberto 545854359Sroberto printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 545954359Sroberto for (i = 0; i < size; i++) { 546054359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 546154359Sroberto if (i%16 == 15) printf("\n\t"); 546254359Sroberto } 546354359Sroberto printf("\n"); 546454359Sroberto } 546554359Sroberto#endif 546654359Sroberto 546754359Sroberto if (tr) 546854359Sroberto tr->last_msg = current_time; 5469290000Sglebius 547054359Sroberto s = trimble_convert(cmd, trimble_rcmds); 5471290000Sglebius 547254359Sroberto if (s) 547354359Sroberto { 5474290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname); 547554359Sroberto } 547654359Sroberto else 547754359Sroberto { 5478182007Sroberto DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 547954359Sroberto return; 548054359Sroberto } 548154359Sroberto 5482290000Sglebius var_flag = (u_short) s->varmode; 548354359Sroberto 548454359Sroberto switch(cmd) 548554359Sroberto { 548654359Sroberto case CMD_RCURTIME: 5487290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f", 5488182007Sroberto getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5489182007Sroberto getflt((unsigned char *)&mb(6))); 549054359Sroberto break; 5491290000Sglebius 549254359Sroberto case CMD_RBEST4: 5493290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 549454359Sroberto switch (mb(0) & 0xF) 549554359Sroberto { 549654359Sroberto default: 5497290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, 5498290000Sglebius "0x%x", mb(0) & 0x7); 549954359Sroberto break; 550054359Sroberto 550154359Sroberto case 1: 5502290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "0D"); 550354359Sroberto break; 5504290000Sglebius 550554359Sroberto case 3: 5506290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 550754359Sroberto break; 5508290000Sglebius 550954359Sroberto case 4: 5510290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 551154359Sroberto break; 551254359Sroberto } 551354359Sroberto if (mb(0) & 0x10) 5514290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 551554359Sroberto else 5516290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5517290000Sglebius 5518290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 551954359Sroberto mb(1), mb(2), mb(3), mb(4), 552054359Sroberto getflt((unsigned char *)&mb(5)), 552154359Sroberto getflt((unsigned char *)&mb(9)), 552254359Sroberto getflt((unsigned char *)&mb(13)), 552354359Sroberto getflt((unsigned char *)&mb(17))); 552454359Sroberto 552554359Sroberto break; 5526290000Sglebius 552754359Sroberto case CMD_RVERSION: 5528290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)", 552954359Sroberto mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 553054359Sroberto break; 5531290000Sglebius 553254359Sroberto case CMD_RRECVHEALTH: 553354359Sroberto { 553454359Sroberto static const char *msgs[] = 553554359Sroberto { 553654359Sroberto "Battery backup failed", 553754359Sroberto "Signal processor error", 553854359Sroberto "Alignment error, channel or chip 1", 553954359Sroberto "Alignment error, channel or chip 2", 554054359Sroberto "Antenna feed line fault", 554154359Sroberto "Excessive ref freq. error", 554254359Sroberto "<BIT 6>", 554354359Sroberto "<BIT 7>" 554454359Sroberto }; 5545290000Sglebius 554654359Sroberto int i, bits; 5547290000Sglebius 554854359Sroberto switch (mb(0) & 0xFF) 554954359Sroberto { 555054359Sroberto default: 5551290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF); 555254359Sroberto break; 555354359Sroberto case 0x00: 5554290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes"); 555554359Sroberto break; 555654359Sroberto case 0x01: 5557290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet"); 555854359Sroberto break; 555954359Sroberto case 0x03: 5560290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high"); 556154359Sroberto break; 556254359Sroberto case 0x08: 5563290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites"); 556454359Sroberto break; 556554359Sroberto case 0x09: 5566290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite"); 556754359Sroberto break; 556854359Sroberto case 0x0A: 5569290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites"); 557054359Sroberto break; 557154359Sroberto case 0x0B: 5572290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites"); 557354359Sroberto break; 557454359Sroberto case 0x0C: 5575290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable"); 557654359Sroberto break; 557754359Sroberto } 557854359Sroberto 5579290000Sglebius bits = mb(1) & 0xFF; 558054359Sroberto 558154359Sroberto for (i = 0; i < 8; i++) 558254359Sroberto if (bits & (0x1<<i)) 558354359Sroberto { 5584290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 558554359Sroberto } 558654359Sroberto } 558754359Sroberto break; 5588290000Sglebius 558954359Sroberto case CMD_RMESSAGE: 5590182007Sroberto mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 559154359Sroberto break; 5592290000Sglebius 559354359Sroberto case CMD_RMACHSTAT: 559454359Sroberto { 559554359Sroberto static const char *msgs[] = 559654359Sroberto { 559754359Sroberto "Synthesizer Fault", 559854359Sroberto "Battery Powered Time Clock Fault", 559954359Sroberto "A-to-D Converter Fault", 560054359Sroberto "The almanac stored in the receiver is not complete and current", 560154359Sroberto "<BIT 4>", 560254359Sroberto "<BIT 5", 560354359Sroberto "<BIT 6>", 560454359Sroberto "<BIT 7>" 560554359Sroberto }; 5606290000Sglebius 560754359Sroberto int i, bits; 560854359Sroberto 5609290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF); 561054359Sroberto bits = mb(1) & 0xFF; 5611290000Sglebius 561254359Sroberto for (i = 0; i < 8; i++) 561354359Sroberto if (bits & (0x1<<i)) 561454359Sroberto { 5615290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 561654359Sroberto } 561754359Sroberto 5618290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 561954359Sroberto } 562054359Sroberto break; 5621290000Sglebius 562254359Sroberto case CMD_ROPERPARAM: 5623290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f", 562454359Sroberto mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 562554359Sroberto getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 562654359Sroberto break; 5627290000Sglebius 562854359Sroberto case CMD_RUTCPARAM: 562954359Sroberto { 563054359Sroberto float t0t = getflt((unsigned char *)&mb(14)); 5631290000Sglebius short wnt = (short) getshort((unsigned char *)&mb(18)); 5632290000Sglebius short dtls = (short) getshort((unsigned char *)&mb(12)); 5633290000Sglebius short wnlsf = (short) getshort((unsigned char *)&mb(20)); 5634290000Sglebius short dn = (short) getshort((unsigned char *)&mb(22)); 5635290000Sglebius short dtlsf = (short) getshort((unsigned char *)&mb(24)); 563654359Sroberto 563754359Sroberto if ((int)t0t != 0) 5638290000Sglebius { 5639290000Sglebius mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 5640290000Sglebius } 564154359Sroberto else 5642290000Sglebius { 5643290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>"); 5644290000Sglebius } 564554359Sroberto } 564654359Sroberto break; 564754359Sroberto 564854359Sroberto case CMD_RSAT1BIAS: 5649290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs", 565054359Sroberto getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 565154359Sroberto break; 565254359Sroberto 565354359Sroberto case CMD_RIOOPTIONS: 565454359Sroberto { 5655290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x", 565654359Sroberto mb(0), mb(1), mb(2), mb(3)); 565754359Sroberto if (mb(0) != TRIM_POS_OPT || 565854359Sroberto mb(2) != TRIM_TIME_OPT) 565954359Sroberto { 566054359Sroberto (void)trimbletsip_setup(parse, "bad io options"); 566154359Sroberto } 566254359Sroberto } 566354359Sroberto break; 5664290000Sglebius 566554359Sroberto case CMD_RSPOSXYZ: 566654359Sroberto { 566754359Sroberto double x = getflt((unsigned char *)&mb(0)); 566854359Sroberto double y = getflt((unsigned char *)&mb(4)); 566954359Sroberto double z = getflt((unsigned char *)&mb(8)); 567054359Sroberto double f = getflt((unsigned char *)&mb(12)); 5671290000Sglebius 567254359Sroberto if (f > 0.0) 5673290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 567454359Sroberto x, y, z, 567554359Sroberto f); 567654359Sroberto else 5677290000Sglebius return; 567854359Sroberto } 567954359Sroberto break; 568054359Sroberto 568154359Sroberto case CMD_RSLLAPOS: 568254359Sroberto { 568354359Sroberto double lat = getflt((unsigned char *)&mb(0)); 568454359Sroberto double lng = getflt((unsigned char *)&mb(4)); 568554359Sroberto double f = getflt((unsigned char *)&mb(12)); 5686290000Sglebius 568754359Sroberto if (f > 0.0) 5688290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm", 568954359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 569054359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 569154359Sroberto getflt((unsigned char *)&mb(8))); 569254359Sroberto else 5693290000Sglebius return; 569454359Sroberto } 569554359Sroberto break; 569654359Sroberto 569754359Sroberto case CMD_RDOUBLEXYZ: 569854359Sroberto { 569954359Sroberto double x = getdbl((unsigned char *)&mb(0)); 570054359Sroberto double y = getdbl((unsigned char *)&mb(8)); 570154359Sroberto double z = getdbl((unsigned char *)&mb(16)); 5702290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm", 570354359Sroberto x, y, z); 570454359Sroberto } 570554359Sroberto break; 5706290000Sglebius 570754359Sroberto case CMD_RDOUBLELLA: 570854359Sroberto { 570954359Sroberto double lat = getdbl((unsigned char *)&mb(0)); 571054359Sroberto double lng = getdbl((unsigned char *)&mb(8)); 5711290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm", 571254359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 571354359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 571454359Sroberto getdbl((unsigned char *)&mb(16))); 571554359Sroberto } 571654359Sroberto break; 571754359Sroberto 571854359Sroberto case CMD_RALLINVIEW: 571954359Sroberto { 572054359Sroberto int i, sats; 5721290000Sglebius 5722290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 572354359Sroberto switch (mb(0) & 0x7) 572454359Sroberto { 572554359Sroberto default: 5726290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7); 572754359Sroberto break; 572854359Sroberto 572954359Sroberto case 3: 5730290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 573154359Sroberto break; 5732290000Sglebius 573354359Sroberto case 4: 5734290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 573554359Sroberto break; 573654359Sroberto } 573754359Sroberto if (mb(0) & 0x8) 5738290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 573954359Sroberto else 5740290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5741290000Sglebius 574254359Sroberto sats = (mb(0)>>4) & 0xF; 5743290000Sglebius 5744290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 574554359Sroberto getflt((unsigned char *)&mb(1)), 574654359Sroberto getflt((unsigned char *)&mb(5)), 574754359Sroberto getflt((unsigned char *)&mb(9)), 574854359Sroberto getflt((unsigned char *)&mb(13)), 574954359Sroberto sats, (sats == 1) ? "" : "s"); 575054359Sroberto 575154359Sroberto for (i=0; i < sats; i++) 575254359Sroberto { 5753290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i)); 575454359Sroberto if (tr) 575554359Sroberto tr->ctrack |= (1 << (mb(17+i)-1)); 575654359Sroberto } 575754359Sroberto 575854359Sroberto if (tr) 5759290000Sglebius { /* mark for tracking status query */ 576054359Sroberto tr->qtracking = 1; 576154359Sroberto } 576254359Sroberto } 576354359Sroberto break; 5764290000Sglebius 576554359Sroberto case CMD_RSTATTRACK: 576654359Sroberto { 5767290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */ 576854359Sroberto if (getflt((unsigned char *)&mb(4)) < 0.0) 576954359Sroberto { 5770290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>"); 5771290000Sglebius var_flag &= (u_short)(~DEF); 577254359Sroberto } 577354359Sroberto else 5774290000Sglebius { 5775290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 577654359Sroberto (mb(1) & 0xFF)>>3, 577754359Sroberto mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 577854359Sroberto mb(3), 577954359Sroberto getflt((unsigned char *)&mb(4)), 578054359Sroberto getflt((unsigned char *)&mb(12)) * RTOD, 578154359Sroberto getflt((unsigned char *)&mb(16)) * RTOD); 578254359Sroberto if (mb(20)) 578354359Sroberto { 5784290000Sglebius var_flag &= (u_short)(~DEF); 5785290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, ", OLD"); 578654359Sroberto } 578754359Sroberto if (mb(22)) 578854359Sroberto { 578954359Sroberto if (mb(22) == 1) 5790290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY"); 579154359Sroberto else 579254359Sroberto if (mb(22) == 2) 5793290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH"); 579454359Sroberto } 579554359Sroberto if (mb(23)) 5796290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data"); 579754359Sroberto } 579854359Sroberto } 579954359Sroberto break; 5800290000Sglebius 580154359Sroberto default: 5802290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>"); 580354359Sroberto break; 580454359Sroberto } 5805182007Sroberto 5806290000Sglebius t = ap(pbuffer, sizeof(pbuffer), t, "\""); 580754359Sroberto set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 580854359Sroberto } 580954359Sroberto} 581054359Sroberto 5811290000Sglebius 581254359Sroberto/**============================================================ 581354359Sroberto ** RAWDCF support 581454359Sroberto **/ 581554359Sroberto 581654359Sroberto/*-------------------------------------------------- 581756746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers 581856746Sroberto * SET DTR line 581954359Sroberto */ 582054359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 582154359Srobertostatic int 582256746Srobertorawdcf_init_1( 582354359Sroberto struct parseunit *parse 582454359Sroberto ) 582554359Sroberto{ 582682498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 582754359Sroberto /* 582854359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 582954359Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 583054359Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 583154359Sroberto */ 583282498Sroberto int sl232; 583382498Sroberto 583482498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 583582498Sroberto { 583682498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 583782498Sroberto return 0; 583882498Sroberto } 583982498Sroberto 584054359Sroberto#ifdef TIOCM_DTR 584182498Sroberto sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 584254359Sroberto#else 584382498Sroberto sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 584454359Sroberto#endif 584554359Sroberto 584654359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 584754359Sroberto { 584856746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 584954359Sroberto } 585054359Sroberto return 0; 585154359Sroberto} 585254359Sroberto#else 585354359Srobertostatic int 5854132451Srobertorawdcfdtr_init_1( 585554359Sroberto struct parseunit *parse 585654359Sroberto ) 585754359Sroberto{ 585856746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 585954359Sroberto return 0; 586054359Sroberto} 586154359Sroberto#endif /* DTR initialisation type */ 586254359Sroberto 586354359Sroberto/*-------------------------------------------------- 586456746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers 586556746Sroberto * CLR DTR line, SET RTS line 586654359Sroberto */ 586756746Sroberto#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 586854359Srobertostatic int 586956746Srobertorawdcf_init_2( 587054359Sroberto struct parseunit *parse 587154359Sroberto ) 587254359Sroberto{ 587382498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 587454359Sroberto /* 587554359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 587656746Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 587756746Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 587854359Sroberto */ 587982498Sroberto int sl232; 588082498Sroberto 588182498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 588282498Sroberto { 588382498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 588482498Sroberto return 0; 588582498Sroberto } 588682498Sroberto 588754359Sroberto#ifdef TIOCM_RTS 588882498Sroberto sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 588954359Sroberto#else 589082498Sroberto sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 589154359Sroberto#endif 589254359Sroberto 589354359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 589454359Sroberto { 589556746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 589654359Sroberto } 589754359Sroberto return 0; 589854359Sroberto} 589954359Sroberto#else 590054359Srobertostatic int 590156746Srobertorawdcf_init_2( 590254359Sroberto struct parseunit *parse 590354359Sroberto ) 590454359Sroberto{ 590556746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 590654359Sroberto return 0; 590754359Sroberto} 590856746Sroberto#endif /* DTR initialisation type */ 590954359Sroberto 591054359Sroberto#else /* defined(REFCLOCK) && defined(PARSE) */ 5911290000SglebiusNONEMPTY_TRANSLATION_UNIT 591254359Sroberto#endif /* defined(REFCLOCK) && defined(PARSE) */ 591354359Sroberto 591454359Sroberto/* 591554359Sroberto * History: 591654359Sroberto * 591754359Sroberto * refclock_parse.c,v 5918290000Sglebius * Revision 4.81 2009/05/01 10:15:29 kardel 5919290000Sglebius * use new refclock_ppsapi interface 5920290000Sglebius * 5921182007Sroberto * Revision 4.80 2007/08/11 12:06:29 kardel 5922182007Sroberto * update comments wrt/ to PPS 5923182007Sroberto * 5924182007Sroberto * Revision 4.79 2007/08/11 11:52:23 kardel 5925182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor 5926182007Sroberto * 5927182007Sroberto * Revision 4.78 2006/12/22 20:08:27 kardel 5928182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5929182007Sroberto * 5930182007Sroberto * Revision 4.77 2006/08/05 07:44:49 kardel 5931182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5932182007Sroberto * 5933182007Sroberto * Revision 4.76 2006/06/22 18:40:47 kardel 5934182007Sroberto * clean up signedness (gcc 4) 5935182007Sroberto * 5936182007Sroberto * Revision 4.75 2006/06/22 16:58:10 kardel 5937182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5938182007Sroberto * the PPS offset. Fix sign of offset passed to kernel. 5939182007Sroberto * 5940182007Sroberto * Revision 4.74 2006/06/18 21:18:37 kardel 5941182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref 5942182007Sroberto * 5943182007Sroberto * Revision 4.73 2006/05/26 14:23:46 kardel 5944182007Sroberto * cleanup of copyright info 5945182007Sroberto * 5946182007Sroberto * Revision 4.72 2006/05/26 14:19:43 kardel 5947182007Sroberto * cleanup of ioctl cruft 5948182007Sroberto * 5949182007Sroberto * Revision 4.71 2006/05/26 14:15:57 kardel 5950182007Sroberto * delay adding refclock to async refclock io after all initializations 5951182007Sroberto * 5952182007Sroberto * Revision 4.70 2006/05/25 18:20:50 kardel 5953182007Sroberto * bug #619 5954182007Sroberto * terminate parse io engine after de-registering 5955182007Sroberto * from refclock io engine 5956182007Sroberto * 5957182007Sroberto * Revision 4.69 2006/05/25 17:28:02 kardel 5958182007Sroberto * complete refclock io structure initialization *before* inserting it into the 5959182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619) 5960182007Sroberto * 5961182007Sroberto * Revision 4.68 2006/05/01 17:02:51 kardel 5962182007Sroberto * copy receiver method also for newlwy created receive buffers 5963182007Sroberto * 5964182007Sroberto * Revision 4.67 2006/05/01 14:37:29 kardel 5965182007Sroberto * If an input buffer parses into more than one message do insert the 5966182007Sroberto * parsed message in a new input buffer instead of processing it 5967182007Sroberto * directly. This avoids deed complicated processing in signal 5968182007Sroberto * handling. 5969182007Sroberto * 5970182007Sroberto * Revision 4.66 2006/03/18 00:45:30 kardel 5971182007Sroberto * coverity fixes found in NetBSD coverity scan 5972182007Sroberto * 5973182007Sroberto * Revision 4.65 2006/01/26 06:08:33 kardel 5974182007Sroberto * output errno on PPS setup failure 5975182007Sroberto * 5976182007Sroberto * Revision 4.64 2005/11/09 20:44:47 kardel 5977182007Sroberto * utilize full PPS timestamp resolution from PPS API 5978182007Sroberto * 5979182007Sroberto * Revision 4.63 2005/10/07 22:10:25 kardel 5980182007Sroberto * bounded buffer implementation 5981182007Sroberto * 5982182007Sroberto * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 5983182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 5984182007Sroberto * replace almost all str* and *printf functions be their buffer bounded 5985182007Sroberto * counterparts 5986182007Sroberto * 5987182007Sroberto * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 5988182007Sroberto * limit re-set rate of trimble clocks 5989182007Sroberto * 5990182007Sroberto * Revision 4.62 2005/08/06 17:40:00 kardel 5991182007Sroberto * cleanup size handling wrt/ to buffer boundaries 5992182007Sroberto * 5993182007Sroberto * Revision 4.61 2005/07/27 21:16:19 kardel 5994182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 5995182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of 5996182007Sroberto * the DCF77 clocks. 5997182007Sroberto * 5998182007Sroberto * Revision 4.60 2005/07/17 21:14:44 kardel 5999182007Sroberto * change contents of version string to include the RCS/CVS Id 6000182007Sroberto * 6001182007Sroberto * Revision 4.59 2005/07/06 06:56:38 kardel 6002182007Sroberto * syntax error 6003182007Sroberto * 6004182007Sroberto * Revision 4.58 2005/07/04 13:10:40 kardel 6005182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup 6006182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 6007182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and 6008182007Sroberto * varying structure element sizes 6009182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers 6010182007Sroberto * 6011182007Sroberto * Revision 4.57 2005/06/25 09:25:19 kardel 6012182007Sroberto * sort out log output sequence 6013182007Sroberto * 6014182007Sroberto * Revision 4.56 2005/06/14 21:47:27 kardel 6015182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel) 6016182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 6017182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state 6018182007Sroberto * 6019182007Sroberto * Revision 4.55 2005/06/02 21:28:31 kardel 6020182007Sroberto * clarify trust logic 6021182007Sroberto * 6022182007Sroberto * Revision 4.54 2005/06/02 17:06:49 kardel 6023182007Sroberto * change status reporting to use fixed refclock_report() 6024182007Sroberto * 6025182007Sroberto * Revision 4.53 2005/06/02 16:33:31 kardel 6026182007Sroberto * fix acceptance of clocks unsync clocks right at start 6027182007Sroberto * 6028182007Sroberto * Revision 4.52 2005/05/26 21:55:06 kardel 6029182007Sroberto * cleanup status reporting 6030182007Sroberto * 6031182007Sroberto * Revision 4.51 2005/05/26 19:19:14 kardel 6032182007Sroberto * implement fast refclock startup 6033182007Sroberto * 6034182007Sroberto * Revision 4.50 2005/04/16 20:51:35 kardel 6035290000Sglebius * set hardpps_enable = 1 when binding a kernel PPS source 6036182007Sroberto * 6037182007Sroberto * Revision 4.49 2005/04/16 17:29:26 kardel 6038182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks 6039182007Sroberto * 6040182007Sroberto * Revision 4.48 2005/04/16 16:22:27 kardel 6041182007Sroberto * bk sync 20050415 ntp-dev 6042182007Sroberto * 6043182007Sroberto * Revision 4.47 2004/11/29 10:42:48 kardel 6044182007Sroberto * bk sync ntp-dev 20041129 6045182007Sroberto * 6046182007Sroberto * Revision 4.46 2004/11/29 10:26:29 kardel 6047182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 6048182007Sroberto * 6049182007Sroberto * Revision 4.45 2004/11/14 20:53:20 kardel 6050182007Sroberto * clear PPS flags after using them 6051182007Sroberto * 6052182007Sroberto * Revision 4.44 2004/11/14 15:29:41 kardel 6053182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style 6054182007Sroberto * 6055182007Sroberto * Revision 4.43 2001/05/26 22:53:16 kardel 6056182007Sroberto * 20010526 reconcilation 6057182007Sroberto * 6058182007Sroberto * Revision 4.42 2000/05/14 15:31:51 kardel 6059182007Sroberto * PPSAPI && RAWDCF modemline support 6060182007Sroberto * 6061182007Sroberto * Revision 4.41 2000/04/09 19:50:45 kardel 6062182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1 6063182007Sroberto * 6064182007Sroberto * Revision 4.40 2000/04/09 15:27:55 kardel 6065182007Sroberto * modem line fiddle in rawdcf_init_2 6066182007Sroberto * 6067182007Sroberto * Revision 4.39 2000/03/18 09:16:55 kardel 6068182007Sroberto * PPSAPI integration 6069182007Sroberto * 6070182007Sroberto * Revision 4.38 2000/03/05 20:25:06 kardel 6071182007Sroberto * support PPSAPI 6072182007Sroberto * 6073182007Sroberto * Revision 4.37 2000/03/05 20:11:14 kardel 6074182007Sroberto * 4.0.99g reconcilation 6075182007Sroberto * 607656746Sroberto * Revision 4.36 1999/11/28 17:18:20 kardel 607756746Sroberto * disabled burst mode 607856746Sroberto * 607956746Sroberto * Revision 4.35 1999/11/28 09:14:14 kardel 608056746Sroberto * RECON_4_0_98F 608156746Sroberto * 608256746Sroberto * Revision 4.34 1999/05/14 06:08:05 kardel 608356746Sroberto * store current_time in a suitable container (u_long) 608456746Sroberto * 608556746Sroberto * Revision 4.33 1999/05/13 21:48:38 kardel 608656746Sroberto * double the no response timeout interval 608756746Sroberto * 608856746Sroberto * Revision 4.32 1999/05/13 20:09:13 kardel 608956746Sroberto * complain only about missing polls after a full poll interval 609056746Sroberto * 609156746Sroberto * Revision 4.31 1999/05/13 19:59:32 kardel 609256746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF 609356746Sroberto * 609456746Sroberto * Revision 4.30 1999/02/28 20:36:43 kardel 609556746Sroberto * fixed printf fmt 609656746Sroberto * 609754359Sroberto * Revision 4.29 1999/02/28 19:58:23 kardel 609854359Sroberto * updated copyright information 609954359Sroberto * 610054359Sroberto * Revision 4.28 1999/02/28 19:01:50 kardel 610154359Sroberto * improved debug out on sent Meinberg messages 610254359Sroberto * 610354359Sroberto * Revision 4.27 1999/02/28 18:05:55 kardel 610454359Sroberto * no linux/ppsclock.h stuff 610554359Sroberto * 610654359Sroberto * Revision 4.26 1999/02/28 15:27:27 kardel 610754359Sroberto * wharton clock integration 610854359Sroberto * 610954359Sroberto * Revision 4.25 1999/02/28 14:04:46 kardel 611054359Sroberto * added missing double quotes to UTC information string 611154359Sroberto * 611254359Sroberto * Revision 4.24 1999/02/28 12:06:50 kardel 611354359Sroberto * (parse_control): using gmprettydate instead of prettydate() 611454359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information 611554359Sroberto * (gps16x_message): changed to use mk_utcinfo() 611654359Sroberto * (trimbletsip_message): changed to use mk_utcinfo() 611754359Sroberto * ignoring position information in unsynchronized mode 611854359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 611954359Sroberto * 612054359Sroberto * Revision 4.23 1999/02/23 19:47:53 kardel 612154359Sroberto * fixed #endifs 612254359Sroberto * (stream_receive): fixed formats 612354359Sroberto * 612454359Sroberto * Revision 4.22 1999/02/22 06:21:02 kardel 612554359Sroberto * use new autoconfig symbols 612654359Sroberto * 612754359Sroberto * Revision 4.21 1999/02/21 12:18:13 kardel 612854359Sroberto * 4.91f reconcilation 612954359Sroberto * 613054359Sroberto * Revision 4.20 1999/02/21 10:53:36 kardel 613154359Sroberto * initial Linux PPSkit version 613254359Sroberto * 613354359Sroberto * Revision 4.19 1999/02/07 09:10:45 kardel 613454359Sroberto * clarify STREAMS mitigation rules in comment 613554359Sroberto * 613654359Sroberto * Revision 4.18 1998/12/20 23:45:34 kardel 613754359Sroberto * fix types and warnings 613854359Sroberto * 613954359Sroberto * Revision 4.17 1998/11/15 21:24:51 kardel 614054359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG 614154359Sroberto * is not defined 614254359Sroberto * 614354359Sroberto * Revision 4.16 1998/11/15 20:28:17 kardel 614454359Sroberto * Release 4.0.73e13 reconcilation 614554359Sroberto * 614654359Sroberto * Revision 4.15 1998/08/22 21:56:08 kardel 614754359Sroberto * fixed IO handling for non-STREAM IO 614854359Sroberto * 614954359Sroberto * Revision 4.14 1998/08/16 19:00:48 kardel 615054359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 615154359Sroberto * made uval a local variable (killed one of the last globals) 615254359Sroberto * (sendetx): added logging of messages when in debug mode 615354359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization 615454359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation 615554359Sroberto * (trimbletsip_message): extended message interpretation 615654359Sroberto * (getdbl): fixed data conversion 615754359Sroberto * 615854359Sroberto * Revision 4.13 1998/08/09 22:29:13 kardel 615954359Sroberto * Trimble TSIP support 616054359Sroberto * 616154359Sroberto * Revision 4.12 1998/07/11 10:05:34 kardel 616254359Sroberto * Release 4.0.73d reconcilation 616354359Sroberto * 616454359Sroberto * Revision 4.11 1998/06/14 21:09:42 kardel 616554359Sroberto * Sun acc cleanup 616654359Sroberto * 616754359Sroberto * Revision 4.10 1998/06/13 12:36:45 kardel 616854359Sroberto * signed/unsigned, name clashes 616954359Sroberto * 617054359Sroberto * Revision 4.9 1998/06/12 15:30:00 kardel 617154359Sroberto * prototype fixes 617254359Sroberto * 617354359Sroberto * Revision 4.8 1998/06/12 11:19:42 kardel 617454359Sroberto * added direct input processing routine for refclocks in 617554359Sroberto * order to avaiod that single character io gobbles up all 617654359Sroberto * receive buffers and drops input data. (Problem started 617754359Sroberto * with fast machines so a character a buffer was possible 617854359Sroberto * one of the few cases where faster machines break existing 617954359Sroberto * allocation algorithms) 618054359Sroberto * 618154359Sroberto * Revision 4.7 1998/06/06 18:35:20 kardel 618254359Sroberto * (parse_start): added BURST mode initialisation 618354359Sroberto * 618454359Sroberto * Revision 4.6 1998/05/27 06:12:46 kardel 618554359Sroberto * RAWDCF_BASEDELAY default added 618654359Sroberto * old comment removed 618754359Sroberto * casts for ioctl() 618854359Sroberto * 618954359Sroberto * Revision 4.5 1998/05/25 22:05:09 kardel 619054359Sroberto * RAWDCF_SETDTR option removed 619154359Sroberto * clock type 14 attempts to set DTR for 619254359Sroberto * power supply of RAWDCF receivers 619354359Sroberto * 619454359Sroberto * Revision 4.4 1998/05/24 16:20:47 kardel 619554359Sroberto * updated comments referencing Meinberg clocks 619654359Sroberto * added RAWDCF clock with DTR set option as type 14 619754359Sroberto * 619854359Sroberto * Revision 4.3 1998/05/24 10:48:33 kardel 619954359Sroberto * calibrated CONRAD RAWDCF default fudge factor 620054359Sroberto * 620154359Sroberto * Revision 4.2 1998/05/24 09:59:35 kardel 620254359Sroberto * corrected version information (ntpq support) 620354359Sroberto * 620454359Sroberto * Revision 4.1 1998/05/24 09:52:31 kardel 620554359Sroberto * use fixed format only (new IO model) 620654359Sroberto * output debug to stdout instead of msyslog() 620754359Sroberto * don't include >"< in ASCII output in order not to confuse 620854359Sroberto * ntpq parsing 620954359Sroberto * 621054359Sroberto * Revision 4.0 1998/04/10 19:52:11 kardel 621154359Sroberto * Start 4.0 release version numbering 621254359Sroberto * 621354359Sroberto * Revision 1.2 1998/04/10 19:28:04 kardel 621454359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 621554359Sroberto * derived from 3.105.1.2 from V3 tree 621654359Sroberto * 621754359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 621854359Sroberto * 621954359Sroberto */ 6220