154359Sroberto/* 2280849Scy * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 354359Sroberto * 4280849Scy * 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 * 18285169Scy * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org> 19280849Scy * 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 51280849Scy#include "ntp_types.h" 52280849Scy 5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) 5454359Sroberto 5554359Sroberto/* 5654359Sroberto * This driver currently provides the support for 57282408Scy * - Meinberg receiver DCF77 PZF535 (TCXO version) (DCF) 58282408Scy * - Meinberg receiver DCF77 PZF535 (OCXO version) (DCF) 59282408Scy * - 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) 66282408Scy * - WHARTON 400A Series clock (DCF) 6754359Sroberto * 68282408Scy * - Meinberg GPS receivers (GPS) 6954359Sroberto * - Trimble (TSIP and TAIP protocol) (GPS) 7054359Sroberto * 7154359Sroberto * - RCC8000 MSF Receiver (MSF) 72282408Scy * - VARITEXT clock (MSF) 7354359Sroberto */ 7454359Sroberto 7554359Sroberto/* 7654359Sroberto * Meinberg receivers are usually connected via a 77282408Scy * 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: 83282408Scy * output time code every second 84282408Scy * Baud rate 9600 7E2S 8554359Sroberto * 86282408Scy * 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 94282408Scy * oldest GPS receiver, GPS16x. For newer receiver types 95282408Scy * the output string format can be configured at the device, 96282408Scy * 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" 103280849Scy#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 127280849Scy# 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" 149280849Scy# 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 161282408Scy# define BUFFER_SIZE(_BUF, _PTR) ((int)((_BUF) + sizeof(_BUF) - (_PTR))) 162282408Scy# 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 */ 167282408Scy#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 186282408Scy/* 187282408Scy * COND_DEF can be conditionally defined as DEF or 0. If defined as DEF 188282408Scy * then some more parse-specific variables are flagged to be printed with 189282408Scy * "ntpq -c cv <assid>". This can be lengthy, so by default COND_DEF 190282408Scy * should be defined as 0. 191282408Scy */ 192282408Scy#if 0 193282408Scy# define COND_DEF DEF // enable this for testing 194282408Scy#else 195282408Scy# define COND_DEF 0 // enable this by default 196282408Scy#endif 197282408Scy 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 209280849Scystatic 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 215280849Scystatic int parse_start (int, struct peer *); 216280849Scystatic void parse_shutdown (int, struct peer *); 217280849Scystatic void parse_poll (int, struct peer *); 218280849Scystatic 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 */ 252280849Scy int (*bd_init) (struct parseunit *); /* initialize */ 253280849Scy void (*bd_end) (struct parseunit *); /* end */ 254280849Scy int (*bd_setcs) (struct parseunit *, parsectl_t *); /* set character size */ 255280849Scy int (*bd_disable) (struct parseunit *); /* disable */ 256280849Scy int (*bd_enable) (struct parseunit *); /* enable */ 257280849Scy int (*bd_getfmt) (struct parseunit *, parsectl_t *); /* get format */ 258280849Scy int (*bd_setfmt) (struct parseunit *, parsectl_t *); /* setfmt */ 259280849Scy int (*bd_timecode) (struct parseunit *, parsectl_t *); /* get time code */ 260280849Scy void (*bd_receive) (struct recvbuf *); /* receive operation */ 261280849Scy 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/* 273280849Scy * special handling flags 27454359Sroberto */ 275280849Scy#define PARSE_F_PPSONSECOND 0x00000001 /* PPS pulses are on second */ 276280849Scy#define PARSE_F_POWERUPTRUST 0x00000100 /* POWERUP state ist trusted for */ 277280849Scy /* 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 */ 399282408Scy 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 */ 426280849Scy 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 442280849Scystatic void poll_dpoll (struct parseunit *); 443280849Scystatic void poll_poll (struct peer *); 444280849Scystatic 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 467282408Scy#define NOCLOCK_ROOTDELAY 0.0 468282408Scy#define NOCLOCK_BASEDELAY 0.0 469282408Scy#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 475282408Scy#define NOCLOCK_ID "TILT" 476282408Scy#define NOCLOCK_POLL NO_POLL 477282408Scy#define NOCLOCK_INIT NO_INIT 478282408Scy#define NOCLOCK_END NO_END 479282408Scy#define NOCLOCK_DATA NO_LCLDATA 480282408Scy#define NOCLOCK_FORMAT "" 481282408Scy#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 482282408Scy#define NOCLOCK_SAMPLES 0 483282408Scy#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/* 553282408Scy * Meinberg GPS receivers 55454359Sroberto */ 555280849Scystatic void gps16x_message (struct parseunit *, parsetime_t *); 556280849Scystatic 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) */ 560282408Scy#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 */ 696280849Scystatic int rawdcf_init_1 (struct parseunit *); 69756746Sroberto#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 698280849Scy#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 */ 705280849Scystatic int rawdcf_init_2 (struct parseunit *); 70656746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 707280849Scy#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 }; 721280849Scystatic int trimbletaip_init (struct parseunit *); 722280849Scystatic 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) }; 728280849Scystatic int trimbletsip_init (struct parseunit *); 729280849Scystatic void trimbletsip_end (struct parseunit *); 730280849Scystatic void trimbletsip_message (struct parseunit *, parsetime_t *); 731280849Scystatic 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 762282408Scy#define TRIMBLETAIP_EVENT trimbletaip_event 76354359Sroberto 764282408Scy#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/* 821282408Scy * 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 876280849Scy/* 877280849Scy * SEL240x Satellite Sychronized Clock 878280849Scy */ 879280849Scy#define SEL240X_POLLRATE 0 /* only true direct polling */ 880280849Scy#define SEL240X_POLLCMD "BUB8" 881280849Scy#define SEL240X_CMDSIZE 4 882280849Scy 883280849Scystatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE, 884280849Scy SEL240X_POLLCMD, 885280849Scy SEL240X_CMDSIZE }; 886280849Scy#define SEL240X_FLAGS (PARSE_F_PPSONSECOND) 887280849Scy#define SEL240X_POLL poll_dpoll 888280849Scy#define SEL240X_INIT poll_init 889280849Scy#define SEL240X_END 0 890280849Scy#define SEL240X_DATA ((void *)(&sel240x_pollinfo)) 891280849Scy#define SEL240X_ROOTDELAY 0.0 892280849Scy#define SEL240X_BASEDELAY 0.0 893280849Scy#define SEL240X_ID GPS_ID 894280849Scy#define SEL240X_DESCRIPTION "SEL240x Satellite Synchronized Clock" 895280849Scy#define SEL240X_FORMAT "SEL B8" 896280849Scy#define SEL240X_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours */ 897280849Scy#define SEL240X_SPEED (B9600) 898280849Scy#define SEL240X_CFLAG (CS8|CREAD|CLOCAL) 899280849Scy#define SEL240X_IFLAG (IGNBRK|IGNPAR) 900280849Scy#define SEL240X_OFLAG (0) 901280849Scy#define SEL240X_LFLAG (0) 902280849Scy#define SEL240X_SAMPLES 5 903280849Scy#define SEL240X_KEEP 3 904280849Scy 90554359Srobertostatic struct parse_clockinfo 90654359Sroberto{ 907280849Scy u_long cl_flags; /* operation flags (PPS interpretation, trust handling) */ 908280849Scy void (*cl_poll) (struct parseunit *); /* active poll routine */ 909280849Scy int (*cl_init) (struct parseunit *); /* active poll init routine */ 910280849Scy void (*cl_event) (struct parseunit *, int); /* special event handling (e.g. reset clock) */ 911280849Scy void (*cl_end) (struct parseunit *); /* active poll end routine */ 912280849Scy 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, 1217282408Scy 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 }, 1401280849Scy { /* mode 20, like mode 14 but driven by 75 baud */ 1402280849Scy RAWDCF_FLAGS, 1403280849Scy NO_POLL, 1404280849Scy RAWDCFDTRSET_INIT, 1405280849Scy NO_EVENT, 1406280849Scy NO_END, 1407280849Scy NO_MESSAGE, 1408280849Scy NO_LCLDATA, 1409280849Scy RAWDCF_ROOTDELAY, 1410280849Scy RAWDCF_BASEDELAY, 1411280849Scy DCF_A_ID, 1412280849Scy RAWDCFDTRSET75_DESCRIPTION, 1413280849Scy RAWDCF_FORMAT, 1414280849Scy DCF_TYPE, 1415280849Scy RAWDCF_MAXUNSYNC, 1416280849Scy B75, 1417280849Scy RAWDCF_CFLAG, 1418280849Scy RAWDCF_IFLAG, 1419280849Scy RAWDCF_OFLAG, 1420280849Scy RAWDCF_LFLAG, 1421280849Scy RAWDCF_SAMPLES, 1422280849Scy RAWDCF_KEEP 1423280849Scy }, 1424280849Scy { /* mode 21, like mode 16 but driven by 75 baud 1425280849Scy - RAWDCF RTS set, DTR clr */ 1426280849Scy RAWDCF_FLAGS, 1427280849Scy NO_POLL, 1428280849Scy RAWDCFDTRCLRRTSSET_INIT, 1429280849Scy NO_EVENT, 1430280849Scy NO_END, 1431280849Scy NO_MESSAGE, 1432280849Scy NO_LCLDATA, 1433280849Scy RAWDCF_ROOTDELAY, 1434280849Scy RAWDCF_BASEDELAY, 1435280849Scy DCF_A_ID, 1436280849Scy RAWDCFDTRCLRRTSSET75_DESCRIPTION, 1437280849Scy RAWDCF_FORMAT, 1438280849Scy DCF_TYPE, 1439280849Scy RAWDCF_MAXUNSYNC, 1440280849Scy B75, 1441280849Scy RAWDCF_CFLAG, 1442280849Scy RAWDCF_IFLAG, 1443280849Scy RAWDCF_OFLAG, 1444280849Scy RAWDCF_LFLAG, 1445280849Scy RAWDCF_SAMPLES, 1446280849Scy RAWDCF_KEEP 1447280849Scy }, 1448280849Scy { /* mode 22 - like 2 with POWERUP trust */ 1449280849Scy MBG_FLAGS | PARSE_F_POWERUPTRUST, 1450280849Scy NO_POLL, 1451280849Scy NO_INIT, 1452280849Scy NO_EVENT, 1453280849Scy NO_END, 1454280849Scy NO_MESSAGE, 1455280849Scy NO_LCLDATA, 1456280849Scy DCFUA31_ROOTDELAY, 1457280849Scy DCFUA31_BASEDELAY, 1458280849Scy DCF_A_ID, 1459280849Scy DCFUA31_DESCRIPTION, 1460280849Scy DCFUA31_FORMAT, 1461280849Scy DCF_TYPE, 1462280849Scy DCFUA31_MAXUNSYNC, 1463280849Scy DCFUA31_SPEED, 1464280849Scy DCFUA31_CFLAG, 1465280849Scy DCFUA31_IFLAG, 1466280849Scy DCFUA31_OFLAG, 1467280849Scy DCFUA31_LFLAG, 1468280849Scy DCFUA31_SAMPLES, 1469280849Scy DCFUA31_KEEP 1470280849Scy }, 1471280849Scy { /* mode 23 - like 7 with POWERUP trust */ 1472280849Scy MBG_FLAGS | PARSE_F_POWERUPTRUST, 1473280849Scy GPS16X_POLL, 1474280849Scy GPS16X_INIT, 1475280849Scy NO_EVENT, 1476280849Scy GPS16X_END, 1477280849Scy GPS16X_MESSAGE, 1478280849Scy GPS16X_DATA, 1479280849Scy GPS16X_ROOTDELAY, 1480280849Scy GPS16X_BASEDELAY, 1481280849Scy GPS16X_ID, 1482280849Scy GPS16X_DESCRIPTION, 1483280849Scy GPS16X_FORMAT, 1484280849Scy GPS_TYPE, 1485280849Scy GPS16X_MAXUNSYNC, 1486280849Scy GPS16X_SPEED, 1487280849Scy GPS16X_CFLAG, 1488280849Scy GPS16X_IFLAG, 1489280849Scy GPS16X_OFLAG, 1490280849Scy GPS16X_LFLAG, 1491280849Scy GPS16X_SAMPLES, 1492280849Scy GPS16X_KEEP 1493280849Scy }, 1494280849Scy { /* mode 24 */ 1495280849Scy SEL240X_FLAGS, 1496280849Scy SEL240X_POLL, 1497280849Scy SEL240X_INIT, 1498280849Scy NO_EVENT, 1499280849Scy SEL240X_END, 1500280849Scy NO_MESSAGE, 1501280849Scy SEL240X_DATA, 1502280849Scy SEL240X_ROOTDELAY, 1503280849Scy SEL240X_BASEDELAY, 1504280849Scy SEL240X_ID, 1505280849Scy SEL240X_DESCRIPTION, 1506280849Scy SEL240X_FORMAT, 1507280849Scy GPS_TYPE, 1508280849Scy SEL240X_MAXUNSYNC, 1509280849Scy SEL240X_SPEED, 1510280849Scy SEL240X_CFLAG, 1511280849Scy SEL240X_IFLAG, 1512280849Scy SEL240X_OFLAG, 1513280849Scy SEL240X_LFLAG, 1514280849Scy SEL240X_SAMPLES, 1515280849Scy SEL240X_KEEP 1516280849Scy }, 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 1537280849Scystatic void parse_event (struct parseunit *, int); 1538280849Scystatic void parse_process (struct parseunit *, parsetime_t *); 1539280849Scystatic void clear_err (struct parseunit *, u_long); 1540280849Scystatic int list_err (struct parseunit *, u_long); 1541280849Scystatic 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 { 1554280849Scy 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++; 1593282408Scy 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 } 1617282408Scy 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, 1633293423Sdelphij size_t blen, 163454359Sroberto const char *src, 1635293423Sdelphij size_t srclen, 163654359Sroberto int hex 163754359Sroberto ) 163854359Sroberto{ 1639280849Scy static const char ellipsis[] = "..."; 164054359Sroberto char *b = buffer; 1641280849Scy char *endb = NULL; 164254359Sroberto 164354359Sroberto if (blen < 4) 1644280849Scy return NULL; /* don't bother with mini buffers */ 164554359Sroberto 1646280849Scy 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 " */ 1655280849Scy 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 { 1675280849Scy memcpy(buffer, "\\\\", 2); 167654359Sroberto buffer += 2; 167754359Sroberto blen -= 2; 167854359Sroberto src++; 167954359Sroberto } 168054359Sroberto else 168154359Sroberto { 1682280849Scy 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 ... */ 1689280849Scy 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 1721280849Scystatic int ppsclock_init (struct parseunit *); 1722280849Scystatic int stream_init (struct parseunit *); 1723280849Scystatic void stream_end (struct parseunit *); 1724280849Scystatic int stream_enable (struct parseunit *); 1725280849Scystatic int stream_disable (struct parseunit *); 1726280849Scystatic int stream_setcs (struct parseunit *, parsectl_t *); 1727280849Scystatic int stream_getfmt (struct parseunit *, parsectl_t *); 1728280849Scystatic int stream_setfmt (struct parseunit *, parsectl_t *); 1729280849Scystatic int stream_timecode (struct parseunit *, parsectl_t *); 1730280849Scystatic void stream_receive (struct recvbuf *); 173154359Sroberto#endif 1732282408Scy 1733280849Scystatic int local_init (struct parseunit *); 1734280849Scystatic void local_end (struct parseunit *); 1735280849Scystatic int local_nop (struct parseunit *); 1736280849Scystatic int local_setcs (struct parseunit *, parsectl_t *); 1737280849Scystatic int local_getfmt (struct parseunit *, parsectl_t *); 1738280849Scystatic int local_setfmt (struct parseunit *, parsectl_t *); 1739280849Scystatic int local_timecode (struct parseunit *, parsectl_t *); 1740280849Scystatic void local_receive (struct recvbuf *); 1741280849Scystatic int local_input (struct recvbuf *); 174254359Sroberto 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, 1788280849Scy NULL, 1789280849Scy NULL, 1790280849Scy NULL, 1791280849Scy NULL, 1792280849Scy NULL, 1793280849Scy NULL, 1794280849Scy NULL, 1795280849Scy NULL, 1796280849Scy NULL, 1797280849Scy 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"; 1813282408Scy 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; 1902282408Scy 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; 1925282408Scy 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; 1949282408Scy 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; 1974282408Scy 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; 1997282408Scy 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; 2022282408Scy 202354359Sroberto strioc.ic_cmd = PARSEIOC_TIMECODE; 202454359Sroberto strioc.ic_timout = 0; 202554359Sroberto strioc.ic_dp = (char *)tcl; 202654359Sroberto strioc.ic_len = sizeof (*tcl); 2027282408Scy 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{ 2046280849Scy struct parseunit * parse; 204754359Sroberto parsetime_t parsetime; 204854359Sroberto 2049280849Scy 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); 2062282408Scy 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 2088280849Scy parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv); 208954359Sroberto 209054359Sroberto if (PARSE_TIMECODE(parsetime.parse_state)) 209154359Sroberto { 2092280849Scy parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv); 209354359Sroberto } 209454359Sroberto 209554359Sroberto if (PARSE_PPS(parsetime.parse_state)) 2096280849Scy { 2097280849Scy parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv); 2098280849Scy } 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{ 2195280849Scy struct parseunit * parse; 2196280849Scy 219754359Sroberto int count; 219854359Sroberto unsigned char *s; 219954359Sroberto timestamp_t ts; 220054359Sroberto 2201280849Scy 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; 2228282408Scy 2229182007Sroberto pps_timeout.tv_sec = 0; 2230182007Sroberto pps_timeout.tv_nsec = 0; 2231182007Sroberto 2232280849Scy 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 2249282408Scy parse->parseio.parse_dtime.parse_ptime.fp.l_ui = (uint32_t) (pts.tv_sec + JAN_1970); 2250182007Sroberto 2251282408Scy 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 } 2260282408Scy parse->parseio.parse_dtime.parse_ptime.fp.l_uf = (uint32_t)(dtemp * FRAC); 2261182007Sroberto 2262282408Scy parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2263182007Sroberto#ifdef DEBUG 2264182007Sroberto if (debug > 3) 2265182007Sroberto { 2266182007Sroberto printf( 2267301247Sdelphij "parse: local_receive: fd %ld PPSAPI seq %ld - PPS %s\n", 2268301247Sdelphij (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( 2280301247Sdelphij "parse: local_receive: fd %ld PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2281301247Sdelphij (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( 2294301247Sdelphij "parse: local_receive: fd %ld PPSAPI time_pps_fetch errno = %d\n", 2295301247Sdelphij (long)rbufp->fd, 2296182007Sroberto errno); 2297182007Sroberto } 2298182007Sroberto } 2299182007Sroberto#endif 2300182007Sroberto } 2301182007Sroberto#else 230254359Sroberto#ifdef TIOCDCDTIMESTAMP 230354359Sroberto struct timeval dcd_time; 2304282408Scy 2305182007Sroberto if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 230654359Sroberto { 230754359Sroberto l_fp tstmp; 2308282408Scy 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 */ 2369362716Scy buf = get_free_recv_buffer(TRUE); 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; 2376280849Scy#ifndef HAVE_IO_COMPLETION_PORT 2377182007Sroberto buf->srcadr = rbufp->srcadr; 2378280849Scy#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; 2383280849Scy parse->generic->io.recvcount++; 2384280849Scy packets_received++; 2385182007Sroberto add_full_recv_buffer(buf); 2386280849Scy#ifdef HAVE_IO_COMPLETION_PORT 2387280849Scy SetEvent(WaitableIoEventHandle); 2388280849Scy#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{ 2414280849Scy struct parseunit * parse; 241554359Sroberto parsetime_t parsetime; 241654359Sroberto 2417280849Scy 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); 2430282408Scy 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 2479280849Scystatic NTP_PRINTF(4, 5) char * 2480280849Scyap(char *buffer, size_t len, char *pos, const char *fmt, ...) 2481280849Scy{ 2482280849Scy va_list va; 2483280849Scy int l; 2484280849Scy size_t rem = len - (pos - buffer); 2485280849Scy 2486280849Scy if (rem == 0) 2487280849Scy return pos; 2488280849Scy 2489280849Scy va_start(va, fmt); 2490280849Scy l = vsnprintf(pos, rem, fmt, va); 2491280849Scy va_end(va); 2492280849Scy 2493280849Scy if (l != -1) { 2494280849Scy rem--; 2495280849Scy if (rem >= (size_t)l) 2496280849Scy pos += l; 2497280849Scy else 2498280849Scy pos += rem; 2499280849Scy } 2500280849Scy 2501280849Scy return pos; 2502280849Scy} 2503280849Scy 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" }, 2528282408Scy { PARSEB_CALLBIT, "CALL BIT" }, 252956746Sroberto { PARSEB_TIMECODE, "TIME CODE" }, 253056746Sroberto { PARSEB_PPS, "PPS" }, 253156746Sroberto { PARSEB_POSITION, "POSITION" }, 2532280849Scy { 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" }, 2543285169Scy { PARSEB_S_CALLBIT, "CALLBIT" }, 254454359Sroberto { PARSEB_S_POSITION, "POSITION" }, 2545280849Scy { 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) 2559280849Scy t = ap(buffer, size, t, "; "); 2560280849Scy t = ap(buffer, size, t, "%s", flagstrings[i].name); 256154359Sroberto } 256254359Sroberto i++; 256354359Sroberto } 256454359Sroberto 2565285169Scy if (lstate & (PARSEB_S_LEAP|PARSEB_S_CALLBIT|PARSEB_S_PPS|PARSEB_S_POSITION)) 256654359Sroberto { 2567182007Sroberto if (s != t) 2568280849Scy t = ap(buffer, size, t, "; "); 256954359Sroberto 2570280849Scy t = ap(buffer, size, t, "("); 257154359Sroberto 2572280849Scy s = t; 257354359Sroberto 257454359Sroberto i = 0; 257554359Sroberto while (sflagstrings[i].bit) 257654359Sroberto { 257754359Sroberto if (sflagstrings[i].bit & lstate) 257854359Sroberto { 257954359Sroberto if (t != s) 258054359Sroberto { 2581280849Scy t = ap(buffer, size, t, "; "); 258254359Sroberto } 2583282408Scy 2584280849Scy t = ap(buffer, size, t, "%s", 2585280849Scy sflagstrings[i].name); 258654359Sroberto } 258754359Sroberto i++; 258854359Sroberto } 2589280849Scy t = ap(buffer, size, t, ")"); 2590289764Sglebius /* t is unused here, but if we don't track it and 2591289764Sglebius * need it later, that's a bug waiting to happen. 2592289764Sglebius */ 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" }, 2620280849Scy { 0, NULL } 262154359Sroberto }; 262254359Sroberto int i; 2623280849Scy char *t; 262454359Sroberto 2625280849Scy t = buffer; 262654359Sroberto *buffer = '\0'; 262754359Sroberto 262854359Sroberto i = 0; 262954359Sroberto while (flagstrings[i].bit) 263054359Sroberto { 263154359Sroberto if (flagstrings[i].bit & lstate) 263254359Sroberto { 2633280849Scy if (t != buffer) 2634280849Scy t = ap(buffer, size, t, "; "); 2635280849Scy 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" }, 2665280849Scy { (unsigned)~0L, NULL } 266654359Sroberto }; 266754359Sroberto int i; 266854359Sroberto 266954359Sroberto i = 0; 2670280849Scy 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'; 2698280849Scy t = buffer; 269954359Sroberto 270054359Sroberto if ((tmp = delta / (60*60*24)) != 0) 270154359Sroberto { 2702280849Scy 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 2711280849Scy t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d", 2712280849Scy (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{ 2792280849Scy struct parseunit *parse = NULL; 279354359Sroberto 2794182007Sroberto if (peer && peer->procptr) 2795280849Scy parse = peer->procptr->unitptr; 2796182007Sroberto 2797182007Sroberto if (!parse) 279854359Sroberto { 2799182007Sroberto /* nothing to clean up */ 280054359Sroberto return; 280154359Sroberto } 280254359Sroberto 2803280849Scy 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 { 2812280849Scy (void)time_pps_destroy(parse->atom.handle); 2813182007Sroberto } 2814182007Sroberto#endif 2815182007Sroberto if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2816280849Scy (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 } 2828282408Scy 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); 2841282408Scy 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 2867282408Scy if (mode == PARSE_HARDPPS_ENABLE) 2868182007Sroberto { 2869182007Sroberto if (parse->flags & PARSE_CLEAR) 2870182007Sroberto i = PPS_CAPTURECLEAR; 2871182007Sroberto else 2872182007Sroberto i = PPS_CAPTUREASSERT; 2873182007Sroberto } 2874282408Scy 2875280849Scy 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) 2887280849Scy 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{ 2902280849Scy int cap, mode_ppsoffset; 2903280849Scy const char *cp; 2904182007Sroberto 2905282408Scy parse->flags &= (u_char) (~PARSE_PPSCLOCK); 2906282408Scy 2907280849Scy /* 2908280849Scy * collect PPSAPI offset capability - should move into generic handling 2909280849Scy */ 2910280849Scy 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)); 2913282408Scy 2914182007Sroberto return 0; 2915182007Sroberto } 2916182007Sroberto 2917280849Scy /* 2918280849Scy * initialize generic PPSAPI interface 2919280849Scy * 2920280849Scy * we leave out CLK_FLAG3 as time_pps_kcbind() 2921280849Scy * is handled here for now. Ideally this should also 2922280849Scy * be part of the generic PPSAPI interface 2923280849Scy */ 2924280849Scy 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"; 2933280849Scy mode_ppsoffset = PPS_OFFSETCLEAR; 2934182007Sroberto } else { 2935182007Sroberto cp = "ASSERT"; 2936280849Scy mode_ppsoffset = PPS_OFFSETASSERT; 2937182007Sroberto } 2938182007Sroberto 2939182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2940182007Sroberto CLK_UNIT(parse->peer), cp); 2941182007Sroberto 2942280849Scy 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); 2945280849Scy mode_ppsoffset = 0; 2946182007Sroberto } else { 2947282408Scy if (mode_ppsoffset == PPS_OFFSETCLEAR) 2948282408Scy { 2949282408Scy parse->atom.pps_params.clear_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2950282408Scy parse->atom.pps_params.clear_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2951182007Sroberto } 2952282408Scy 2953280849Scy if (mode_ppsoffset == PPS_OFFSETASSERT) 2954282408Scy { 2955282408Scy parse->atom.pps_params.assert_offset.tv_sec = (time_t)(-parse->ppsphaseadjust); 2956282408Scy parse->atom.pps_params.assert_offset.tv_nsec = (long)(-1e9*(parse->ppsphaseadjust - (double)(long)parse->ppsphaseadjust)); 2957182007Sroberto } 2958182007Sroberto } 2959282408Scy 2960280849Scy parse->atom.pps_params.mode |= mode_ppsoffset; 2961182007Sroberto 2962280849Scy 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 */ 3004285169Scy 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 3011280849Scy 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 3027280849Scy#ifndef O_NONBLOCK 3028280849Scy#define O_NONBLOCK 0 302954359Sroberto#endif 303054359Sroberto 3031280849Scy fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3032280849Scy 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 3039280849Scy 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); 3063282408Scy 306454359Sroberto parse->parse_type = &parse_clockinfo[type]; 3065282408Scy 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; 3072358659Scy parse->generic->fudgeminjitter = 0.0; 307354359Sroberto 3074182007Sroberto parse->generic->clockdesc = parse->parse_type->cl_description; 307554359Sroberto 307654359Sroberto peer->rootdelay = parse->parse_type->cl_rootdelay; 307754359Sroberto peer->sstclktype = parse->parse_type->cl_type; 307854359Sroberto peer->precision = sys_precision; 3079282408Scy 308054359Sroberto peer->stratum = STRATUM_REFCLOCK; 3081182007Sroberto 308254359Sroberto if (peer->stratum <= 1) 308354359Sroberto memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 308454359Sroberto else 308554359Sroberto parse->generic->refid = htonl(PARSEHSREFID); 3086282408Scy 308754359Sroberto parse->generic->io.fd = fd232; 3088282408Scy 308954359Sroberto parse->peer = peer; /* marks it also as busy */ 309054359Sroberto 309154359Sroberto /* 309254359Sroberto * configure terminal line 309354359Sroberto */ 309454359Sroberto if (TTY_GETATTR(fd232, &tio) == -1) 309554359Sroberto { 309654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 309754359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 309854359Sroberto return 0; 309954359Sroberto } 310054359Sroberto else 310154359Sroberto { 310254359Sroberto#ifndef _PC_VDISABLE 310354359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 310454359Sroberto#else 310554359Sroberto int disablec; 310654359Sroberto errno = 0; /* pathconf can deliver -1 without changing errno ! */ 310754359Sroberto 310854359Sroberto disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 310954359Sroberto if (disablec == -1 && errno) 311054359Sroberto { 311154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 311254359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 311354359Sroberto } 311454359Sroberto else 311554359Sroberto if (disablec != -1) 311654359Sroberto memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 311754359Sroberto#endif 311854359Sroberto 311954359Sroberto#if defined (VMIN) || defined(VTIME) 312054359Sroberto if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 312154359Sroberto { 312254359Sroberto#ifdef VMIN 312354359Sroberto tio.c_cc[VMIN] = 1; 312454359Sroberto#endif 312554359Sroberto#ifdef VTIME 312654359Sroberto tio.c_cc[VTIME] = 0; 312754359Sroberto#endif 312854359Sroberto } 312954359Sroberto#endif 313054359Sroberto 3131282408Scy tio.c_cflag = (tcflag_t) parse_clockinfo[type].cl_cflag; 3132282408Scy tio.c_iflag = (tcflag_t) parse_clockinfo[type].cl_iflag; 3133282408Scy tio.c_oflag = (tcflag_t) parse_clockinfo[type].cl_oflag; 3134282408Scy tio.c_lflag = (tcflag_t) parse_clockinfo[type].cl_lflag; 313554359Sroberto 3136282408Scy 313754359Sroberto#ifdef HAVE_TERMIOS 3138282408Scy if ((cfsetospeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1) || 3139282408Scy (cfsetispeed(&tio, (speed_t) parse_clockinfo[type].cl_speed) == -1)) 314054359Sroberto { 314154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 314254359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 314354359Sroberto return 0; 314454359Sroberto } 314554359Sroberto#else 314654359Sroberto tio.c_cflag |= parse_clockinfo[type].cl_speed; 314754359Sroberto#endif 314854359Sroberto 3149182007Sroberto /* 3150182007Sroberto * set up pps device 3151182007Sroberto * if the PARSEPPSDEVICE can be opened that will be used 3152182007Sroberto * for PPS else PARSEDEVICE will be used 3153182007Sroberto */ 3154280849Scy parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3155182007Sroberto 3156182007Sroberto if (parse->ppsfd == -1) 3157182007Sroberto { 3158182007Sroberto parse->ppsfd = fd232; 3159182007Sroberto } 3160182007Sroberto 3161182007Sroberto/* 3162182007Sroberto * Linux PPS - the old way 3163182007Sroberto */ 316454359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 316554359Sroberto { 3166182007Sroberto struct serial_struct ss; 3167182007Sroberto if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 || 3168182007Sroberto ( 316954359Sroberto#ifdef ASYNC_LOW_LATENCY 3170182007Sroberto ss.flags |= ASYNC_LOW_LATENCY, 317154359Sroberto#endif 3172182007Sroberto#ifndef HAVE_PPSAPI 317354359Sroberto#ifdef ASYNC_PPS_CD_NEG 3174182007Sroberto ss.flags |= ASYNC_PPS_CD_NEG, 317554359Sroberto#endif 3176182007Sroberto#endif 3177182007Sroberto ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) { 3178182007Sroberto msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd); 3179182007Sroberto msyslog(LOG_NOTICE, 3180182007Sroberto "refclock_parse: optional PPS processing not available"); 3181182007Sroberto } else { 3182182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3183182007Sroberto#ifdef ASYNC_PPS_CD_NEG 3184182007Sroberto NLOG(NLOG_CLOCKINFO) 3185182007Sroberto msyslog(LOG_INFO, 3186182007Sroberto "refclock_parse: PPS detection on"); 3187182007Sroberto#endif 3188182007Sroberto } 318954359Sroberto } 319054359Sroberto#endif 3191182007Sroberto 3192182007Sroberto/* 3193182007Sroberto * SUN the Solaris way 3194182007Sroberto */ 319554359Sroberto#ifdef HAVE_TIOCSPPS /* SUN PPS support */ 319654359Sroberto if (CLK_PPS(parse->peer)) 3197182007Sroberto { 3198182007Sroberto int i = 1; 3199282408Scy 3200182007Sroberto if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0) 3201182007Sroberto { 3202182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3203182007Sroberto } 3204182007Sroberto } 320554359Sroberto#endif 320654359Sroberto 3207182007Sroberto/* 3208182007Sroberto * PPS via PPSAPI 3209182007Sroberto */ 3210182007Sroberto#if defined(HAVE_PPSAPI) 3211182007Sroberto parse->hardppsstate = PARSE_HARDPPS_DISABLE; 3212182007Sroberto if (CLK_PPS(parse->peer)) 3213182007Sroberto { 3214280849Scy if (!refclock_ppsapi(parse->ppsfd, &parse->atom)) 3215182007Sroberto { 3216182007Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer)); 3217182007Sroberto } 3218182007Sroberto else 3219182007Sroberto { 3220182007Sroberto parse_ppsapi(parse); 3221182007Sroberto } 3222182007Sroberto } 3223182007Sroberto#endif 3224182007Sroberto 322554359Sroberto if (TTY_SETATTR(fd232, &tio) == -1) 322654359Sroberto { 322754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 322854359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 322954359Sroberto return 0; 323054359Sroberto } 323154359Sroberto } 323254359Sroberto 323354359Sroberto /* 3234182007Sroberto * pick correct input machine 323554359Sroberto */ 3236280849Scy parse->generic->io.srcclock = peer; 323754359Sroberto parse->generic->io.datalen = 0; 3238282408Scy 323954359Sroberto parse->binding = init_iobinding(parse); 324054359Sroberto 324154359Sroberto if (parse->binding == (bind_t *)0) 324254359Sroberto { 324354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 324454359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 324554359Sroberto return 0; /* well, ok - special initialisation broke */ 3246280849Scy } 324754359Sroberto 3248182007Sroberto parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 3249182007Sroberto parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 3250182007Sroberto 325154359Sroberto /* 325254359Sroberto * as we always(?) get 8 bit chars we want to be 325354359Sroberto * sure, that the upper bits are zero for less 325454359Sroberto * than 8 bit I/O - so we pass that information on. 325554359Sroberto * note that there can be only one bit count format 325654359Sroberto * per file descriptor 325754359Sroberto */ 325854359Sroberto 325954359Sroberto switch (tio.c_cflag & CSIZE) 326054359Sroberto { 326154359Sroberto case CS5: 326254359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 326354359Sroberto break; 326454359Sroberto 326554359Sroberto case CS6: 326654359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 326754359Sroberto break; 326854359Sroberto 326954359Sroberto case CS7: 327054359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 327154359Sroberto break; 327254359Sroberto 327354359Sroberto case CS8: 327454359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 327554359Sroberto break; 327654359Sroberto } 327754359Sroberto 327854359Sroberto if (!PARSE_SETCS(parse, &tmp_ctl)) 327954359Sroberto { 328054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 328154359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 328254359Sroberto return 0; /* well, ok - special initialisation broke */ 328354359Sroberto } 3284282408Scy 3285280849Scy strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 3286282408Scy tmp_ctl.parseformat.parse_count = (u_short) strlen(tmp_ctl.parseformat.parse_buffer); 328754359Sroberto 328854359Sroberto if (!PARSE_SETFMT(parse, &tmp_ctl)) 328954359Sroberto { 329054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 329154359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 329254359Sroberto return 0; /* well, ok - special initialisation broke */ 329354359Sroberto } 3294282408Scy 329554359Sroberto /* 329654359Sroberto * get rid of all IO accumulated so far 329754359Sroberto */ 329854359Sroberto#ifdef HAVE_TERMIOS 329954359Sroberto (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 330054359Sroberto#else 3301182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH) 330254359Sroberto { 330354359Sroberto int flshcmd = TCIOFLUSH; 330454359Sroberto 330554359Sroberto (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 330654359Sroberto } 330754359Sroberto#endif 330854359Sroberto#endif 330956746Sroberto 331054359Sroberto /* 331154359Sroberto * try to do any special initializations 331254359Sroberto */ 331354359Sroberto if (parse->parse_type->cl_init) 331454359Sroberto { 331554359Sroberto if (parse->parse_type->cl_init(parse)) 331654359Sroberto { 331754359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 331854359Sroberto return 0; /* well, ok - special initialisation broke */ 331954359Sroberto } 332054359Sroberto } 3321282408Scy 332254359Sroberto /* 3323182007Sroberto * Insert in async io device list. 332454359Sroberto */ 3325182007Sroberto if (!io_addclock(&parse->generic->io)) 332654359Sroberto { 3327182007Sroberto msyslog(LOG_ERR, 3328182007Sroberto "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 3329182007Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3330182007Sroberto return 0; 333154359Sroberto } 333254359Sroberto 333354359Sroberto /* 333454359Sroberto * print out configuration 333554359Sroberto */ 333654359Sroberto NLOG(NLOG_CLOCKINFO) 333754359Sroberto { 333854359Sroberto /* conditional if clause for conditional syslog */ 3339182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added", 334054359Sroberto CLK_UNIT(parse->peer), 3341182007Sroberto parse->parse_type->cl_description, parsedev, 3342182007Sroberto (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev); 334354359Sroberto 3344182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d", 334554359Sroberto CLK_UNIT(parse->peer), 3346182007Sroberto parse->peer->stratum, 3347182007Sroberto l_mktime(parse->maxunsync), parse->peer->precision); 334854359Sroberto 3349182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling", 335054359Sroberto CLK_UNIT(parse->peer), 335154359Sroberto parse->parse_type->cl_rootdelay, 335254359Sroberto parse->generic->fudgetime1, 3353182007Sroberto parse->ppsphaseadjust, 3354182007Sroberto parse->binding->bd_description); 335554359Sroberto 3356182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 335754359Sroberto parse->parse_type->cl_format); 3358182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer), 3359182007Sroberto CLK_PPS(parse->peer) ? "" : "NO ", 3360182007Sroberto CLK_PPS(parse->peer) ? 3361182007Sroberto#ifdef PPS_METHOD 3362182007Sroberto " (implementation " PPS_METHOD ")" 3363182007Sroberto#else 3364182007Sroberto "" 336554359Sroberto#endif 3366182007Sroberto : "" 3367182007Sroberto ); 336854359Sroberto } 336954359Sroberto 337054359Sroberto return 1; 337154359Sroberto} 337254359Sroberto 337354359Sroberto/*-------------------------------------------------- 3374182007Sroberto * parse_ctl - process changes on flags/time values 3375182007Sroberto */ 3376182007Srobertostatic void 3377182007Srobertoparse_ctl( 3378182007Sroberto struct parseunit *parse, 3379280849Scy const struct refclockstat *in 3380182007Sroberto ) 3381182007Sroberto{ 3382182007Sroberto if (in) 3383182007Sroberto { 3384182007Sroberto if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3385182007Sroberto { 3386282408Scy u_char mask = CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4; 3387282408Scy parse->flags = (parse->flags & (u_char)(~mask)) | (in->flags & mask); 3388182007Sroberto#if defined(HAVE_PPSAPI) 3389182007Sroberto if (CLK_PPS(parse->peer)) 3390182007Sroberto { 3391182007Sroberto parse_ppsapi(parse); 3392182007Sroberto } 3393182007Sroberto#endif 3394182007Sroberto } 3395282408Scy 3396182007Sroberto if (in->haveflags & CLK_HAVETIME1) 3397182007Sroberto { 3398182007Sroberto parse->generic->fudgetime1 = in->fudgetime1; 3399182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s", 3400182007Sroberto CLK_UNIT(parse->peer), 3401182007Sroberto parse->generic->fudgetime1); 3402182007Sroberto } 3403282408Scy 3404182007Sroberto if (in->haveflags & CLK_HAVETIME2) 3405182007Sroberto { 3406182007Sroberto parse->generic->fudgetime2 = in->fudgetime2; 3407282408Scy if (parse->flags & PARSE_TRUSTTIME) 3408182007Sroberto { 3409182007Sroberto parse->maxunsync = (u_long)ABS(in->fudgetime2); 3410182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s", 3411182007Sroberto CLK_UNIT(parse->peer), 3412182007Sroberto l_mktime(parse->maxunsync)); 3413182007Sroberto } 3414182007Sroberto else 3415182007Sroberto { 3416182007Sroberto parse->ppsphaseadjust = in->fudgetime2; 3417182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s", 3418182007Sroberto CLK_UNIT(parse->peer), 3419182007Sroberto parse->ppsphaseadjust); 3420182007Sroberto#if defined(HAVE_PPSAPI) 3421182007Sroberto if (CLK_PPS(parse->peer)) 3422182007Sroberto { 3423182007Sroberto parse_ppsapi(parse); 3424182007Sroberto } 3425182007Sroberto#endif 3426182007Sroberto } 3427182007Sroberto } 3428358659Scy 3429358659Scy parse->generic->fudgeminjitter = in->fudgeminjitter; 3430182007Sroberto } 3431182007Sroberto} 3432182007Sroberto 3433182007Sroberto/*-------------------------------------------------- 343454359Sroberto * parse_poll - called by the transmit procedure 343554359Sroberto */ 343654359Srobertostatic void 343754359Srobertoparse_poll( 343854359Sroberto int unit, 343954359Sroberto struct peer *peer 344054359Sroberto ) 344154359Sroberto{ 3442280849Scy struct parseunit *parse = peer->procptr->unitptr; 344354359Sroberto 344454359Sroberto if (peer != parse->peer) 344554359Sroberto { 344654359Sroberto msyslog(LOG_ERR, 344754359Sroberto "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 344854359Sroberto unit); 344954359Sroberto return; 345054359Sroberto } 345154359Sroberto 345254359Sroberto /* 345354359Sroberto * Update clock stat counters 345454359Sroberto */ 345554359Sroberto parse->generic->polls++; 345654359Sroberto 3457282408Scy if (parse->pollneeddata && 3458280849Scy ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 345954359Sroberto { 346054359Sroberto /* 346156746Sroberto * start worrying when exceeding a poll inteval 346254359Sroberto * bad news - didn't get a response last time 346354359Sroberto */ 346454359Sroberto parse->lastmissed = current_time; 346554359Sroberto parse_event(parse, CEVNT_TIMEOUT); 3466282408Scy 346754359Sroberto ERR(ERR_NODATA) 3468182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer)); 346954359Sroberto } 347054359Sroberto 347154359Sroberto /* 347254359Sroberto * we just mark that we want the next sample for the clock filter 347354359Sroberto */ 347456746Sroberto parse->pollneeddata = current_time; 347554359Sroberto 347654359Sroberto if (parse->parse_type->cl_poll) 347754359Sroberto { 347854359Sroberto parse->parse_type->cl_poll(parse); 347954359Sroberto } 348054359Sroberto 348154359Sroberto cparse_statistics(parse); 348254359Sroberto 348354359Sroberto return; 348454359Sroberto} 348554359Sroberto 348654359Sroberto#define LEN_STATES 300 /* length of state string */ 348754359Sroberto 348854359Sroberto/*-------------------------------------------------- 348954359Sroberto * parse_control - set fudge factors, return statistics 349054359Sroberto */ 349154359Srobertostatic void 349254359Srobertoparse_control( 349354359Sroberto int unit, 3494280849Scy const struct refclockstat *in, 349554359Sroberto struct refclockstat *out, 349654359Sroberto struct peer *peer 349754359Sroberto ) 349854359Sroberto{ 3499280849Scy struct parseunit *parse = peer->procptr->unitptr; 350054359Sroberto parsectl_t tmpctl; 350154359Sroberto 350254359Sroberto static char outstatus[400]; /* status output buffer */ 350354359Sroberto 350454359Sroberto if (out) 350554359Sroberto { 350654359Sroberto out->lencode = 0; 350754359Sroberto out->p_lastcode = 0; 350854359Sroberto out->kv_list = (struct ctl_var *)0; 350954359Sroberto } 351054359Sroberto 351154359Sroberto if (!parse || !parse->peer) 351254359Sroberto { 351354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 351454359Sroberto unit); 351554359Sroberto return; 351654359Sroberto } 351754359Sroberto 351854359Sroberto unit = CLK_UNIT(parse->peer); 351954359Sroberto 3520182007Sroberto /* 3521182007Sroberto * handle changes 3522182007Sroberto */ 3523182007Sroberto parse_ctl(parse, in); 3524282408Scy 3525182007Sroberto /* 3526182007Sroberto * supply data 3527182007Sroberto */ 352854359Sroberto if (out) 352954359Sroberto { 353054359Sroberto u_long sum = 0; 3531182007Sroberto char *tt, *start; 353254359Sroberto int i; 353354359Sroberto 353454359Sroberto outstatus[0] = '\0'; 353554359Sroberto 353654359Sroberto out->type = REFCLK_PARSE; 353754359Sroberto 353854359Sroberto /* 3539182007Sroberto * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1 3540182007Sroberto */ 3541182007Sroberto parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust; 3542182007Sroberto 3543182007Sroberto /* 354454359Sroberto * figure out skew between PPS and RS232 - just for informational 3545182007Sroberto * purposes 354654359Sroberto */ 3547182007Sroberto if (PARSE_SYNC(parse->timedata.parse_state)) 354854359Sroberto { 3549182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state)) 355054359Sroberto { 355154359Sroberto l_fp off; 355254359Sroberto 355354359Sroberto /* 355454359Sroberto * we have a PPS and RS232 signal - calculate the skew 355554359Sroberto * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 355654359Sroberto */ 3557182007Sroberto off = parse->timedata.parse_stime.fp; 3558182007Sroberto L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */ 355954359Sroberto tt = add_var(&out->kv_list, 80, RO); 3560182007Sroberto snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6)); 356154359Sroberto } 356254359Sroberto } 356354359Sroberto 3564182007Sroberto if (PARSE_PPS(parse->timedata.parse_state)) 356554359Sroberto { 356654359Sroberto tt = add_var(&out->kv_list, 80, RO|DEF); 3567182007Sroberto snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp)); 356854359Sroberto } 356954359Sroberto 3570182007Sroberto start = tt = add_var(&out->kv_list, 128, RO|DEF); 3571280849Scy tt = ap(start, 128, tt, "refclock_time=\""); 357254359Sroberto 3573182007Sroberto if (parse->timedata.parse_time.fp.l_ui == 0) 357454359Sroberto { 3575280849Scy tt = ap(start, 128, tt, "<UNDEFINED>\""); 357654359Sroberto } 357754359Sroberto else 357854359Sroberto { 3579280849Scy tt = ap(start, 128, tt, "%s\"", 3580280849Scy gmprettydate(&parse->timedata.parse_time.fp)); 358154359Sroberto } 358254359Sroberto 358354359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 358454359Sroberto { 358554359Sroberto ERR(ERR_INTERNAL) 358654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 358754359Sroberto } 358854359Sroberto else 358954359Sroberto { 3590182007Sroberto start = tt = add_var(&out->kv_list, 512, RO|DEF); 3591280849Scy tt = ap(start, 512, tt, "refclock_status=\""); 359254359Sroberto 359354359Sroberto /* 359454359Sroberto * copy PPS flags from last read transaction (informational only) 359554359Sroberto */ 3596182007Sroberto tmpctl.parsegettc.parse_state |= parse->timedata.parse_state & 359754359Sroberto (PARSEB_PPS|PARSEB_S_PPS); 359854359Sroberto 3599280849Scy (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 360054359Sroberto 3601280849Scy tt += strlen(tt); 360254359Sroberto 3603280849Scy tt = ap(start, 512, tt, "\""); 3604280849Scy 360554359Sroberto if (tmpctl.parsegettc.parse_count) 360654359Sroberto mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 3607182007Sroberto tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count)); 360854359Sroberto 360954359Sroberto } 3610282408Scy 361154359Sroberto tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 3612282408Scy 361354359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 361454359Sroberto { 361554359Sroberto ERR(ERR_INTERNAL) 361654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 361754359Sroberto } 361854359Sroberto else 361954359Sroberto { 3620330106Sdelphij int count = tmpctl.parseformat.parse_count; 3621330106Sdelphij if (count) 3622330106Sdelphij --count; 362354359Sroberto 3624280849Scy start = tt = add_var(&out->kv_list, 80, RO|DEF); 3625280849Scy tt = ap(start, 80, tt, "refclock_format=\""); 3626280849Scy 3627280849Scy if (count > 0) { 3628282408Scy tt = ap(start, 80, tt, "%*.*s", 3629280849Scy count, 3630280849Scy count, 3631280849Scy tmpctl.parseformat.parse_buffer); 3632280849Scy } 3633280849Scy 3634280849Scy tt = ap(start, 80, tt, "\""); 363554359Sroberto } 363654359Sroberto 363754359Sroberto /* 363854359Sroberto * gather state statistics 363954359Sroberto */ 364054359Sroberto 364154359Sroberto start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3642280849Scy tt = ap(start, LEN_STATES, tt, "refclock_states=\""); 364354359Sroberto 364454359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 364554359Sroberto { 364654359Sroberto u_long s_time; 364754359Sroberto u_long d = current_time - parse->generic->timestarted; 364854359Sroberto u_long percent; 364954359Sroberto 365054359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 365154359Sroberto 365254359Sroberto while (((u_long)(~0) / 10000) < percent) 365354359Sroberto { 365454359Sroberto percent /= 10; 365554359Sroberto d /= 10; 365654359Sroberto } 3657282408Scy 365854359Sroberto if (d) 365954359Sroberto percent = (percent * 10000) / d; 366054359Sroberto else 366154359Sroberto percent = 10000; 366254359Sroberto 366354359Sroberto if (s_time) 366454359Sroberto { 366554359Sroberto char item[80]; 366654359Sroberto int count; 3667282408Scy 3668182007Sroberto snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 366954359Sroberto sum ? "; " : "", 367054359Sroberto (parse->generic->currentstatus == i) ? "*" : "", 367154359Sroberto clockstatus((unsigned int)i), 367254359Sroberto l_mktime(s_time), 367354359Sroberto (int)(percent / 100), (int)(percent % 100)); 3674282408Scy if ((count = (int) strlen(item)) < (LEN_STATES - 40 - (tt - start))) 367554359Sroberto { 3676280849Scy tt = ap(start, LEN_STATES, tt, 3677280849Scy "%s", item); 367854359Sroberto } 367954359Sroberto sum += s_time; 368054359Sroberto } 368154359Sroberto } 3682282408Scy 3683316068Sdelphij ap(start, LEN_STATES, tt, "; running time: %s\"", l_mktime(sum)); 3684282408Scy 368554359Sroberto tt = add_var(&out->kv_list, 32, RO); 3686182007Sroberto snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 3687282408Scy 368854359Sroberto tt = add_var(&out->kv_list, 80, RO); 3689182007Sroberto snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 369054359Sroberto 369154359Sroberto tt = add_var(&out->kv_list, 128, RO); 3692182007Sroberto snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 3693282408Scy 369454359Sroberto { 369554359Sroberto struct ctl_var *k; 3696282408Scy 369754359Sroberto k = parse->kv; 369854359Sroberto while (k && !(k->flags & EOV)) 369954359Sroberto { 370054359Sroberto set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 370154359Sroberto k++; 370254359Sroberto } 370354359Sroberto } 3704282408Scy 3705282408Scy out->lencode = (u_short) strlen(outstatus); 370654359Sroberto out->p_lastcode = outstatus; 370754359Sroberto } 370854359Sroberto} 370954359Sroberto 371054359Sroberto/**=========================================================================== 371154359Sroberto ** processing routines 371254359Sroberto **/ 371354359Sroberto 371454359Sroberto/*-------------------------------------------------- 371554359Sroberto * event handling - note that nominal events will also be posted 3716182007Sroberto * keep track of state dwelling times 371754359Sroberto */ 371854359Srobertostatic void 371954359Srobertoparse_event( 372054359Sroberto struct parseunit *parse, 372154359Sroberto int event 372254359Sroberto ) 372354359Sroberto{ 372454359Sroberto if (parse->generic->currentstatus != (u_char) event) 372554359Sroberto { 372654359Sroberto parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 372754359Sroberto parse->lastchange = current_time; 372854359Sroberto 372954359Sroberto if (parse->parse_type->cl_event) 373054359Sroberto parse->parse_type->cl_event(parse, event); 3731280849Scy 3732182007Sroberto if (event == CEVNT_NOMINAL) 373354359Sroberto { 373454359Sroberto NLOG(NLOG_CLOCKSTATUS) 373554359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 373654359Sroberto CLK_UNIT(parse->peer)); 373754359Sroberto } 373854359Sroberto 3739182007Sroberto refclock_report(parse->peer, event); 374054359Sroberto } 374154359Sroberto} 374254359Sroberto 374354359Sroberto/*-------------------------------------------------- 374454359Sroberto * process a PARSE time sample 374554359Sroberto */ 374654359Srobertostatic void 374754359Srobertoparse_process( 374854359Sroberto struct parseunit *parse, 374954359Sroberto parsetime_t *parsetime 375054359Sroberto ) 375154359Sroberto{ 375254359Sroberto l_fp off, rectime, reftime; 375354359Sroberto double fudge; 3754282408Scy 3755280849Scy /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */ 3756280849Scy ZERO(off); 3757280849Scy 375854359Sroberto /* 375954359Sroberto * check for changes in conversion status 376054359Sroberto * (only one for each new status !) 376154359Sroberto */ 376254359Sroberto if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 376354359Sroberto ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3764182007Sroberto (parse->timedata.parse_status != parsetime->parse_status)) 376554359Sroberto { 376654359Sroberto char buffer[400]; 3767282408Scy 376854359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 376954359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3770182007Sroberto CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 3771282408Scy 377254359Sroberto if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 377354359Sroberto { 377454359Sroberto /* 377554359Sroberto * tell more about the story - list time code 377654359Sroberto * there is a slight change for a race condition and 377754359Sroberto * the time code might be overwritten by the next packet 377854359Sroberto */ 377954359Sroberto parsectl_t tmpctl; 3780282408Scy 378154359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 378254359Sroberto { 378354359Sroberto ERR(ERR_INTERNAL) 378454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 378554359Sroberto } 378654359Sroberto else 378754359Sroberto { 3788330106Sdelphij unsigned int count = tmpctl.parsegettc.parse_count; 3789330106Sdelphij if (count) 3790330106Sdelphij --count; 379154359Sroberto ERR(ERR_BADDATA) 3792330106Sdelphij msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 3793330106Sdelphij CLK_UNIT(parse->peer), 3794330106Sdelphij mkascii(buffer, sizeof(buffer), 3795330106Sdelphij tmpctl.parsegettc.parse_buffer, count)); 379654359Sroberto } 3797285169Scy /* copy status to show only changes in case of failures */ 3798285169Scy parse->timedata.parse_status = parsetime->parse_status; 379954359Sroberto } 380054359Sroberto } 380154359Sroberto 380254359Sroberto /* 380354359Sroberto * examine status and post appropriate events 380454359Sroberto */ 380554359Sroberto if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 380654359Sroberto { 380754359Sroberto /* 380854359Sroberto * got bad data - tell the rest of the system 380954359Sroberto */ 381054359Sroberto switch (parsetime->parse_status & CVT_MASK) 381154359Sroberto { 381254359Sroberto case CVT_NONE: 381354359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 381454359Sroberto parse->parse_type->cl_message) 381554359Sroberto parse->parse_type->cl_message(parse, parsetime); 3816182007Sroberto /* 3817182007Sroberto * save PPS information that comes piggyback 3818182007Sroberto */ 3819182007Sroberto if (PARSE_PPS(parsetime->parse_state)) 3820182007Sroberto { 3821182007Sroberto parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3822182007Sroberto parse->timedata.parse_ptime = parsetime->parse_ptime; 3823182007Sroberto } 382454359Sroberto break; /* well, still waiting - timeout is handled at higher levels */ 3825282408Scy 382654359Sroberto case CVT_FAIL: 382754359Sroberto if (parsetime->parse_status & CVT_BADFMT) 382854359Sroberto { 382954359Sroberto parse_event(parse, CEVNT_BADREPLY); 383054359Sroberto } 383154359Sroberto else 383254359Sroberto if (parsetime->parse_status & CVT_BADDATE) 383354359Sroberto { 383454359Sroberto parse_event(parse, CEVNT_BADDATE); 383554359Sroberto } 383654359Sroberto else 383754359Sroberto if (parsetime->parse_status & CVT_BADTIME) 383854359Sroberto { 383954359Sroberto parse_event(parse, CEVNT_BADTIME); 384054359Sroberto } 384154359Sroberto else 384254359Sroberto { 384354359Sroberto parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 384454359Sroberto } 384554359Sroberto } 384654359Sroberto return; /* skip the rest - useless */ 384754359Sroberto } 384854359Sroberto 384954359Sroberto /* 385054359Sroberto * check for format changes 385154359Sroberto * (in case somebody has swapped clocks 8-) 385254359Sroberto */ 385354359Sroberto if (parse->lastformat != parsetime->parse_format) 385454359Sroberto { 385554359Sroberto parsectl_t tmpctl; 3856282408Scy 385754359Sroberto tmpctl.parseformat.parse_format = parsetime->parse_format; 385854359Sroberto 385954359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 386054359Sroberto { 386154359Sroberto ERR(ERR_INTERNAL) 386254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 386354359Sroberto } 386454359Sroberto else 386554359Sroberto { 386654359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 386754359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 386854359Sroberto CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 386954359Sroberto } 387054359Sroberto parse->lastformat = parsetime->parse_format; 387154359Sroberto } 387254359Sroberto 387354359Sroberto /* 387454359Sroberto * now, any changes ? 387554359Sroberto */ 3876182007Sroberto if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3877182007Sroberto ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 387854359Sroberto { 387954359Sroberto char tmp1[200]; 388054359Sroberto char tmp2[200]; 388154359Sroberto /* 3882182007Sroberto * something happend - except for PPS events 388354359Sroberto */ 3884282408Scy 3885182007Sroberto (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3886182007Sroberto (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 3887282408Scy 388854359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 388954359Sroberto msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 389054359Sroberto CLK_UNIT(parse->peer), tmp2, tmp1); 389154359Sroberto } 389254359Sroberto 389354359Sroberto /* 3894182007Sroberto * carry on PPS information if still usable 3895182007Sroberto */ 3896182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3897182007Sroberto { 3898182007Sroberto parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3899182007Sroberto parsetime->parse_ptime = parse->timedata.parse_ptime; 3900182007Sroberto } 3901182007Sroberto 3902182007Sroberto /* 390354359Sroberto * remember for future 390454359Sroberto */ 3905182007Sroberto parse->timedata = *parsetime; 390654359Sroberto 390754359Sroberto /* 390854359Sroberto * check to see, whether the clock did a complete powerup or lost PZF signal 390954359Sroberto * and post correct events for current condition 391054359Sroberto */ 391154359Sroberto if (PARSE_POWERUP(parsetime->parse_state)) 391254359Sroberto { 391354359Sroberto /* 391454359Sroberto * this is bad, as we have completely lost synchronisation 391554359Sroberto * well this is a problem with the receiver here 391654359Sroberto * for PARSE Meinberg DCF77 receivers the lost synchronisation 391754359Sroberto * is true as it is the powerup state and the time is taken 391854359Sroberto * from a crude real time clock chip 3919280849Scy * for the PZF/GPS series this is only partly true, as 392054359Sroberto * PARSE_POWERUP only means that the pseudo random 392154359Sroberto * phase shift sequence cannot be found. this is only 392254359Sroberto * bad, if we have never seen the clock in the SYNC 392354359Sroberto * state, where the PHASE and EPOCH are correct. 392454359Sroberto * for reporting events the above business does not 392554359Sroberto * really matter, but we can use the time code 392654359Sroberto * even in the POWERUP state after having seen 392754359Sroberto * the clock in the synchronized state (PZF class 392854359Sroberto * receivers) unless we have had a telegram disruption 392954359Sroberto * after having seen the clock in the SYNC state. we 393054359Sroberto * thus require having seen the clock in SYNC state 393154359Sroberto * *after* having missed telegrams (noresponse) from 393254359Sroberto * the clock. one problem remains: we might use erroneously 393354359Sroberto * POWERUP data if the disruption is shorter than 1 polling 393454359Sroberto * interval. fortunately powerdowns last usually longer than 64 393554359Sroberto * seconds and the receiver is at least 2 minutes in the 393654359Sroberto * POWERUP or NOSYNC state before switching to SYNC 3937280849Scy * for GPS receivers this can mean antenna problems and other causes. 3938280849Scy * the additional grace period can be enables by a clock 3939280849Scy * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set. 394054359Sroberto */ 394154359Sroberto parse_event(parse, CEVNT_FAULT); 394254359Sroberto NLOG(NLOG_CLOCKSTATUS) 394354359Sroberto ERR(ERR_BADSTATUS) 3944280849Scy msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS", 394554359Sroberto CLK_UNIT(parse->peer)); 394654359Sroberto } 394754359Sroberto else 394854359Sroberto { 394954359Sroberto /* 395054359Sroberto * we have two states left 395154359Sroberto * 395254359Sroberto * SYNC: 395354359Sroberto * this state means that the EPOCH (timecode) and PHASE 395454359Sroberto * information has be read correctly (at least two 395554359Sroberto * successive PARSE timecodes were received correctly) 395654359Sroberto * this is the best possible state - full trust 395754359Sroberto * 395854359Sroberto * NOSYNC: 395954359Sroberto * The clock should be on phase with respect to the second 396054359Sroberto * signal, but the timecode has not been received correctly within 396154359Sroberto * at least the last two minutes. this is a sort of half baked state 396254359Sroberto * for PARSE Meinberg DCF77 clocks this is bad news (clock running 396354359Sroberto * without timecode confirmation) 396454359Sroberto * PZF 535 has also no time confirmation, but the phase should be 396554359Sroberto * very precise as the PZF signal can be decoded 396654359Sroberto */ 396754359Sroberto 396854359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 396954359Sroberto { 397054359Sroberto /* 397154359Sroberto * currently completely synchronized - best possible state 397254359Sroberto */ 397354359Sroberto parse->lastsync = current_time; 397454359Sroberto clear_err(parse, ERR_BADSTATUS); 397554359Sroberto } 397654359Sroberto else 397754359Sroberto { 397854359Sroberto /* 397954359Sroberto * we have had some problems receiving the time code 398054359Sroberto */ 398154359Sroberto parse_event(parse, CEVNT_PROP); 398254359Sroberto NLOG(NLOG_CLOCKSTATUS) 398354359Sroberto ERR(ERR_BADSTATUS) 398454359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 398554359Sroberto CLK_UNIT(parse->peer)); 398654359Sroberto } 398754359Sroberto } 398854359Sroberto 398954359Sroberto fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 3990282408Scy 399154359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 399254359Sroberto { 399354359Sroberto rectime = parsetime->parse_stime.fp; 399454359Sroberto off = reftime = parsetime->parse_time.fp; 3995282408Scy 399654359Sroberto L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 399754359Sroberto 399854359Sroberto#ifdef DEBUG 399954359Sroberto if (debug > 3) 400054359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 400154359Sroberto CLK_UNIT(parse->peer), 400254359Sroberto prettydate(&reftime), 400354359Sroberto prettydate(&rectime), 400454359Sroberto lfptoa(&off,6)); 400554359Sroberto#endif 400654359Sroberto } 400754359Sroberto 400854359Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 400954359Sroberto { 401054359Sroberto l_fp offset; 4011182007Sroberto double ppsphaseadjust = parse->ppsphaseadjust; 401254359Sroberto 4013182007Sroberto#ifdef HAVE_PPSAPI 401454359Sroberto /* 4015182007Sroberto * set fudge = 0.0 if already included in PPS time stamps 4016182007Sroberto */ 4017280849Scy if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 4018182007Sroberto { 4019182007Sroberto ppsphaseadjust = 0.0; 4020182007Sroberto } 4021182007Sroberto#endif 4022182007Sroberto 4023182007Sroberto /* 402454359Sroberto * we have a PPS signal - much better than the RS232 stuff (we hope) 402554359Sroberto */ 402654359Sroberto offset = parsetime->parse_ptime.fp; 402754359Sroberto 402854359Sroberto#ifdef DEBUG 402954359Sroberto if (debug > 3) 403054359Sroberto printf("PARSE receiver #%d: PPStime %s\n", 403154359Sroberto CLK_UNIT(parse->peer), 403254359Sroberto prettydate(&offset)); 403354359Sroberto#endif 403454359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 403554359Sroberto { 4036280849Scy if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) && 4037280849Scy M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf)) 403854359Sroberto { 4039182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 4040282408Scy 404154359Sroberto /* 404254359Sroberto * RS232 offsets within [-0.5..0.5[ - take PPS offsets 404354359Sroberto */ 404454359Sroberto 404554359Sroberto if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 404654359Sroberto { 404754359Sroberto reftime = off = offset; 4048280849Scy if (reftime.l_uf & 0x80000000) 404954359Sroberto reftime.l_ui++; 405054359Sroberto reftime.l_uf = 0; 405156746Sroberto 4052282408Scy 405354359Sroberto /* 405454359Sroberto * implied on second offset 405554359Sroberto */ 405654359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4057280849Scy off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 405854359Sroberto } 405954359Sroberto else 406054359Sroberto { 406154359Sroberto /* 406254359Sroberto * time code describes pulse 406354359Sroberto */ 406454359Sroberto reftime = off = parsetime->parse_time.fp; 406554359Sroberto 406654359Sroberto L_SUB(&off, &offset); /* true offset */ 406754359Sroberto } 406854359Sroberto } 406954359Sroberto /* 407054359Sroberto * take RS232 offset when PPS when out of bounds 407154359Sroberto */ 407254359Sroberto } 407354359Sroberto else 407454359Sroberto { 4075182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 407654359Sroberto /* 407754359Sroberto * Well, no time code to guide us - assume on second pulse 407854359Sroberto * and pray, that we are within [-0.5..0.5[ 407954359Sroberto */ 408054359Sroberto off = offset; 408154359Sroberto reftime = offset; 4082280849Scy if (reftime.l_uf & 0x80000000) 408354359Sroberto reftime.l_ui++; 408454359Sroberto reftime.l_uf = 0; 408554359Sroberto /* 408654359Sroberto * implied on second offset 408754359Sroberto */ 408854359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4089280849Scy off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 409054359Sroberto } 409154359Sroberto } 409254359Sroberto else 409354359Sroberto { 409454359Sroberto if (!PARSE_TIMECODE(parsetime->parse_state)) 409554359Sroberto { 409654359Sroberto /* 409754359Sroberto * Well, no PPS, no TIMECODE, no more work ... 409854359Sroberto */ 409954359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 410054359Sroberto parse->parse_type->cl_message) 410154359Sroberto parse->parse_type->cl_message(parse, parsetime); 410254359Sroberto return; 410354359Sroberto } 410454359Sroberto } 410554359Sroberto 410654359Sroberto#ifdef DEBUG 410754359Sroberto if (debug > 3) 410854359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 410954359Sroberto CLK_UNIT(parse->peer), 411054359Sroberto prettydate(&reftime), 411154359Sroberto prettydate(&rectime), 411254359Sroberto lfptoa(&off,6)); 411354359Sroberto#endif 411454359Sroberto 411554359Sroberto 411654359Sroberto rectime = reftime; 411754359Sroberto L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 4118282408Scy 411954359Sroberto#ifdef DEBUG 412054359Sroberto if (debug > 3) 412154359Sroberto printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 412254359Sroberto CLK_UNIT(parse->peer), 412354359Sroberto prettydate(&reftime), 412454359Sroberto prettydate(&rectime)); 412554359Sroberto#endif 412654359Sroberto 412754359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 412854359Sroberto parse->parse_type->cl_message) 412954359Sroberto parse->parse_type->cl_message(parse, parsetime); 413054359Sroberto 413154359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 413254359Sroberto { 413354359Sroberto /* 413454359Sroberto * log OK status 413554359Sroberto */ 413654359Sroberto parse_event(parse, CEVNT_NOMINAL); 413754359Sroberto } 413854359Sroberto 413954359Sroberto clear_err(parse, ERR_BADIO); 414054359Sroberto clear_err(parse, ERR_BADDATA); 414154359Sroberto clear_err(parse, ERR_NODATA); 414254359Sroberto clear_err(parse, ERR_INTERNAL); 4143282408Scy 414454359Sroberto /* 414554359Sroberto * and now stick it into the clock machine 414654359Sroberto * samples are only valid iff lastsync is not too old and 414754359Sroberto * we have seen the clock in sync at least once 414854359Sroberto * after the last time we didn't see an expected data telegram 4149182007Sroberto * at startup being not in sync is also bad just like 4150282408Scy * POWERUP state unless PARSE_F_POWERUPTRUST is set 415154359Sroberto * see the clock states section above for more reasoning 415254359Sroberto */ 4153280849Scy if (((current_time - parse->lastsync) > parse->maxunsync) || 4154280849Scy (parse->lastsync < parse->lastmissed) || 4155182007Sroberto ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 4156280849Scy (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) && 4157280849Scy PARSE_POWERUP(parsetime->parse_state))) 415854359Sroberto { 415954359Sroberto parse->generic->leap = LEAP_NOTINSYNC; 4160182007Sroberto parse->lastsync = 0; /* wait for full sync again */ 416154359Sroberto } 416254359Sroberto else 416354359Sroberto { 416454359Sroberto if (PARSE_LEAPADD(parsetime->parse_state)) 416554359Sroberto { 416654359Sroberto /* 416754359Sroberto * we pick this state also for time code that pass leap warnings 416854359Sroberto * without direction information (as earth is currently slowing 416954359Sroberto * down). 417054359Sroberto */ 417154359Sroberto parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 417254359Sroberto } 417354359Sroberto else 417454359Sroberto if (PARSE_LEAPDEL(parsetime->parse_state)) 417554359Sroberto { 417654359Sroberto parse->generic->leap = LEAP_DELSECOND; 417754359Sroberto } 417854359Sroberto else 417954359Sroberto { 418054359Sroberto parse->generic->leap = LEAP_NOWARNING; 418154359Sroberto } 418254359Sroberto } 4183182007Sroberto 4184182007Sroberto if (parse->generic->leap != LEAP_NOTINSYNC) 4185182007Sroberto { 4186182007Sroberto /* 4187182007Sroberto * only good/trusted samples are interesting 4188182007Sroberto */ 4189182007Sroberto#ifdef DEBUG 4190282408Scy if (debug > 2) 4191282408Scy { 4192282408Scy printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 4193182007Sroberto CLK_UNIT(parse->peer), 4194182007Sroberto prettydate(&reftime), 4195182007Sroberto prettydate(&rectime), 4196182007Sroberto fudge); 4197182007Sroberto } 4198182007Sroberto#endif 4199182007Sroberto parse->generic->lastref = reftime; 4200282408Scy 4201182007Sroberto refclock_process_offset(parse->generic, reftime, rectime, fudge); 4202182007Sroberto 4203280849Scy#ifdef HAVE_PPSAPI 4204182007Sroberto /* 4205182007Sroberto * pass PPS information on to PPS clock 4206182007Sroberto */ 4207182007Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4208282408Scy { 4209282408Scy parse->peer->flags |= (FLAG_PPS | FLAG_TSTAMP_PPS); 4210182007Sroberto parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4211182007Sroberto } 4212280849Scy#endif 4213182007Sroberto } else { 4214282408Scy parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4215282408Scy parse->peer->flags &= ~(FLAG_PPS | FLAG_TSTAMP_PPS); 4216182007Sroberto } 4217182007Sroberto 421854359Sroberto /* 4219282408Scy * ready, unless the machine wants a sample or 4220182007Sroberto * we are in fast startup mode (peer->dist > MAXDISTANCE) 422154359Sroberto */ 4222182007Sroberto if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 422354359Sroberto return; 422454359Sroberto 422554359Sroberto parse->pollneeddata = 0; 422654359Sroberto 4227182007Sroberto parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4228182007Sroberto 422954359Sroberto refclock_receive(parse->peer); 423054359Sroberto} 4231282408Scy 423254359Sroberto/**=========================================================================== 423354359Sroberto ** special code for special clocks 423454359Sroberto **/ 423554359Sroberto 423654359Srobertostatic void 423754359Srobertomk_utcinfo( 4238316068Sdelphij char *t, /* pointer to the output string buffer */ 4239316068Sdelphij uint16_t wnt, 4240316068Sdelphij uint16_t wnlsf, 424154359Sroberto int dn, 424254359Sroberto int dtls, 4243182007Sroberto int dtlsf, 4244316068Sdelphij int size /* size of the output string buffer */ 424554359Sroberto ) 424654359Sroberto{ 4247282408Scy /* 4248282408Scy * The week number transmitted by the GPS satellites for the leap date 4249282408Scy * is truncated to 8 bits only. If the nearest leap second date is off 4250282408Scy * the current date by more than +/- 128 weeks then conversion to a 4251282408Scy * calendar date is ambiguous. On the other hand, if a leap second is 4252282408Scy * currently being announced (i.e. dtlsf != dtls) then the week number 4253282408Scy * wnlsf is close enough, and we can unambiguously determine the date 4254282408Scy * for which the leap second is scheduled. 4255282408Scy */ 4256282408Scy if ( dtlsf != dtls ) 4257282408Scy { 4258282408Scy time_t t_ls; 4259282408Scy struct tm *tm; 4260316068Sdelphij int nc; 4261282408Scy 4262344884Scy wnlsf = basedate_expand_gpsweek(wnlsf); 4263316068Sdelphij /* 'wnt' not used here: would need the same treatment as 'wnlsf */ 4264282408Scy 4265282408Scy t_ls = (time_t) wnlsf * SECSPERWEEK 4266282408Scy + (time_t) dn * SECSPERDAY 4267282408Scy + GPS_SEC_BIAS - 1; 4268282408Scy 4269282408Scy tm = gmtime( &t_ls ); 4270316068Sdelphij if (tm == NULL) /* gmtime() failed */ 4271282408Scy { 4272282408Scy snprintf( t, size, "** (gmtime() failed in mk_utcinfo())" ); 4273282408Scy return; 4274282408Scy } 4275282408Scy 4276316068Sdelphij nc = snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s", 4277282408Scy dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" ); 4278316068Sdelphij if (nc < 0) 4279316068Sdelphij nc = strlen(t); 4280316068Sdelphij else if (nc > size) 4281316068Sdelphij nc = size; 4282316068Sdelphij 4283316068Sdelphij snprintf( t + nc, size - nc, " at UTC midnight at the end of %s, %04i-%02i-%02i", 4284282408Scy daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday ); 4285282408Scy } 4286282408Scy else 4287316068Sdelphij { 4288282408Scy snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls ); 4289316068Sdelphij } 4290282408Scy 429154359Sroberto} 429254359Sroberto 429354359Sroberto#ifdef CLOCK_MEINBERG 429454359Sroberto/**=========================================================================== 4295282408Scy ** Meinberg GPS receiver support 429654359Sroberto **/ 429754359Sroberto 429854359Sroberto/*------------------------------------------------------------ 4299282408Scy * gps16x_message - process messages from Meinberg GPS receiver 430054359Sroberto */ 430154359Srobertostatic void 430254359Srobertogps16x_message( 430354359Sroberto struct parseunit *parse, 430454359Sroberto parsetime_t *parsetime 430554359Sroberto ) 430654359Sroberto{ 4307182007Sroberto if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 430854359Sroberto { 430954359Sroberto GPS_MSG_HDR header; 431054359Sroberto unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 4311282408Scy 431254359Sroberto#ifdef DEBUG 431354359Sroberto if (debug > 2) 431454359Sroberto { 431554359Sroberto char msgbuffer[600]; 4316282408Scy 431754359Sroberto mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 431854359Sroberto printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 431954359Sroberto CLK_UNIT(parse->peer), 432054359Sroberto parsetime->parse_msglen, 432154359Sroberto msgbuffer); 432254359Sroberto } 432354359Sroberto#endif 432454359Sroberto get_mbg_header(&bufp, &header); 4325282408Scy if (header.hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 4326282408Scy (header.len == 0 || 4327282408Scy (header.len < sizeof(parsetime->parse_msg) && 4328282408Scy header.data_csum == mbg_csum(bufp, header.len)))) 432954359Sroberto { 433054359Sroberto /* 433154359Sroberto * clean message 433254359Sroberto */ 4333282408Scy switch (header.cmd) 433454359Sroberto { 433554359Sroberto case GPS_SW_REV: 433654359Sroberto { 433754359Sroberto char buffer[64]; 433854359Sroberto SW_REV gps_sw_rev; 4339282408Scy 434054359Sroberto get_mbg_sw_rev(&bufp, &gps_sw_rev); 4341182007Sroberto snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 434254359Sroberto (gps_sw_rev.code >> 8) & 0xFF, 434354359Sroberto gps_sw_rev.code & 0xFF, 434454359Sroberto gps_sw_rev.name[0] ? " " : "", 434554359Sroberto gps_sw_rev.name); 4346182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 434754359Sroberto } 434854359Sroberto break; 434954359Sroberto 4350282408Scy case GPS_BVAR_STAT: 435154359Sroberto { 435254359Sroberto static struct state 435354359Sroberto { 4354282408Scy BVAR_STAT flag; /* status flag */ 4355282408Scy const char *string; /* bit name */ 435654359Sroberto } states[] = 435754359Sroberto { 4358282408Scy { BVAR_CFGH_INVALID, "Configuration/Health" }, 4359282408Scy { BVAR_ALM_NOT_COMPLETE, "Almanachs" }, 4360282408Scy { BVAR_UTC_INVALID, "UTC Correction" }, 4361282408Scy { BVAR_IONO_INVALID, "Ionospheric Correction" }, 4362282408Scy { BVAR_RCVR_POS_INVALID, "Receiver Position" }, 4363282408Scy { 0, "" } 436454359Sroberto }; 4365282408Scy BVAR_STAT status; 436654359Sroberto struct state *s = states; 436754359Sroberto char buffer[512]; 436854359Sroberto char *p, *b; 4369282408Scy 4370282408Scy status = (BVAR_STAT) get_lsb_short(&bufp); 4371280849Scy p = b = buffer; 4372280849Scy p = ap(buffer, sizeof(buffer), p, 4373280849Scy "meinberg_gps_status=\"[0x%04x] ", 4374280849Scy status); 4375282408Scy 437654359Sroberto if (status) 437754359Sroberto { 4378282408Scy p = ap(buffer, sizeof(buffer), p, "incomplete buffered data: "); 4379280849Scy b = p; 438054359Sroberto while (s->flag) 438154359Sroberto { 438254359Sroberto if (status & s->flag) 438354359Sroberto { 438454359Sroberto if (p != b) 438554359Sroberto { 4386280849Scy p = ap(buffer, sizeof(buffer), p, ", "); 438754359Sroberto } 4388282408Scy 4389280849Scy p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string); 439054359Sroberto } 439154359Sroberto s++; 439254359Sroberto } 4393280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 439454359Sroberto } 439554359Sroberto else 439654359Sroberto { 4397282408Scy p = ap(buffer, sizeof(buffer), p, "<all buffered data complete>\""); 439854359Sroberto } 4399282408Scy 4400182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 440154359Sroberto } 440254359Sroberto break; 440354359Sroberto 440454359Sroberto case GPS_POS_XYZ: 440554359Sroberto { 440654359Sroberto XYZ xyz; 440754359Sroberto char buffer[256]; 4408282408Scy 440954359Sroberto get_mbg_xyz(&bufp, xyz); 4410182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 441154359Sroberto mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 441254359Sroberto mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 441354359Sroberto mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 4414282408Scy 441554359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 441654359Sroberto } 441754359Sroberto break; 4418282408Scy 441954359Sroberto case GPS_POS_LLA: 442054359Sroberto { 442154359Sroberto LLA lla; 442254359Sroberto char buffer[256]; 4423282408Scy 442454359Sroberto get_mbg_lla(&bufp, lla); 4425282408Scy 4426182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 442754359Sroberto mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 4428282408Scy mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 442954359Sroberto mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 4430282408Scy 443154359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 443254359Sroberto } 443354359Sroberto break; 4434282408Scy 443554359Sroberto case GPS_TZDL: 443654359Sroberto break; 4437282408Scy 443854359Sroberto case GPS_PORT_PARM: 443954359Sroberto break; 4440282408Scy 444154359Sroberto case GPS_SYNTH: 444254359Sroberto break; 4443282408Scy 444454359Sroberto case GPS_ANT_INFO: 444554359Sroberto { 444654359Sroberto ANT_INFO antinfo; 4447182007Sroberto char buffer[512]; 4448280849Scy char *p, *q; 4449282408Scy 445054359Sroberto get_mbg_antinfo(&bufp, &antinfo); 4451280849Scy p = buffer; 4452280849Scy p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\""); 445354359Sroberto switch (antinfo.status) 445454359Sroberto { 4455282408Scy case ANT_INVALID: // No other fields valid since antenna has not yet been disconnected 4456280849Scy p = ap(buffer, sizeof(buffer), 4457280849Scy p, "<OK>"); 445854359Sroberto break; 4459282408Scy 4460282408Scy case ANT_DISCONN: // Antenna is disconnected, tm_reconn and delta_t not yet set 4461280849Scy q = ap(buffer, sizeof(buffer), 4462280849Scy p, "DISCONNECTED since "); 446354359Sroberto NLOG(NLOG_CLOCKSTATUS) 446454359Sroberto ERR(ERR_BADSTATUS) 446554359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 446654359Sroberto CLK_UNIT(parse->peer), p); 4467282408Scy 4468280849Scy p = q; 4469282408Scy mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 447054359Sroberto *p = '\0'; 447154359Sroberto break; 4472282408Scy 4473282408Scy case ANT_RECONN: // Antenna had been disconnect, but receiver sync. after reconnect, so all fields valid 4474280849Scy p = ap(buffer, sizeof(buffer), 4475282408Scy p, "SYNC AFTER RECONNECT on "); 4476282408Scy mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p), 0); 4477280849Scy p = ap(buffer, sizeof(buffer), 4478282408Scy p, ", clock offset at reconnect %c%ld.%07ld s, disconnect time ", 447954359Sroberto (antinfo.delta_t < 0) ? '-' : '+', 4480282408Scy (long) ABS(antinfo.delta_t) / 10000, 4481282408Scy (long) ABS(antinfo.delta_t) % 10000); 4482282408Scy mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p), 0); 448354359Sroberto *p = '\0'; 448454359Sroberto break; 4485282408Scy 448654359Sroberto default: 4487280849Scy p = ap(buffer, sizeof(buffer), 4488280849Scy p, "bad status 0x%04x", 4489280849Scy antinfo.status); 449054359Sroberto break; 449154359Sroberto } 4492282408Scy 4493280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 4494282408Scy 4495280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 449654359Sroberto } 449754359Sroberto break; 4498282408Scy 449954359Sroberto case GPS_UCAP: 450054359Sroberto break; 4501282408Scy 450254359Sroberto case GPS_CFGH: 450354359Sroberto { 450454359Sroberto CFGH cfgh; 4505182007Sroberto char buffer[512]; 4506182007Sroberto char *p; 4507282408Scy 450854359Sroberto get_mbg_cfgh(&bufp, &cfgh); 450954359Sroberto if (cfgh.valid) 451054359Sroberto { 4511282408Scy const char *cp; 4512282408Scy uint16_t tmp_val; 451354359Sroberto int i; 4514282408Scy 451554359Sroberto p = buffer; 4516280849Scy p = ap(buffer, sizeof(buffer), 4517280849Scy p, "gps_tot_51=\""); 4518182007Sroberto mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4519280849Scy p = ap(buffer, sizeof(buffer), 4520280849Scy p, "\""); 4521282408Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4522282408Scy 452354359Sroberto p = buffer; 4524280849Scy p = ap(buffer, sizeof(buffer), 4525280849Scy p, "gps_tot_63=\""); 4526182007Sroberto mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4527280849Scy p = ap(buffer, sizeof(buffer), 4528280849Scy p, "\""); 4529282408Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4530282408Scy 453154359Sroberto p = buffer; 4532280849Scy p = ap(buffer, sizeof(buffer), 4533280849Scy p, "gps_t0a=\""); 4534182007Sroberto mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4535280849Scy p = ap(buffer, sizeof(buffer), 4536280849Scy p, "\""); 4537282408Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 4538282408Scy 4539282408Scy for (i = 0; i < N_SVNO_GPS; i++) 454054359Sroberto { 454154359Sroberto p = buffer; 4542282408Scy p = ap(buffer, sizeof(buffer), p, "sv_info[%d]=\"PRN%d", i, i + N_SVNO_GPS); 4543282408Scy 4544282408Scy tmp_val = cfgh.health[i]; /* a 6 bit SV health code */ 4545282408Scy p = ap(buffer, sizeof(buffer), p, "; health=0x%02x (", tmp_val); 4546282408Scy /* "All Ones" has a special meaning" */ 4547282408Scy if (tmp_val == 0x3F) /* satellite is unusable or doesn't even exist */ 4548282408Scy cp = "SV UNAVAILABLE"; 4549282408Scy else { 4550282408Scy /* The MSB contains a summary of the 3 MSBs of the 8 bit health code, 4551282408Scy * indicating if the data sent by the satellite is OK or not. */ 4552282408Scy p = ap(buffer, sizeof(buffer), p, "DATA %s, ", (tmp_val & 0x20) ? "BAD" : "OK" ); 4553282408Scy 4554282408Scy /* The 5 LSBs contain the status of the different signals sent by the satellite. */ 4555282408Scy switch (tmp_val & 0x1F) 4556282408Scy { 4557282408Scy case 0x00: cp = "SIGNAL OK"; break; 4558282408Scy /* codes 0x01 through 0x1B indicate that one or more 4559282408Scy * specific signal components are weak or dead. 4560282408Scy * We don't decode this here in detail. */ 4561282408Scy case 0x1C: cp = "SV IS TEMP OUT"; break; 4562282408Scy case 0x1D: cp = "SV WILL BE TEMP OUT"; break; 4563282408Scy default: cp = "TRANSMISSION PROBLEMS"; break; 4564282408Scy } 456554359Sroberto } 4566282408Scy p = ap(buffer, sizeof(buffer), p, "%s)", cp ); 4567282408Scy 4568282408Scy tmp_val = cfgh.cfg[i]; /* a 4 bit SV configuration/type code */ 4569282408Scy p = ap(buffer, sizeof(buffer), p, "; cfg=0x%02x (", tmp_val); 4570282408Scy switch (tmp_val & 0x7) 457154359Sroberto { 4572282408Scy case 0x00: cp = "(reserved)"; break; 4573282408Scy case 0x01: cp = "BLOCK II/IIA/IIR"; break; 4574282408Scy case 0x02: cp = "BLOCK IIR-M"; break; 4575282408Scy case 0x03: cp = "BLOCK IIF"; break; 4576282408Scy case 0x04: cp = "BLOCK III"; break; 4577282408Scy default: cp = "unknown SV type"; break; 457854359Sroberto } 4579282408Scy p = ap(buffer, sizeof(buffer), p, "%s", cp ); 4580282408Scy if (tmp_val & 0x08) /* A-S is on, P-code is encrypted */ 4581282408Scy p = ap( buffer, sizeof(buffer), p, ", A-S on" ); 4582282408Scy 4583282408Scy p = ap(buffer, sizeof(buffer), p, ")\""); 4584282408Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|COND_DEF); 458554359Sroberto } 458654359Sroberto } 458754359Sroberto } 458854359Sroberto break; 4589282408Scy 459054359Sroberto case GPS_ALM: 459154359Sroberto break; 4592282408Scy 459354359Sroberto case GPS_EPH: 459454359Sroberto break; 4595282408Scy 459654359Sroberto case GPS_UTC: 459754359Sroberto { 459854359Sroberto UTC utc; 459954359Sroberto char buffer[512]; 460054359Sroberto char *p; 4601282408Scy 460254359Sroberto p = buffer; 4603282408Scy 460454359Sroberto get_mbg_utc(&bufp, &utc); 4605282408Scy 460654359Sroberto if (utc.valid) 460754359Sroberto { 4608280849Scy p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\""); 4609280849Scy mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 461054359Sroberto p += strlen(p); 4611280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 461254359Sroberto } 461354359Sroberto else 461454359Sroberto { 4615280849Scy p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\""); 461654359Sroberto } 4617280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 461854359Sroberto } 461954359Sroberto break; 4620282408Scy 462154359Sroberto case GPS_IONO: 462254359Sroberto break; 4623282408Scy 462454359Sroberto case GPS_ASCII_MSG: 462554359Sroberto { 462654359Sroberto ASCII_MSG gps_ascii_msg; 462754359Sroberto char buffer[128]; 4628282408Scy 462954359Sroberto get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 4630282408Scy 463154359Sroberto if (gps_ascii_msg.valid) 463254359Sroberto { 463354359Sroberto char buffer1[128]; 463454359Sroberto mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 4635282408Scy 4636182007Sroberto snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 463754359Sroberto } 463854359Sroberto else 4639280849Scy snprintf(buffer, sizeof(buffer), "gps_message=<NONE>"); 4640282408Scy 4641280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 464254359Sroberto } 4643282408Scy 464454359Sroberto break; 4645282408Scy 464654359Sroberto default: 464754359Sroberto break; 464854359Sroberto } 464954359Sroberto } 465054359Sroberto else 465154359Sroberto { 4652282408Scy msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%x), " 4653282408Scy "data_len = %d, data_csum = 0x%x (expected 0x%x)", 465454359Sroberto CLK_UNIT(parse->peer), 4655282408Scy header.hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 4656282408Scy header.len, 4657282408Scy header.data_csum, mbg_csum(bufp, (unsigned)((header.len < sizeof(parsetime->parse_msg)) ? header.len : 0))); 465854359Sroberto } 465954359Sroberto } 4660282408Scy 466154359Sroberto return; 466254359Sroberto} 466354359Sroberto 466454359Sroberto/*------------------------------------------------------------ 466554359Sroberto * gps16x_poll - query the reciver peridically 466654359Sroberto */ 466754359Srobertostatic void 466854359Srobertogps16x_poll( 466954359Sroberto struct peer *peer 467054359Sroberto ) 467154359Sroberto{ 4672280849Scy struct parseunit *parse = peer->procptr->unitptr; 4673282408Scy 4674282408Scy static GPS_MSG_HDR sequence[] = 467554359Sroberto { 467654359Sroberto { GPS_SW_REV, 0, 0, 0 }, 4677282408Scy { GPS_BVAR_STAT, 0, 0, 0 }, 467854359Sroberto { GPS_UTC, 0, 0, 0 }, 467954359Sroberto { GPS_ASCII_MSG, 0, 0, 0 }, 468054359Sroberto { GPS_ANT_INFO, 0, 0, 0 }, 468154359Sroberto { GPS_CFGH, 0, 0, 0 }, 468254359Sroberto { GPS_POS_XYZ, 0, 0, 0 }, 468354359Sroberto { GPS_POS_LLA, 0, 0, 0 }, 468454359Sroberto { (unsigned short)~0, 0, 0, 0 } 468554359Sroberto }; 4686280849Scy 468754359Sroberto int rtc; 468854359Sroberto unsigned char cmd_buffer[64]; 468954359Sroberto unsigned char *outp = cmd_buffer; 469054359Sroberto GPS_MSG_HDR *header; 4691282408Scy 469254359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 469354359Sroberto { 4694280849Scy parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 469554359Sroberto } 469654359Sroberto 4697282408Scy if (sequence[parse->localstate].cmd == (unsigned short)~0) 469854359Sroberto parse->localstate = 0; 4699282408Scy 470054359Sroberto header = sequence + parse->localstate++; 4701282408Scy 470254359Sroberto *outp++ = SOH; /* start command */ 4703282408Scy 470454359Sroberto put_mbg_header(&outp, header); 470554359Sroberto outp = cmd_buffer + 1; 4706282408Scy 4707282408Scy header->hdr_csum = (short)mbg_csum(outp, 6); 470854359Sroberto put_mbg_header(&outp, header); 4709282408Scy 471054359Sroberto#ifdef DEBUG 471154359Sroberto if (debug > 2) 471254359Sroberto { 471354359Sroberto char buffer[128]; 4714282408Scy 471554359Sroberto mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 471654359Sroberto printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 471754359Sroberto CLK_UNIT(parse->peer), 471854359Sroberto parse->localstate - 1, 471954359Sroberto (int)(outp - cmd_buffer), 4720282408Scy buffer); 472154359Sroberto } 472254359Sroberto#endif 4723282408Scy 4724282408Scy rtc = (int) write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 4725282408Scy 472654359Sroberto if (rtc < 0) 472754359Sroberto { 472854359Sroberto ERR(ERR_BADIO) 472954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 473054359Sroberto } 473154359Sroberto else 473254359Sroberto if (rtc != outp - cmd_buffer) 473354359Sroberto { 473454359Sroberto ERR(ERR_BADIO) 473554359Sroberto 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)); 473654359Sroberto } 473754359Sroberto 473854359Sroberto clear_err(parse, ERR_BADIO); 473954359Sroberto return; 474054359Sroberto} 474154359Sroberto 474254359Sroberto/*-------------------------------------------------- 474354359Sroberto * init routine - setup timer 474454359Sroberto */ 474554359Srobertostatic int 474654359Srobertogps16x_poll_init( 474754359Sroberto struct parseunit *parse 474854359Sroberto ) 474954359Sroberto{ 475054359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 475154359Sroberto { 4752280849Scy parse->peer->procptr->action = gps16x_poll; 475354359Sroberto gps16x_poll(parse->peer); 475454359Sroberto } 475554359Sroberto 475654359Sroberto return 0; 475754359Sroberto} 475854359Sroberto 475954359Sroberto#else 476054359Srobertostatic void 476154359Srobertogps16x_message( 476254359Sroberto struct parseunit *parse, 476354359Sroberto parsetime_t *parsetime 476454359Sroberto ) 476554359Sroberto{} 476654359Srobertostatic int 476754359Srobertogps16x_poll_init( 476854359Sroberto struct parseunit *parse 476954359Sroberto ) 477054359Sroberto{ 477154359Sroberto return 1; 477254359Sroberto} 477354359Sroberto#endif /* CLOCK_MEINBERG */ 4774282408Scy 477554359Sroberto/**=========================================================================== 477654359Sroberto ** clock polling support 477754359Sroberto **/ 477854359Sroberto 477954359Sroberto/*-------------------------------------------------- 478054359Sroberto * direct poll routine 478154359Sroberto */ 478254359Srobertostatic void 478354359Srobertopoll_dpoll( 478454359Sroberto struct parseunit *parse 478554359Sroberto ) 478654359Sroberto{ 4787282408Scy long rtc; 478854359Sroberto const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 4789282408Scy long ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 479054359Sroberto 4791282408Scy rtc = write(parse->generic->io.fd, ps, ct); 479254359Sroberto if (rtc < 0) 479354359Sroberto { 479454359Sroberto ERR(ERR_BADIO) 479554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 479654359Sroberto } 479754359Sroberto else 479854359Sroberto if (rtc != ct) 479954359Sroberto { 480054359Sroberto ERR(ERR_BADIO) 4801282408Scy msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%ld of %ld bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 480254359Sroberto } 480354359Sroberto clear_err(parse, ERR_BADIO); 480454359Sroberto} 480554359Sroberto 480654359Sroberto/*-------------------------------------------------- 480754359Sroberto * periodic poll routine 480854359Sroberto */ 480954359Srobertostatic void 481054359Srobertopoll_poll( 481154359Sroberto struct peer *peer 481254359Sroberto ) 481354359Sroberto{ 4814280849Scy struct parseunit *parse = peer->procptr->unitptr; 4815282408Scy 481654359Sroberto if (parse->parse_type->cl_poll) 481754359Sroberto parse->parse_type->cl_poll(parse); 481854359Sroberto 481954359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 482054359Sroberto { 4821280849Scy parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 482254359Sroberto } 482354359Sroberto} 482454359Sroberto 482554359Sroberto/*-------------------------------------------------- 482654359Sroberto * init routine - setup timer 482754359Sroberto */ 482854359Srobertostatic int 482954359Srobertopoll_init( 483054359Sroberto struct parseunit *parse 483154359Sroberto ) 483254359Sroberto{ 483354359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 483454359Sroberto { 4835280849Scy parse->peer->procptr->action = poll_poll; 483654359Sroberto poll_poll(parse->peer); 483754359Sroberto } 483854359Sroberto 483954359Sroberto return 0; 484054359Sroberto} 4841282408Scy 484254359Sroberto/**=========================================================================== 484354359Sroberto ** Trimble support 484454359Sroberto **/ 484554359Sroberto 484654359Sroberto/*------------------------------------------------------------- 484754359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init. 484854359Sroberto */ 484954359Srobertostatic int 485054359Srobertotrimbletaip_init( 485154359Sroberto struct parseunit *parse 485254359Sroberto ) 485354359Sroberto{ 485454359Sroberto#ifdef HAVE_TERMIOS 485554359Sroberto struct termios tio; 485654359Sroberto#endif 485754359Sroberto#ifdef HAVE_SYSV_TTYS 485854359Sroberto struct termio tio; 485954359Sroberto#endif 486054359Sroberto /* 486154359Sroberto * configure terminal line for trimble receiver 486254359Sroberto */ 486354359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 486454359Sroberto { 486554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 486654359Sroberto return 0; 486754359Sroberto } 486854359Sroberto else 486954359Sroberto { 487054359Sroberto tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 4871282408Scy 487254359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 487354359Sroberto { 487454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 487554359Sroberto return 0; 487654359Sroberto } 487754359Sroberto } 487854359Sroberto return poll_init(parse); 487954359Sroberto} 488054359Sroberto 488154359Sroberto/*-------------------------------------------------- 488254359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble 488354359Sroberto */ 488454359Srobertostatic const char *taipinit[] = { 488554359Sroberto ">FPV00000000<", 488654359Sroberto ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 488754359Sroberto ">FTM00020001<", 488854359Sroberto (char *)0 488954359Sroberto}; 4890282408Scy 489154359Srobertostatic void 489254359Srobertotrimbletaip_event( 489354359Sroberto struct parseunit *parse, 489454359Sroberto int event 489554359Sroberto ) 489654359Sroberto{ 489754359Sroberto switch (event) 489854359Sroberto { 489954359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 490054359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 490154359Sroberto { 490254359Sroberto const char **iv; 490354359Sroberto 490454359Sroberto iv = taipinit; 490554359Sroberto while (*iv) 490654359Sroberto { 4907282408Scy int rtc = (int) write(parse->generic->io.fd, *iv, strlen(*iv)); 490854359Sroberto if (rtc < 0) 490954359Sroberto { 491054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 491154359Sroberto return; 491254359Sroberto } 491354359Sroberto else 491454359Sroberto { 4915280849Scy if (rtc != (int)strlen(*iv)) 491654359Sroberto { 491754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 491854359Sroberto CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 491954359Sroberto return; 492054359Sroberto } 492154359Sroberto } 492254359Sroberto iv++; 492354359Sroberto } 492454359Sroberto 492554359Sroberto NLOG(NLOG_CLOCKINFO) 492654359Sroberto ERR(ERR_BADIO) 492754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 492854359Sroberto CLK_UNIT(parse->peer)); 492954359Sroberto } 493054359Sroberto break; 493154359Sroberto 493254359Sroberto default: /* ignore */ 493354359Sroberto break; 493454359Sroberto } 493554359Sroberto} 493654359Sroberto 493754359Sroberto/* 493854359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module. 493954359Sroberto * It should support other Trimble receivers which use the Trimble Standard 494054359Sroberto * Interface Protocol (see below). 494154359Sroberto * 494254359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second 494354359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is 494454359Sroberto * coincident with the change of the GPS second. This is the same as 494554359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks 494654359Sroberto * specifically use a feature in the data message as a timing reference, but 494754359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter 494854359Sroberto * on the timing of the messages, so this driver only supports the use 494954359Sroberto * of the PPS pulse for accurate timing. Where it is determined that 495054359Sroberto * the offset is way off, when first starting up ntpd for example, 495154359Sroberto * the timing of the data stream is used until the offset becomes low enough 495256746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used. 495354359Sroberto * 495454359Sroberto * It can use either option for receiving PPS information - the 'ppsclock' 495554359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier 495654359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only 495754359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in 495854359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter 495954359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another 496054359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input, 496154359Sroberto * by whichever method, is handled in ntp_loopfilter.c 496254359Sroberto * 496354359Sroberto * The receiver uses a serial message protocol called Trimble Standard 496454359Sroberto * Interface Protocol (it can support others but this driver only supports 496554359Sroberto * TSIP). Messages in this protocol have the following form: 496654359Sroberto * 496754359Sroberto * <DLE><id> ... <data> ... <DLE><ETX> 496854359Sroberto * 496954359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 497054359Sroberto * on transmission and compressed back to one on reception. Otherwise 497154359Sroberto * the values of data bytes can be anything. The serial interface is RS-422 497254359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 497354359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single, 497454359Sroberto * and double datatypes. Integers are two bytes, sent most significant first. 497554359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent 497654359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point 497754359Sroberto * numbers (8 byte) sent sign & exponent first. 497854359Sroberto * The receiver supports a large set of messages, only a small subset of 497954359Sroberto * which are used here. From driver to receiver the following are used: 498054359Sroberto * 498154359Sroberto * ID Description 498254359Sroberto * 498354359Sroberto * 21 Request current time 498454359Sroberto * 22 Mode Select 498554359Sroberto * 2C Set/Request operating parameters 498654359Sroberto * 2F Request UTC info 498754359Sroberto * 35 Set/Request I/O options 498854359Sroberto 498954359Sroberto * From receiver to driver the following are recognised: 499054359Sroberto * 499154359Sroberto * ID Description 499254359Sroberto * 499354359Sroberto * 41 GPS Time 499454359Sroberto * 44 Satellite selection, PDOP, mode 499554359Sroberto * 46 Receiver health 499654359Sroberto * 4B Machine code/status 499754359Sroberto * 4C Report operating parameters (debug only) 499854359Sroberto * 4F UTC correction data (used to get leap second warnings) 499954359Sroberto * 55 I/O options (debug only) 500054359Sroberto * 500154359Sroberto * All others are accepted but ignored. 500254359Sroberto * 500354359Sroberto */ 500454359Sroberto 500554359Sroberto#define PI 3.1415926535898 /* lots of sig figs */ 500654359Sroberto#define D2R PI/180.0 500754359Sroberto 500854359Sroberto/*------------------------------------------------------------------- 500954359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 501054359Sroberto * interface to the receiver. 501154359Sroberto * 501254359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and 501354359Sroberto * float implementation dependend - these must be converted to portable 501454359Sroberto * versions ! 501554359Sroberto * 501654359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems 501754359Sroberto * with IEEE754 floats as native floats 501854359Sroberto */ 501954359Sroberto 502054359Srobertotypedef struct trimble 502154359Sroberto{ 502254359Sroberto u_long last_msg; /* last message received */ 5023182007Sroberto u_long last_reset; /* last time a reset was issued */ 502454359Sroberto u_char qtracking; /* query tracking status */ 502554359Sroberto u_long ctrack; /* current tracking set */ 502654359Sroberto u_long ltrack; /* last tracking set */ 502754359Sroberto} trimble_t; 502854359Sroberto 502954359Srobertounion uval { 503054359Sroberto u_char bd[8]; 503154359Sroberto int iv; 503254359Sroberto float fv; 503354359Sroberto double dv; 503454359Sroberto}; 5035282408Scy 503654359Srobertostruct txbuf 503754359Sroberto{ 503854359Sroberto short idx; /* index to first unused byte */ 503954359Sroberto u_char *txt; /* pointer to actual data buffer */ 504054359Sroberto}; 504154359Sroberto 5042282408Scyvoid sendcmd (struct txbuf *buf, int c); 5043282408Scyvoid sendbyte (struct txbuf *buf, int b); 5044282408Scyvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5045282408Scyvoid sendint (struct txbuf *buf, int a); 5046282408Scyvoid sendflt (struct txbuf *buf, double a); 5047282408Scy 504854359Srobertovoid 504954359Srobertosendcmd( 505054359Sroberto struct txbuf *buf, 505154359Sroberto int c 505254359Sroberto ) 505354359Sroberto{ 505454359Sroberto buf->txt[0] = DLE; 505554359Sroberto buf->txt[1] = (u_char)c; 505654359Sroberto buf->idx = 2; 505754359Sroberto} 505854359Sroberto 5059282408Scyvoid sendcmd (struct txbuf *buf, int c); 5060282408Scyvoid sendbyte (struct txbuf *buf, int b); 5061282408Scyvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5062282408Scyvoid sendint (struct txbuf *buf, int a); 5063282408Scyvoid sendflt (struct txbuf *buf, double a); 5064282408Scy 506554359Srobertovoid 506654359Srobertosendbyte( 506754359Sroberto struct txbuf *buf, 506854359Sroberto int b 506954359Sroberto ) 507054359Sroberto{ 507154359Sroberto if (b == DLE) 507254359Sroberto buf->txt[buf->idx++] = DLE; 507354359Sroberto buf->txt[buf->idx++] = (u_char)b; 507454359Sroberto} 507554359Sroberto 507654359Srobertovoid 507754359Srobertosendetx( 507854359Sroberto struct txbuf *buf, 507954359Sroberto struct parseunit *parse 508054359Sroberto ) 508154359Sroberto{ 508254359Sroberto buf->txt[buf->idx++] = DLE; 508354359Sroberto buf->txt[buf->idx++] = ETX; 508454359Sroberto 508554359Sroberto if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 508654359Sroberto { 508754359Sroberto ERR(ERR_BADIO) 508854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 508954359Sroberto } 509054359Sroberto else 509154359Sroberto { 509254359Sroberto#ifdef DEBUG 509354359Sroberto if (debug > 2) 509454359Sroberto { 509554359Sroberto char buffer[256]; 5096282408Scy 509754359Sroberto mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 509854359Sroberto printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 509954359Sroberto CLK_UNIT(parse->peer), 5100282408Scy buf->idx, buffer); 510154359Sroberto } 510254359Sroberto#endif 510354359Sroberto clear_err(parse, ERR_BADIO); 510454359Sroberto } 510554359Sroberto} 510654359Sroberto 5107282408Scyvoid 510854359Srobertosendint( 510954359Sroberto struct txbuf *buf, 511054359Sroberto int a 511154359Sroberto ) 511254359Sroberto{ 511354359Sroberto /* send 16bit int, msbyte first */ 511454359Sroberto sendbyte(buf, (u_char)((a>>8) & 0xff)); 511554359Sroberto sendbyte(buf, (u_char)(a & 0xff)); 511654359Sroberto} 511754359Sroberto 511854359Srobertovoid 511954359Srobertosendflt( 512054359Sroberto struct txbuf *buf, 512154359Sroberto double a 512254359Sroberto ) 512354359Sroberto{ 512454359Sroberto int i; 512554359Sroberto union uval uval; 512654359Sroberto 5127282408Scy uval.fv = (float) a; 512854359Sroberto#ifdef WORDS_BIGENDIAN 512954359Sroberto for (i=0; i<=3; i++) 513054359Sroberto#else 513154359Sroberto for (i=3; i>=0; i--) 513254359Sroberto#endif 513354359Sroberto sendbyte(buf, uval.bd[i]); 513454359Sroberto} 513554359Sroberto 513654359Sroberto#define TRIM_POS_OPT 0x13 /* output position with high precision */ 513754359Sroberto#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 513854359Sroberto 513954359Sroberto/*-------------------------------------------------- 514054359Sroberto * trimble TSIP setup routine 514154359Sroberto */ 514254359Srobertostatic int 514354359Srobertotrimbletsip_setup( 514454359Sroberto struct parseunit *parse, 514554359Sroberto const char *reason 514656746Sroberto ) 514754359Sroberto{ 514854359Sroberto u_char buffer[256]; 514954359Sroberto struct txbuf buf; 5150182007Sroberto trimble_t *t = parse->localdata; 515154359Sroberto 5152182007Sroberto if (t && t->last_reset && 5153182007Sroberto ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 5154182007Sroberto return 1; /* not yet */ 5155182007Sroberto } 5156182007Sroberto 5157182007Sroberto if (t) 5158182007Sroberto t->last_reset = current_time; 5159282408Scy 516054359Sroberto buf.txt = buffer; 5161282408Scy 516254359Sroberto sendcmd(&buf, CMD_CVERSION); /* request software versions */ 516356746Sroberto sendetx(&buf, parse); 5164282408Scy 516554359Sroberto sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 516656746Sroberto sendbyte(&buf, 4); /* static */ 516756746Sroberto sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 516856746Sroberto sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 516956746Sroberto sendflt(&buf, 12.0); /* PDOP mask = 12 */ 517056746Sroberto sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 517156746Sroberto sendetx(&buf, parse); 5172282408Scy 517354359Sroberto sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 5174182007Sroberto sendbyte(&buf, 1); /* time transfer mode */ 517556746Sroberto sendetx(&buf, parse); 5176282408Scy 517754359Sroberto sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 517856746Sroberto sendetx(&buf, parse); 5179282408Scy 518054359Sroberto sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 518156746Sroberto sendbyte(&buf, 0x2); /* binary mode */ 518256746Sroberto sendetx(&buf, parse); 5183282408Scy 518454359Sroberto sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 518554359Sroberto sendbyte(&buf, TRIM_POS_OPT); /* position output */ 518654359Sroberto sendbyte(&buf, 0x00); /* no velocity output */ 518754359Sroberto sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 518854359Sroberto sendbyte(&buf, 0x00); /* no raw measurements */ 518956746Sroberto sendetx(&buf, parse); 5190282408Scy 519154359Sroberto sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 519254359Sroberto sendetx(&buf, parse); 519354359Sroberto 519454359Sroberto NLOG(NLOG_CLOCKINFO) 519554359Sroberto ERR(ERR_BADIO) 519654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 519754359Sroberto 519854359Sroberto return 0; 519954359Sroberto} 520054359Sroberto 520154359Sroberto/*-------------------------------------------------- 520254359Sroberto * TRIMBLE TSIP check routine 520354359Sroberto */ 520454359Srobertostatic void 520554359Srobertotrimble_check( 520654359Sroberto struct peer *peer 520754359Sroberto ) 520854359Sroberto{ 5209280849Scy struct parseunit *parse = peer->procptr->unitptr; 521054359Sroberto trimble_t *t = parse->localdata; 521154359Sroberto u_char buffer[256]; 521254359Sroberto struct txbuf buf; 521354359Sroberto buf.txt = buffer; 5214282408Scy 521554359Sroberto if (t) 521654359Sroberto { 521754359Sroberto if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 521854359Sroberto (void)trimbletsip_setup(parse, "message timeout"); 521954359Sroberto } 5220182007Sroberto 522154359Sroberto poll_poll(parse->peer); /* emit query string and re-arm timer */ 5222282408Scy 5223182007Sroberto if (t && t->qtracking) 522454359Sroberto { 522554359Sroberto u_long oldsats = t->ltrack & ~t->ctrack; 5226282408Scy 522754359Sroberto t->qtracking = 0; 522854359Sroberto t->ltrack = t->ctrack; 5229282408Scy 523054359Sroberto if (oldsats) 523154359Sroberto { 523254359Sroberto int i; 5233282408Scy 5234182007Sroberto for (i = 0; oldsats; i++) { 523554359Sroberto if (oldsats & (1 << i)) 523654359Sroberto { 523754359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 523854359Sroberto sendbyte(&buf, i+1); /* old sat */ 523954359Sroberto sendetx(&buf, parse); 524054359Sroberto } 5241182007Sroberto oldsats &= ~(1 << i); 5242182007Sroberto } 524354359Sroberto } 5244282408Scy 524554359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 524654359Sroberto sendbyte(&buf, 0x00); /* current tracking set */ 524754359Sroberto sendetx(&buf, parse); 524854359Sroberto } 524954359Sroberto} 525054359Sroberto 525154359Sroberto/*-------------------------------------------------- 525254359Sroberto * TRIMBLE TSIP end routine 525354359Sroberto */ 525454359Srobertostatic void 525554359Srobertotrimbletsip_end( 525654359Sroberto struct parseunit *parse 525754359Sroberto ) 525854359Sroberto{ trimble_t *t = parse->localdata; 5259282408Scy 526054359Sroberto if (t) 526154359Sroberto { 526254359Sroberto free(t); 5263280849Scy parse->localdata = NULL; 526454359Sroberto } 5265280849Scy parse->peer->procptr->nextaction = 0; 5266280849Scy parse->peer->procptr->action = NULL; 526754359Sroberto} 526854359Sroberto 526954359Sroberto/*-------------------------------------------------- 527054359Sroberto * TRIMBLE TSIP init routine 527154359Sroberto */ 527254359Srobertostatic int 527354359Srobertotrimbletsip_init( 527454359Sroberto struct parseunit *parse 527554359Sroberto ) 527654359Sroberto{ 527754359Sroberto#if defined(VEOL) || defined(VEOL2) 527854359Sroberto#ifdef HAVE_TERMIOS 527954359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 528054359Sroberto#endif 528154359Sroberto#ifdef HAVE_SYSV_TTYS 528254359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 528354359Sroberto#endif 528454359Sroberto /* 528554359Sroberto * allocate local data area 528654359Sroberto */ 528754359Sroberto if (!parse->localdata) 528854359Sroberto { 528954359Sroberto trimble_t *t; 5290282408Scy 529154359Sroberto t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 5292282408Scy 529354359Sroberto if (t) 529454359Sroberto { 529554359Sroberto memset((char *)t, 0, sizeof(trimble_t)); 529654359Sroberto t->last_msg = current_time; 529754359Sroberto } 529854359Sroberto } 529954359Sroberto 5300280849Scy parse->peer->procptr->action = trimble_check; 5301280849Scy parse->peer->procptr->nextaction = current_time; 530254359Sroberto 530354359Sroberto /* 530454359Sroberto * configure terminal line for ICANON mode with VEOL characters 530554359Sroberto */ 530654359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 530754359Sroberto { 530854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 530954359Sroberto return 0; 531054359Sroberto } 531154359Sroberto else 531254359Sroberto { 531354359Sroberto if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 531454359Sroberto { 531554359Sroberto#ifdef VEOL 531654359Sroberto tio.c_cc[VEOL] = ETX; 531754359Sroberto#endif 531854359Sroberto#ifdef VEOL2 531954359Sroberto tio.c_cc[VEOL2] = DLE; 532054359Sroberto#endif 532156746Sroberto } 532254359Sroberto 532354359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 532454359Sroberto { 532554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 532654359Sroberto return 0; 532754359Sroberto } 532854359Sroberto } 532954359Sroberto#endif 533054359Sroberto return trimbletsip_setup(parse, "initial startup"); 533154359Sroberto} 533254359Sroberto 533354359Sroberto/*------------------------------------------------------------ 533454359Sroberto * trimbletsip_event - handle Trimble events 533554359Sroberto * simple evente handler - attempt to re-initialize receiver 533654359Sroberto */ 533754359Srobertostatic void 533854359Srobertotrimbletsip_event( 533954359Sroberto struct parseunit *parse, 534054359Sroberto int event 534154359Sroberto ) 534254359Sroberto{ 534354359Sroberto switch (event) 534454359Sroberto { 534554359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 534654359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 534754359Sroberto (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 534854359Sroberto break; 534954359Sroberto 535054359Sroberto default: /* ignore */ 535154359Sroberto break; 535254359Sroberto } 535354359Sroberto} 535454359Sroberto 535554359Sroberto/* 535654359Sroberto * getflt, getint convert fields in the incoming data into the 535754359Sroberto * appropriate type of item 535854359Sroberto * 535954359Sroberto * CAVEAT: these routines are currently definitely byte order dependent 536054359Sroberto * and assume Representation(float) == IEEE754 536154359Sroberto * These functions MUST be converted to portable versions (especially 536254359Sroberto * converting the float representation into ntp_fp formats in order 536354359Sroberto * to avoid floating point operations at all! 536454359Sroberto */ 536554359Sroberto 536654359Srobertostatic float 536754359Srobertogetflt( 536854359Sroberto u_char *bp 536954359Sroberto ) 537054359Sroberto{ 537154359Sroberto union uval uval; 5372282408Scy 537354359Sroberto#ifdef WORDS_BIGENDIAN 537454359Sroberto uval.bd[0] = *bp++; 537554359Sroberto uval.bd[1] = *bp++; 537654359Sroberto uval.bd[2] = *bp++; 537754359Sroberto uval.bd[3] = *bp; 537854359Sroberto#else /* ! WORDS_BIGENDIAN */ 537954359Sroberto uval.bd[3] = *bp++; 538054359Sroberto uval.bd[2] = *bp++; 538154359Sroberto uval.bd[1] = *bp++; 538254359Sroberto uval.bd[0] = *bp; 538354359Sroberto#endif /* ! WORDS_BIGENDIAN */ 538454359Sroberto return uval.fv; 538554359Sroberto} 538654359Sroberto 538754359Srobertostatic double 538854359Srobertogetdbl( 538954359Sroberto u_char *bp 539054359Sroberto ) 539154359Sroberto{ 539254359Sroberto union uval uval; 5393282408Scy 539454359Sroberto#ifdef WORDS_BIGENDIAN 539554359Sroberto uval.bd[0] = *bp++; 539654359Sroberto uval.bd[1] = *bp++; 539754359Sroberto uval.bd[2] = *bp++; 539854359Sroberto uval.bd[3] = *bp++; 539954359Sroberto uval.bd[4] = *bp++; 540054359Sroberto uval.bd[5] = *bp++; 540154359Sroberto uval.bd[6] = *bp++; 540254359Sroberto uval.bd[7] = *bp; 540354359Sroberto#else /* ! WORDS_BIGENDIAN */ 540454359Sroberto uval.bd[7] = *bp++; 540554359Sroberto uval.bd[6] = *bp++; 540654359Sroberto uval.bd[5] = *bp++; 540754359Sroberto uval.bd[4] = *bp++; 540854359Sroberto uval.bd[3] = *bp++; 540954359Sroberto uval.bd[2] = *bp++; 541054359Sroberto uval.bd[1] = *bp++; 541154359Sroberto uval.bd[0] = *bp; 541254359Sroberto#endif /* ! WORDS_BIGENDIAN */ 541354359Sroberto return uval.dv; 541454359Sroberto} 541554359Sroberto 541654359Srobertostatic int 541754359Srobertogetshort( 541854359Sroberto unsigned char *p 541954359Sroberto ) 542054359Sroberto{ 5421282408Scy return (int) get_msb_short(&p); 542254359Sroberto} 542354359Sroberto 542454359Sroberto/*-------------------------------------------------- 542554359Sroberto * trimbletsip_message - process trimble messages 542654359Sroberto */ 542754359Sroberto#define RTOD (180.0 / 3.1415926535898) 542854359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 542954359Sroberto 543054359Srobertostatic void 543154359Srobertotrimbletsip_message( 543254359Sroberto struct parseunit *parse, 543354359Sroberto parsetime_t *parsetime 543454359Sroberto ) 543554359Sroberto{ 543654359Sroberto unsigned char *buffer = parsetime->parse_msg; 543754359Sroberto unsigned int size = parsetime->parse_msglen; 5438282408Scy 543954359Sroberto if ((size < 4) || 544054359Sroberto (buffer[0] != DLE) || 544154359Sroberto (buffer[size-1] != ETX) || 544254359Sroberto (buffer[size-2] != DLE)) 544354359Sroberto { 544454359Sroberto#ifdef DEBUG 544554359Sroberto if (debug > 2) { 5446280849Scy size_t i; 544754359Sroberto 544854359Sroberto printf("TRIMBLE BAD packet, size %d:\n ", size); 544954359Sroberto for (i = 0; i < size; i++) { 545054359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 545154359Sroberto if (i%16 == 15) printf("\n\t"); 545254359Sroberto } 545354359Sroberto printf("\n"); 545454359Sroberto } 545554359Sroberto#endif 545654359Sroberto return; 545754359Sroberto } 545854359Sroberto else 545954359Sroberto { 5460282408Scy u_short var_flag; 546154359Sroberto trimble_t *tr = parse->localdata; 546254359Sroberto unsigned int cmd = buffer[1]; 546354359Sroberto char pbuffer[200]; 546454359Sroberto char *t = pbuffer; 546554359Sroberto cmd_info_t *s; 5466282408Scy 546754359Sroberto#ifdef DEBUG 546854359Sroberto if (debug > 3) { 5469280849Scy size_t i; 547054359Sroberto 547154359Sroberto printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 547254359Sroberto for (i = 0; i < size; i++) { 547354359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 547454359Sroberto if (i%16 == 15) printf("\n\t"); 547554359Sroberto } 547654359Sroberto printf("\n"); 547754359Sroberto } 547854359Sroberto#endif 547954359Sroberto 548054359Sroberto if (tr) 548154359Sroberto tr->last_msg = current_time; 5482282408Scy 548354359Sroberto s = trimble_convert(cmd, trimble_rcmds); 5484282408Scy 548554359Sroberto if (s) 548654359Sroberto { 5487280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname); 548854359Sroberto } 548954359Sroberto else 549054359Sroberto { 5491182007Sroberto DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 549254359Sroberto return; 549354359Sroberto } 549454359Sroberto 5495282408Scy var_flag = (u_short) s->varmode; 549654359Sroberto 549754359Sroberto switch(cmd) 549854359Sroberto { 549954359Sroberto case CMD_RCURTIME: 5500280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f", 5501182007Sroberto getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5502182007Sroberto getflt((unsigned char *)&mb(6))); 550354359Sroberto break; 5504282408Scy 550554359Sroberto case CMD_RBEST4: 5506280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 550754359Sroberto switch (mb(0) & 0xF) 550854359Sroberto { 550954359Sroberto default: 5510280849Scy t = ap(pbuffer, sizeof(pbuffer), t, 5511280849Scy "0x%x", mb(0) & 0x7); 551254359Sroberto break; 551354359Sroberto 551454359Sroberto case 1: 5515280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "0D"); 551654359Sroberto break; 5517282408Scy 551854359Sroberto case 3: 5519280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 552054359Sroberto break; 5521282408Scy 552254359Sroberto case 4: 5523280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 552454359Sroberto break; 552554359Sroberto } 552654359Sroberto if (mb(0) & 0x10) 5527280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 552854359Sroberto else 5529280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5530282408Scy 5531280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 553254359Sroberto mb(1), mb(2), mb(3), mb(4), 553354359Sroberto getflt((unsigned char *)&mb(5)), 553454359Sroberto getflt((unsigned char *)&mb(9)), 553554359Sroberto getflt((unsigned char *)&mb(13)), 553654359Sroberto getflt((unsigned char *)&mb(17))); 553754359Sroberto 553854359Sroberto break; 5539282408Scy 554054359Sroberto case CMD_RVERSION: 5541280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)", 554254359Sroberto mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 554354359Sroberto break; 5544282408Scy 554554359Sroberto case CMD_RRECVHEALTH: 554654359Sroberto { 554754359Sroberto static const char *msgs[] = 554854359Sroberto { 554954359Sroberto "Battery backup failed", 555054359Sroberto "Signal processor error", 555154359Sroberto "Alignment error, channel or chip 1", 555254359Sroberto "Alignment error, channel or chip 2", 555354359Sroberto "Antenna feed line fault", 555454359Sroberto "Excessive ref freq. error", 555554359Sroberto "<BIT 6>", 555654359Sroberto "<BIT 7>" 555754359Sroberto }; 5558282408Scy 555954359Sroberto int i, bits; 5560282408Scy 556154359Sroberto switch (mb(0) & 0xFF) 556254359Sroberto { 556354359Sroberto default: 5564280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF); 556554359Sroberto break; 556654359Sroberto case 0x00: 5567280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes"); 556854359Sroberto break; 556954359Sroberto case 0x01: 5570280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet"); 557154359Sroberto break; 557254359Sroberto case 0x03: 5573280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high"); 557454359Sroberto break; 557554359Sroberto case 0x08: 5576280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites"); 557754359Sroberto break; 557854359Sroberto case 0x09: 5579280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite"); 558054359Sroberto break; 558154359Sroberto case 0x0A: 5582280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites"); 558354359Sroberto break; 558454359Sroberto case 0x0B: 5585280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites"); 558654359Sroberto break; 558754359Sroberto case 0x0C: 5588280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable"); 558954359Sroberto break; 559054359Sroberto } 559154359Sroberto 559254359Sroberto bits = mb(1) & 0xFF; 5593282408Scy 559454359Sroberto for (i = 0; i < 8; i++) 559554359Sroberto if (bits & (0x1<<i)) 559654359Sroberto { 5597280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 559854359Sroberto } 559954359Sroberto } 560054359Sroberto break; 5601282408Scy 560254359Sroberto case CMD_RMESSAGE: 5603182007Sroberto mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 560454359Sroberto break; 5605282408Scy 560654359Sroberto case CMD_RMACHSTAT: 560754359Sroberto { 560854359Sroberto static const char *msgs[] = 560954359Sroberto { 561054359Sroberto "Synthesizer Fault", 561154359Sroberto "Battery Powered Time Clock Fault", 561254359Sroberto "A-to-D Converter Fault", 561354359Sroberto "The almanac stored in the receiver is not complete and current", 561454359Sroberto "<BIT 4>", 561554359Sroberto "<BIT 5", 561654359Sroberto "<BIT 6>", 561754359Sroberto "<BIT 7>" 561854359Sroberto }; 5619282408Scy 562054359Sroberto int i, bits; 562154359Sroberto 5622280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF); 562354359Sroberto bits = mb(1) & 0xFF; 5624282408Scy 562554359Sroberto for (i = 0; i < 8; i++) 562654359Sroberto if (bits & (0x1<<i)) 562754359Sroberto { 5628280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 562954359Sroberto } 563054359Sroberto 5631280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 563254359Sroberto } 563354359Sroberto break; 5634282408Scy 563554359Sroberto case CMD_ROPERPARAM: 5636280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f", 563754359Sroberto mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 563854359Sroberto getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 563954359Sroberto break; 5640282408Scy 564154359Sroberto case CMD_RUTCPARAM: 564254359Sroberto { 564354359Sroberto float t0t = getflt((unsigned char *)&mb(14)); 5644282408Scy short wnt = (short) getshort((unsigned char *)&mb(18)); 5645282408Scy short dtls = (short) getshort((unsigned char *)&mb(12)); 5646282408Scy short wnlsf = (short) getshort((unsigned char *)&mb(20)); 5647282408Scy short dn = (short) getshort((unsigned char *)&mb(22)); 5648282408Scy short dtlsf = (short) getshort((unsigned char *)&mb(24)); 564954359Sroberto 565054359Sroberto if ((int)t0t != 0) 5651280849Scy { 5652280849Scy mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 5653280849Scy } 565454359Sroberto else 5655280849Scy { 5656280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>"); 5657280849Scy } 565854359Sroberto } 565954359Sroberto break; 566054359Sroberto 566154359Sroberto case CMD_RSAT1BIAS: 5662280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs", 566354359Sroberto getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 566454359Sroberto break; 566554359Sroberto 566654359Sroberto case CMD_RIOOPTIONS: 566754359Sroberto { 5668280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x", 566954359Sroberto mb(0), mb(1), mb(2), mb(3)); 567054359Sroberto if (mb(0) != TRIM_POS_OPT || 567154359Sroberto mb(2) != TRIM_TIME_OPT) 567254359Sroberto { 567354359Sroberto (void)trimbletsip_setup(parse, "bad io options"); 567454359Sroberto } 567554359Sroberto } 567654359Sroberto break; 5677282408Scy 567854359Sroberto case CMD_RSPOSXYZ: 567954359Sroberto { 568054359Sroberto double x = getflt((unsigned char *)&mb(0)); 568154359Sroberto double y = getflt((unsigned char *)&mb(4)); 568254359Sroberto double z = getflt((unsigned char *)&mb(8)); 568354359Sroberto double f = getflt((unsigned char *)&mb(12)); 5684282408Scy 568554359Sroberto if (f > 0.0) 5686280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 568754359Sroberto x, y, z, 568854359Sroberto f); 568954359Sroberto else 5690280849Scy return; 569154359Sroberto } 569254359Sroberto break; 569354359Sroberto 569454359Sroberto case CMD_RSLLAPOS: 569554359Sroberto { 569654359Sroberto double lat = getflt((unsigned char *)&mb(0)); 569754359Sroberto double lng = getflt((unsigned char *)&mb(4)); 569854359Sroberto double f = getflt((unsigned char *)&mb(12)); 5699282408Scy 570054359Sroberto if (f > 0.0) 5701280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm", 570254359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 570354359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 570454359Sroberto getflt((unsigned char *)&mb(8))); 570554359Sroberto else 5706280849Scy return; 570754359Sroberto } 570854359Sroberto break; 570954359Sroberto 571054359Sroberto case CMD_RDOUBLEXYZ: 571154359Sroberto { 571254359Sroberto double x = getdbl((unsigned char *)&mb(0)); 571354359Sroberto double y = getdbl((unsigned char *)&mb(8)); 571454359Sroberto double z = getdbl((unsigned char *)&mb(16)); 5715280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm", 571654359Sroberto x, y, z); 571754359Sroberto } 571854359Sroberto break; 5719282408Scy 572054359Sroberto case CMD_RDOUBLELLA: 572154359Sroberto { 572254359Sroberto double lat = getdbl((unsigned char *)&mb(0)); 572354359Sroberto double lng = getdbl((unsigned char *)&mb(8)); 5724280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm", 572554359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 572654359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 572754359Sroberto getdbl((unsigned char *)&mb(16))); 572854359Sroberto } 572954359Sroberto break; 573054359Sroberto 573154359Sroberto case CMD_RALLINVIEW: 573254359Sroberto { 573354359Sroberto int i, sats; 5734282408Scy 5735280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 573654359Sroberto switch (mb(0) & 0x7) 573754359Sroberto { 573854359Sroberto default: 5739280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7); 574054359Sroberto break; 574154359Sroberto 574254359Sroberto case 3: 5743280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 574454359Sroberto break; 5745282408Scy 574654359Sroberto case 4: 5747280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 574854359Sroberto break; 574954359Sroberto } 575054359Sroberto if (mb(0) & 0x8) 5751280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 575254359Sroberto else 5753280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 5754282408Scy 575554359Sroberto sats = (mb(0)>>4) & 0xF; 5756282408Scy 5757280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 575854359Sroberto getflt((unsigned char *)&mb(1)), 575954359Sroberto getflt((unsigned char *)&mb(5)), 576054359Sroberto getflt((unsigned char *)&mb(9)), 576154359Sroberto getflt((unsigned char *)&mb(13)), 576254359Sroberto sats, (sats == 1) ? "" : "s"); 576354359Sroberto 576454359Sroberto for (i=0; i < sats; i++) 576554359Sroberto { 5766280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i)); 576754359Sroberto if (tr) 576854359Sroberto tr->ctrack |= (1 << (mb(17+i)-1)); 576954359Sroberto } 577054359Sroberto 577154359Sroberto if (tr) 5772280849Scy { /* mark for tracking status query */ 577354359Sroberto tr->qtracking = 1; 577454359Sroberto } 577554359Sroberto } 577654359Sroberto break; 5777282408Scy 577854359Sroberto case CMD_RSTATTRACK: 577954359Sroberto { 5780280849Scy t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */ 578154359Sroberto if (getflt((unsigned char *)&mb(4)) < 0.0) 578254359Sroberto { 5783280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>"); 5784282408Scy var_flag &= (u_short)(~DEF); 578554359Sroberto } 578654359Sroberto else 5787282408Scy { 5788280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 578954359Sroberto (mb(1) & 0xFF)>>3, 579054359Sroberto mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 579154359Sroberto mb(3), 579254359Sroberto getflt((unsigned char *)&mb(4)), 579354359Sroberto getflt((unsigned char *)&mb(12)) * RTOD, 579454359Sroberto getflt((unsigned char *)&mb(16)) * RTOD); 579554359Sroberto if (mb(20)) 579654359Sroberto { 5797282408Scy var_flag &= (u_short)(~DEF); 5798280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", OLD"); 579954359Sroberto } 580054359Sroberto if (mb(22)) 580154359Sroberto { 580254359Sroberto if (mb(22) == 1) 5803280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY"); 580454359Sroberto else 580554359Sroberto if (mb(22) == 2) 5806280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH"); 580754359Sroberto } 580854359Sroberto if (mb(23)) 5809280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data"); 581054359Sroberto } 581154359Sroberto } 581254359Sroberto break; 5813282408Scy 581454359Sroberto default: 5815280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>"); 581654359Sroberto break; 581754359Sroberto } 5818182007Sroberto 5819282408Scy t = ap(pbuffer, sizeof(pbuffer), t, "\""); 582054359Sroberto set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 582154359Sroberto } 582254359Sroberto} 582354359Sroberto 5824282408Scy 582554359Sroberto/**============================================================ 582654359Sroberto ** RAWDCF support 582754359Sroberto **/ 582854359Sroberto 582954359Sroberto/*-------------------------------------------------- 583056746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers 583156746Sroberto * SET DTR line 583254359Sroberto */ 583354359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 583454359Srobertostatic int 583556746Srobertorawdcf_init_1( 583654359Sroberto struct parseunit *parse 583754359Sroberto ) 583854359Sroberto{ 583982498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 584054359Sroberto /* 584154359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 584254359Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 584354359Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 584454359Sroberto */ 584582498Sroberto int sl232; 584682498Sroberto 584782498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 584882498Sroberto { 584982498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 585082498Sroberto return 0; 585182498Sroberto } 585282498Sroberto 585354359Sroberto#ifdef TIOCM_DTR 585482498Sroberto sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 585554359Sroberto#else 585682498Sroberto sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 585754359Sroberto#endif 585854359Sroberto 585954359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 586054359Sroberto { 586156746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 586254359Sroberto } 586354359Sroberto return 0; 586454359Sroberto} 586554359Sroberto#else 586654359Srobertostatic int 5867132451Srobertorawdcfdtr_init_1( 586854359Sroberto struct parseunit *parse 586954359Sroberto ) 587054359Sroberto{ 587156746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 587254359Sroberto return 0; 587354359Sroberto} 587454359Sroberto#endif /* DTR initialisation type */ 587554359Sroberto 587654359Sroberto/*-------------------------------------------------- 587756746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers 587856746Sroberto * CLR DTR line, SET RTS line 587954359Sroberto */ 588056746Sroberto#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 588154359Srobertostatic int 588256746Srobertorawdcf_init_2( 588354359Sroberto struct parseunit *parse 588454359Sroberto ) 588554359Sroberto{ 588682498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 588754359Sroberto /* 588854359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 588956746Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 589056746Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 589154359Sroberto */ 589282498Sroberto int sl232; 589382498Sroberto 589482498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 589582498Sroberto { 589682498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 589782498Sroberto return 0; 589882498Sroberto } 589982498Sroberto 590054359Sroberto#ifdef TIOCM_RTS 590182498Sroberto sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 590254359Sroberto#else 590382498Sroberto sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 590454359Sroberto#endif 590554359Sroberto 590654359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 590754359Sroberto { 590856746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 590954359Sroberto } 591054359Sroberto return 0; 591154359Sroberto} 591254359Sroberto#else 591354359Srobertostatic int 591456746Srobertorawdcf_init_2( 591554359Sroberto struct parseunit *parse 591654359Sroberto ) 591754359Sroberto{ 591856746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 591954359Sroberto return 0; 592054359Sroberto} 592156746Sroberto#endif /* DTR initialisation type */ 592254359Sroberto 592354359Sroberto#else /* defined(REFCLOCK) && defined(PARSE) */ 5924280849ScyNONEMPTY_TRANSLATION_UNIT 592554359Sroberto#endif /* defined(REFCLOCK) && defined(PARSE) */ 592654359Sroberto 592754359Sroberto/* 592854359Sroberto * History: 592954359Sroberto * 593054359Sroberto * refclock_parse.c,v 5931280849Scy * Revision 4.81 2009/05/01 10:15:29 kardel 5932280849Scy * use new refclock_ppsapi interface 5933280849Scy * 5934182007Sroberto * Revision 4.80 2007/08/11 12:06:29 kardel 5935182007Sroberto * update comments wrt/ to PPS 5936182007Sroberto * 5937182007Sroberto * Revision 4.79 2007/08/11 11:52:23 kardel 5938182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor 5939182007Sroberto * 5940182007Sroberto * Revision 4.78 2006/12/22 20:08:27 kardel 5941182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5942182007Sroberto * 5943182007Sroberto * Revision 4.77 2006/08/05 07:44:49 kardel 5944182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5945182007Sroberto * 5946182007Sroberto * Revision 4.76 2006/06/22 18:40:47 kardel 5947182007Sroberto * clean up signedness (gcc 4) 5948182007Sroberto * 5949182007Sroberto * Revision 4.75 2006/06/22 16:58:10 kardel 5950182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5951182007Sroberto * the PPS offset. Fix sign of offset passed to kernel. 5952182007Sroberto * 5953182007Sroberto * Revision 4.74 2006/06/18 21:18:37 kardel 5954182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref 5955182007Sroberto * 5956182007Sroberto * Revision 4.73 2006/05/26 14:23:46 kardel 5957182007Sroberto * cleanup of copyright info 5958182007Sroberto * 5959182007Sroberto * Revision 4.72 2006/05/26 14:19:43 kardel 5960182007Sroberto * cleanup of ioctl cruft 5961182007Sroberto * 5962182007Sroberto * Revision 4.71 2006/05/26 14:15:57 kardel 5963182007Sroberto * delay adding refclock to async refclock io after all initializations 5964182007Sroberto * 5965182007Sroberto * Revision 4.70 2006/05/25 18:20:50 kardel 5966182007Sroberto * bug #619 5967182007Sroberto * terminate parse io engine after de-registering 5968182007Sroberto * from refclock io engine 5969182007Sroberto * 5970182007Sroberto * Revision 4.69 2006/05/25 17:28:02 kardel 5971182007Sroberto * complete refclock io structure initialization *before* inserting it into the 5972182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619) 5973182007Sroberto * 5974182007Sroberto * Revision 4.68 2006/05/01 17:02:51 kardel 5975182007Sroberto * copy receiver method also for newlwy created receive buffers 5976182007Sroberto * 5977182007Sroberto * Revision 4.67 2006/05/01 14:37:29 kardel 5978182007Sroberto * If an input buffer parses into more than one message do insert the 5979182007Sroberto * parsed message in a new input buffer instead of processing it 5980182007Sroberto * directly. This avoids deed complicated processing in signal 5981182007Sroberto * handling. 5982182007Sroberto * 5983182007Sroberto * Revision 4.66 2006/03/18 00:45:30 kardel 5984182007Sroberto * coverity fixes found in NetBSD coverity scan 5985182007Sroberto * 5986182007Sroberto * Revision 4.65 2006/01/26 06:08:33 kardel 5987182007Sroberto * output errno on PPS setup failure 5988182007Sroberto * 5989182007Sroberto * Revision 4.64 2005/11/09 20:44:47 kardel 5990182007Sroberto * utilize full PPS timestamp resolution from PPS API 5991182007Sroberto * 5992182007Sroberto * Revision 4.63 2005/10/07 22:10:25 kardel 5993182007Sroberto * bounded buffer implementation 5994182007Sroberto * 5995182007Sroberto * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 5996182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 5997182007Sroberto * replace almost all str* and *printf functions be their buffer bounded 5998182007Sroberto * counterparts 5999182007Sroberto * 6000182007Sroberto * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 6001182007Sroberto * limit re-set rate of trimble clocks 6002182007Sroberto * 6003182007Sroberto * Revision 4.62 2005/08/06 17:40:00 kardel 6004182007Sroberto * cleanup size handling wrt/ to buffer boundaries 6005182007Sroberto * 6006182007Sroberto * Revision 4.61 2005/07/27 21:16:19 kardel 6007182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 6008182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of 6009182007Sroberto * the DCF77 clocks. 6010182007Sroberto * 6011182007Sroberto * Revision 4.60 2005/07/17 21:14:44 kardel 6012182007Sroberto * change contents of version string to include the RCS/CVS Id 6013182007Sroberto * 6014182007Sroberto * Revision 4.59 2005/07/06 06:56:38 kardel 6015182007Sroberto * syntax error 6016182007Sroberto * 6017182007Sroberto * Revision 4.58 2005/07/04 13:10:40 kardel 6018182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup 6019182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 6020182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and 6021182007Sroberto * varying structure element sizes 6022182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers 6023182007Sroberto * 6024182007Sroberto * Revision 4.57 2005/06/25 09:25:19 kardel 6025182007Sroberto * sort out log output sequence 6026182007Sroberto * 6027182007Sroberto * Revision 4.56 2005/06/14 21:47:27 kardel 6028182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel) 6029182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 6030182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state 6031182007Sroberto * 6032182007Sroberto * Revision 4.55 2005/06/02 21:28:31 kardel 6033182007Sroberto * clarify trust logic 6034182007Sroberto * 6035182007Sroberto * Revision 4.54 2005/06/02 17:06:49 kardel 6036182007Sroberto * change status reporting to use fixed refclock_report() 6037182007Sroberto * 6038182007Sroberto * Revision 4.53 2005/06/02 16:33:31 kardel 6039182007Sroberto * fix acceptance of clocks unsync clocks right at start 6040182007Sroberto * 6041182007Sroberto * Revision 4.52 2005/05/26 21:55:06 kardel 6042182007Sroberto * cleanup status reporting 6043182007Sroberto * 6044182007Sroberto * Revision 4.51 2005/05/26 19:19:14 kardel 6045182007Sroberto * implement fast refclock startup 6046182007Sroberto * 6047182007Sroberto * Revision 4.50 2005/04/16 20:51:35 kardel 6048280849Scy * set hardpps_enable = 1 when binding a kernel PPS source 6049182007Sroberto * 6050182007Sroberto * Revision 4.49 2005/04/16 17:29:26 kardel 6051182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks 6052182007Sroberto * 6053182007Sroberto * Revision 4.48 2005/04/16 16:22:27 kardel 6054182007Sroberto * bk sync 20050415 ntp-dev 6055182007Sroberto * 6056182007Sroberto * Revision 4.47 2004/11/29 10:42:48 kardel 6057182007Sroberto * bk sync ntp-dev 20041129 6058182007Sroberto * 6059182007Sroberto * Revision 4.46 2004/11/29 10:26:29 kardel 6060182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 6061182007Sroberto * 6062182007Sroberto * Revision 4.45 2004/11/14 20:53:20 kardel 6063182007Sroberto * clear PPS flags after using them 6064182007Sroberto * 6065182007Sroberto * Revision 4.44 2004/11/14 15:29:41 kardel 6066182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style 6067182007Sroberto * 6068182007Sroberto * Revision 4.43 2001/05/26 22:53:16 kardel 6069182007Sroberto * 20010526 reconcilation 6070182007Sroberto * 6071182007Sroberto * Revision 4.42 2000/05/14 15:31:51 kardel 6072182007Sroberto * PPSAPI && RAWDCF modemline support 6073182007Sroberto * 6074182007Sroberto * Revision 4.41 2000/04/09 19:50:45 kardel 6075182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1 6076182007Sroberto * 6077182007Sroberto * Revision 4.40 2000/04/09 15:27:55 kardel 6078182007Sroberto * modem line fiddle in rawdcf_init_2 6079182007Sroberto * 6080182007Sroberto * Revision 4.39 2000/03/18 09:16:55 kardel 6081182007Sroberto * PPSAPI integration 6082182007Sroberto * 6083182007Sroberto * Revision 4.38 2000/03/05 20:25:06 kardel 6084182007Sroberto * support PPSAPI 6085182007Sroberto * 6086182007Sroberto * Revision 4.37 2000/03/05 20:11:14 kardel 6087182007Sroberto * 4.0.99g reconcilation 6088182007Sroberto * 608956746Sroberto * Revision 4.36 1999/11/28 17:18:20 kardel 609056746Sroberto * disabled burst mode 609156746Sroberto * 609256746Sroberto * Revision 4.35 1999/11/28 09:14:14 kardel 609356746Sroberto * RECON_4_0_98F 609456746Sroberto * 609556746Sroberto * Revision 4.34 1999/05/14 06:08:05 kardel 609656746Sroberto * store current_time in a suitable container (u_long) 609756746Sroberto * 609856746Sroberto * Revision 4.33 1999/05/13 21:48:38 kardel 609956746Sroberto * double the no response timeout interval 610056746Sroberto * 610156746Sroberto * Revision 4.32 1999/05/13 20:09:13 kardel 610256746Sroberto * complain only about missing polls after a full poll interval 610356746Sroberto * 610456746Sroberto * Revision 4.31 1999/05/13 19:59:32 kardel 610556746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF 610656746Sroberto * 610756746Sroberto * Revision 4.30 1999/02/28 20:36:43 kardel 610856746Sroberto * fixed printf fmt 610956746Sroberto * 611054359Sroberto * Revision 4.29 1999/02/28 19:58:23 kardel 611154359Sroberto * updated copyright information 611254359Sroberto * 611354359Sroberto * Revision 4.28 1999/02/28 19:01:50 kardel 611454359Sroberto * improved debug out on sent Meinberg messages 611554359Sroberto * 611654359Sroberto * Revision 4.27 1999/02/28 18:05:55 kardel 611754359Sroberto * no linux/ppsclock.h stuff 611854359Sroberto * 611954359Sroberto * Revision 4.26 1999/02/28 15:27:27 kardel 612054359Sroberto * wharton clock integration 612154359Sroberto * 612254359Sroberto * Revision 4.25 1999/02/28 14:04:46 kardel 612354359Sroberto * added missing double quotes to UTC information string 612454359Sroberto * 612554359Sroberto * Revision 4.24 1999/02/28 12:06:50 kardel 612654359Sroberto * (parse_control): using gmprettydate instead of prettydate() 612754359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information 612854359Sroberto * (gps16x_message): changed to use mk_utcinfo() 612954359Sroberto * (trimbletsip_message): changed to use mk_utcinfo() 613054359Sroberto * ignoring position information in unsynchronized mode 613154359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 613254359Sroberto * 613354359Sroberto * Revision 4.23 1999/02/23 19:47:53 kardel 613454359Sroberto * fixed #endifs 613554359Sroberto * (stream_receive): fixed formats 613654359Sroberto * 613754359Sroberto * Revision 4.22 1999/02/22 06:21:02 kardel 613854359Sroberto * use new autoconfig symbols 613954359Sroberto * 614054359Sroberto * Revision 4.21 1999/02/21 12:18:13 kardel 614154359Sroberto * 4.91f reconcilation 614254359Sroberto * 614354359Sroberto * Revision 4.20 1999/02/21 10:53:36 kardel 614454359Sroberto * initial Linux PPSkit version 614554359Sroberto * 614654359Sroberto * Revision 4.19 1999/02/07 09:10:45 kardel 614754359Sroberto * clarify STREAMS mitigation rules in comment 614854359Sroberto * 614954359Sroberto * Revision 4.18 1998/12/20 23:45:34 kardel 615054359Sroberto * fix types and warnings 615154359Sroberto * 615254359Sroberto * Revision 4.17 1998/11/15 21:24:51 kardel 615354359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG 615454359Sroberto * is not defined 615554359Sroberto * 615654359Sroberto * Revision 4.16 1998/11/15 20:28:17 kardel 615754359Sroberto * Release 4.0.73e13 reconcilation 615854359Sroberto * 615954359Sroberto * Revision 4.15 1998/08/22 21:56:08 kardel 616054359Sroberto * fixed IO handling for non-STREAM IO 616154359Sroberto * 616254359Sroberto * Revision 4.14 1998/08/16 19:00:48 kardel 616354359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 616454359Sroberto * made uval a local variable (killed one of the last globals) 616554359Sroberto * (sendetx): added logging of messages when in debug mode 616654359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization 616754359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation 616854359Sroberto * (trimbletsip_message): extended message interpretation 616954359Sroberto * (getdbl): fixed data conversion 617054359Sroberto * 617154359Sroberto * Revision 4.13 1998/08/09 22:29:13 kardel 617254359Sroberto * Trimble TSIP support 617354359Sroberto * 617454359Sroberto * Revision 4.12 1998/07/11 10:05:34 kardel 617554359Sroberto * Release 4.0.73d reconcilation 617654359Sroberto * 617754359Sroberto * Revision 4.11 1998/06/14 21:09:42 kardel 617854359Sroberto * Sun acc cleanup 617954359Sroberto * 618054359Sroberto * Revision 4.10 1998/06/13 12:36:45 kardel 618154359Sroberto * signed/unsigned, name clashes 618254359Sroberto * 618354359Sroberto * Revision 4.9 1998/06/12 15:30:00 kardel 618454359Sroberto * prototype fixes 618554359Sroberto * 618654359Sroberto * Revision 4.8 1998/06/12 11:19:42 kardel 618754359Sroberto * added direct input processing routine for refclocks in 618854359Sroberto * order to avaiod that single character io gobbles up all 618954359Sroberto * receive buffers and drops input data. (Problem started 619054359Sroberto * with fast machines so a character a buffer was possible 619154359Sroberto * one of the few cases where faster machines break existing 619254359Sroberto * allocation algorithms) 619354359Sroberto * 619454359Sroberto * Revision 4.7 1998/06/06 18:35:20 kardel 619554359Sroberto * (parse_start): added BURST mode initialisation 619654359Sroberto * 619754359Sroberto * Revision 4.6 1998/05/27 06:12:46 kardel 619854359Sroberto * RAWDCF_BASEDELAY default added 619954359Sroberto * old comment removed 620054359Sroberto * casts for ioctl() 620154359Sroberto * 620254359Sroberto * Revision 4.5 1998/05/25 22:05:09 kardel 620354359Sroberto * RAWDCF_SETDTR option removed 620454359Sroberto * clock type 14 attempts to set DTR for 620554359Sroberto * power supply of RAWDCF receivers 620654359Sroberto * 620754359Sroberto * Revision 4.4 1998/05/24 16:20:47 kardel 620854359Sroberto * updated comments referencing Meinberg clocks 620954359Sroberto * added RAWDCF clock with DTR set option as type 14 621054359Sroberto * 621154359Sroberto * Revision 4.3 1998/05/24 10:48:33 kardel 621254359Sroberto * calibrated CONRAD RAWDCF default fudge factor 621354359Sroberto * 621454359Sroberto * Revision 4.2 1998/05/24 09:59:35 kardel 621554359Sroberto * corrected version information (ntpq support) 621654359Sroberto * 621754359Sroberto * Revision 4.1 1998/05/24 09:52:31 kardel 621854359Sroberto * use fixed format only (new IO model) 621954359Sroberto * output debug to stdout instead of msyslog() 622054359Sroberto * don't include >"< in ASCII output in order not to confuse 622154359Sroberto * ntpq parsing 622254359Sroberto * 622354359Sroberto * Revision 4.0 1998/04/10 19:52:11 kardel 622454359Sroberto * Start 4.0 release version numbering 622554359Sroberto * 622654359Sroberto * Revision 1.2 1998/04/10 19:28:04 kardel 622754359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 622854359Sroberto * derived from 3.105.1.2 from V3 tree 622954359Sroberto * 623054359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 623154359Sroberto * 623254359Sroberto */ 6233