154359Sroberto/* 2182007Sroberto * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp 354359Sroberto * 4182007Sroberto * refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp 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 * 18182007Sroberto * Copyright (c) 1995-2007 by Frank Kardel <kardel <AT> ntp.org> 1954359Sroberto * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit�t Erlangen-N�rnberg, 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 5154359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) 5254359Sroberto 5354359Sroberto/* 5454359Sroberto * This driver currently provides the support for 5554359Sroberto * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF) 5654359Sroberto * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF) 5754359Sroberto * - Meinberg receiver DCF77 PZF 509 (DCF) 5854359Sroberto * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) 5954359Sroberto * - IGEL CLOCK (DCF) 6054359Sroberto * - ELV DCF7000 (DCF) 6154359Sroberto * - Schmid clock (DCF) 6254359Sroberto * - Conrad DCF77 receiver module (DCF) 6354359Sroberto * - FAU DCF77 NTP receiver (TimeBrick) (DCF) 64182007Sroberto * - WHARTON 400A Series clock (DCF) 6554359Sroberto * 6654359Sroberto * - Meinberg GPS166/GPS167 (GPS) 6754359Sroberto * - Trimble (TSIP and TAIP protocol) (GPS) 6854359Sroberto * 6954359Sroberto * - RCC8000 MSF Receiver (MSF) 7054359Sroberto * - VARITEXT clock (MSF) 7154359Sroberto */ 7254359Sroberto 7354359Sroberto/* 7454359Sroberto * Meinberg receivers are usually connected via a 7554359Sroberto * 9600 baud serial line 7654359Sroberto * 7754359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp 7854359Sroberto * format. The firmware release is Uni-Erlangen. 7954359Sroberto * 8054359Sroberto * Meinberg generic receiver setup: 8154359Sroberto * output time code every second 8254359Sroberto * Baud rate 9600 7E2S 8354359Sroberto * 8454359Sroberto * Meinberg GPS16x setup: 8554359Sroberto * output time code every second 8654359Sroberto * Baudrate 19200 8N1 8754359Sroberto * 8854359Sroberto * This software supports the standard data formats used 8954359Sroberto * in Meinberg receivers. 9054359Sroberto * 9154359Sroberto * Special software versions are only sensible for the 9254359Sroberto * GPS 16x family of receivers. 9354359Sroberto * 9454359Sroberto * Meinberg can be reached via: http://www.meinberg.de/ 9554359Sroberto */ 9654359Sroberto 9754359Sroberto#include "ntpd.h" 9854359Sroberto#include "ntp_refclock.h" 9954359Sroberto#include "ntp_unixtime.h" /* includes <sys/time.h> */ 10054359Sroberto#include "ntp_control.h" 101182007Sroberto#include "ntp_string.h" 10254359Sroberto 10354359Sroberto#include <stdio.h> 10454359Sroberto#include <ctype.h> 10554359Sroberto#ifndef TM_IN_SYS_TIME 10654359Sroberto# include <time.h> 10754359Sroberto#endif 10854359Sroberto 109182007Sroberto#ifdef HAVE_UNISTD_H 110182007Sroberto# include <unistd.h> 111182007Sroberto#endif 112182007Sroberto 11354359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) 11454359Sroberto# include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" 11554359Sroberto#endif 11654359Sroberto 11754359Sroberto#ifdef STREAM 11854359Sroberto# include <sys/stream.h> 11954359Sroberto# include <sys/stropts.h> 12054359Sroberto#endif 12154359Sroberto 12254359Sroberto#ifdef HAVE_TERMIOS 12354359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 12454359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 12554359Sroberto# undef HAVE_SYSV_TTYS 12654359Sroberto#endif 12754359Sroberto 12854359Sroberto#ifdef HAVE_SYSV_TTYS 12954359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) 13054359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) 13154359Sroberto#endif 13254359Sroberto 13354359Sroberto#ifdef HAVE_BSD_TTYS 13454359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */ 13554359Sroberto# include "Bletch: BSD TTY not currently supported" 13654359Sroberto#endif 13754359Sroberto 13854359Sroberto#ifdef HAVE_SYS_IOCTL_H 13954359Sroberto# include <sys/ioctl.h> 14054359Sroberto#endif 14154359Sroberto 142182007Sroberto#ifdef HAVE_PPSAPI 143182007Sroberto# include "ppsapi_timepps.h" 144182007Sroberto#endif 145182007Sroberto 14654359Sroberto#ifdef PPS 147182007Sroberto# ifdef HAVE_SYS_PPSCLOCK_H 148182007Sroberto# include <sys/ppsclock.h> 149182007Sroberto# endif 150182007Sroberto# ifdef HAVE_TIO_SERIAL_STUFF 151182007Sroberto# include <linux/serial.h> 152182007Sroberto# endif 15354359Sroberto#endif 154182007Sroberto 155182007Sroberto#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR)) 156182007Sroberto#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR)) 157182007Sroberto 158182007Sroberto/* 159182007Sroberto * document type of PPS interfacing - copy of ifdef mechanism in local_input() 160182007Sroberto */ 161182007Sroberto#undef PPS_METHOD 162182007Sroberto 163182007Sroberto#ifdef HAVE_PPSAPI 164182007Sroberto#define PPS_METHOD "PPS API" 165182007Sroberto#else 166182007Sroberto#ifdef TIOCDCDTIMESTAMP 167182007Sroberto#define PPS_METHOD "TIOCDCDTIMESTAMP" 168182007Sroberto#else /* TIOCDCDTIMESTAMP */ 169182007Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 170182007Sroberto#ifdef HAVE_CIOGETEV 171182007Sroberto#define PPS_METHOD "CIOGETEV" 17254359Sroberto#endif 173182007Sroberto#ifdef HAVE_TIOCGPPSEV 174182007Sroberto#define PPS_METHOD "TIOCGPPSEV" 17554359Sroberto#endif 176182007Sroberto#endif 177182007Sroberto#endif /* TIOCDCDTIMESTAMP */ 178182007Sroberto#endif /* HAVE_PPSAPI */ 17954359Sroberto 18054359Sroberto#include "ntp_io.h" 18154359Sroberto#include "ntp_stdlib.h" 18254359Sroberto 18354359Sroberto#include "parse.h" 18454359Sroberto#include "mbg_gps166.h" 18554359Sroberto#include "trimble.h" 18654359Sroberto#include "binio.h" 18754359Sroberto#include "ascii.h" 18854359Sroberto#include "ieee754io.h" 189182007Sroberto#include "recvbuff.h" 19054359Sroberto 191182007Srobertostatic char rcsid[] = "refclock_parse.c,v 4.80 2007/08/11 12:06:29 kardel Exp"; 19254359Sroberto 19354359Sroberto/**=========================================================================== 19454359Sroberto ** external interface to ntp mechanism 19554359Sroberto **/ 19654359Sroberto 19754359Srobertostatic int parse_start P((int, struct peer *)); 19854359Srobertostatic void parse_shutdown P((int, struct peer *)); 19954359Srobertostatic void parse_poll P((int, struct peer *)); 20054359Srobertostatic void parse_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); 20154359Sroberto 20254359Srobertostruct refclock refclock_parse = { 20354359Sroberto parse_start, 20454359Sroberto parse_shutdown, 20554359Sroberto parse_poll, 20654359Sroberto parse_control, 207182007Sroberto noentry, 208182007Sroberto noentry, 20954359Sroberto NOFLAGS 21054359Sroberto}; 21154359Sroberto 21254359Sroberto/* 21354359Sroberto * Definitions 21454359Sroberto */ 21554359Sroberto#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ 21654359Sroberto#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ 217182007Sroberto#define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */ 21854359Sroberto 21954359Sroberto#undef ABS 22054359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) 22154359Sroberto 222182007Sroberto#define PARSE_HARDPPS_DISABLE 0 223182007Sroberto#define PARSE_HARDPPS_ENABLE 1 224182007Sroberto 22554359Sroberto/**=========================================================================== 22654359Sroberto ** function vector for dynamically binding io handling mechanism 22754359Sroberto **/ 22854359Sroberto 22954359Srobertostruct parseunit; /* to keep inquiring minds happy */ 23054359Sroberto 23154359Srobertotypedef struct bind 23254359Sroberto{ 23354359Sroberto const char *bd_description; /* name of type of binding */ 23454359Sroberto int (*bd_init) P((struct parseunit *)); /* initialize */ 23554359Sroberto void (*bd_end) P((struct parseunit *)); /* end */ 23654359Sroberto int (*bd_setcs) P((struct parseunit *, parsectl_t *)); /* set character size */ 23754359Sroberto int (*bd_disable) P((struct parseunit *)); /* disable */ 23854359Sroberto int (*bd_enable) P((struct parseunit *)); /* enable */ 23954359Sroberto int (*bd_getfmt) P((struct parseunit *, parsectl_t *)); /* get format */ 24054359Sroberto int (*bd_setfmt) P((struct parseunit *, parsectl_t *)); /* setfmt */ 24154359Sroberto int (*bd_timecode) P((struct parseunit *, parsectl_t *)); /* get time code */ 24254359Sroberto void (*bd_receive) P((struct recvbuf *)); /* receive operation */ 24354359Sroberto int (*bd_io_input) P((struct recvbuf *)); /* input operation */ 24454359Sroberto} bind_t; 24554359Sroberto 24654359Sroberto#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) 24754359Sroberto#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) 24854359Sroberto#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) 24954359Sroberto#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) 25054359Sroberto#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) 25154359Sroberto#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) 25254359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) 25354359Sroberto 25454359Sroberto/* 25554359Sroberto * io modes 25654359Sroberto */ 25754359Sroberto#define PARSE_F_PPSPPS 0x0001 /* use loopfilter PPS code (CIOGETEV) */ 25854359Sroberto#define PARSE_F_PPSONSECOND 0x0002 /* PPS pulses are on second */ 25954359Sroberto 26054359Sroberto 26154359Sroberto/**=========================================================================== 26254359Sroberto ** error message regression handling 26354359Sroberto ** 26454359Sroberto ** there are quite a few errors that can occur in rapid succession such as 26554359Sroberto ** noisy input data or no data at all. in order to reduce the amount of 26654359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit 26754359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a 26854359Sroberto ** configurable number of messages is displayed that way, we move on to the 26954359Sroberto ** next time unit / count for that class. a count of messages that have been 27054359Sroberto ** suppressed is held and displayed whenever a corresponding message is 27154359Sroberto ** displayed. the time units for a message class will also be displayed. 27254359Sroberto ** whenever an error condition clears we reset the error message state, 27354359Sroberto ** thus we would still generate much output on pathological conditions 27454359Sroberto ** where the system oscillates between OK and NOT OK states. coping 27554359Sroberto ** with that condition is currently considered too complicated. 27654359Sroberto **/ 27754359Sroberto 27854359Sroberto#define ERR_ALL (unsigned)~0 /* "all" errors */ 27954359Sroberto#define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ 28054359Sroberto#define ERR_NODATA (unsigned)1 /* no input data */ 28154359Sroberto#define ERR_BADIO (unsigned)2 /* read/write/select errors */ 28254359Sroberto#define ERR_BADSTATUS (unsigned)3 /* unsync states */ 28354359Sroberto#define ERR_BADEVENT (unsigned)4 /* non nominal events */ 28454359Sroberto#define ERR_INTERNAL (unsigned)5 /* internal error */ 28554359Sroberto#define ERR_CNT (unsigned)(ERR_INTERNAL+1) 28654359Sroberto 28754359Sroberto#define ERR(_X_) if (list_err(parse, (_X_))) 28854359Sroberto 28954359Srobertostruct errorregression 29054359Sroberto{ 29154359Sroberto u_long err_count; /* number of repititions per class */ 29254359Sroberto u_long err_delay; /* minimum delay between messages */ 29354359Sroberto}; 29454359Sroberto 29554359Srobertostatic struct errorregression 29654359Srobertoerr_baddata[] = /* error messages for bad input data */ 29754359Sroberto{ 29854359Sroberto { 1, 0 }, /* output first message immediately */ 29954359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 30054359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 30154359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 30254359Sroberto}; 30354359Sroberto 30454359Srobertostatic struct errorregression 30554359Srobertoerr_nodata[] = /* error messages for missing input data */ 30654359Sroberto{ 30754359Sroberto { 1, 0 }, /* output first message immediately */ 30854359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 30954359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 31054359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 31154359Sroberto}; 31254359Sroberto 31354359Srobertostatic struct errorregression 31454359Srobertoerr_badstatus[] = /* unsynchronized state messages */ 31554359Sroberto{ 31654359Sroberto { 1, 0 }, /* output first message immediately */ 31754359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 31854359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 31954359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 32054359Sroberto}; 32154359Sroberto 32254359Srobertostatic struct errorregression 32354359Srobertoerr_badio[] = /* io failures (bad reads, selects, ...) */ 32454359Sroberto{ 32554359Sroberto { 1, 0 }, /* output first message immediately */ 32654359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 32754359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 32854359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 32954359Sroberto}; 33054359Sroberto 33154359Srobertostatic struct errorregression 33254359Srobertoerr_badevent[] = /* non nominal events */ 33354359Sroberto{ 33454359Sroberto { 20, 0 }, /* output first message immediately */ 33554359Sroberto { 6, 60 }, /* output next five messages in 60 second intervals */ 33654359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 33754359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 33854359Sroberto}; 33954359Sroberto 34054359Srobertostatic struct errorregression 34154359Srobertoerr_internal[] = /* really bad things - basically coding/OS errors */ 34254359Sroberto{ 34354359Sroberto { 0, 0 }, /* output all messages immediately */ 34454359Sroberto}; 34554359Sroberto 34654359Srobertostatic struct errorregression * 34754359Srobertoerr_tbl[] = 34854359Sroberto{ 34954359Sroberto err_baddata, 35054359Sroberto err_nodata, 35154359Sroberto err_badio, 35254359Sroberto err_badstatus, 35354359Sroberto err_badevent, 35454359Sroberto err_internal 35554359Sroberto}; 35654359Sroberto 35754359Srobertostruct errorinfo 35854359Sroberto{ 35954359Sroberto u_long err_started; /* begin time (ntp) of error condition */ 36054359Sroberto u_long err_last; /* last time (ntp) error occurred */ 36154359Sroberto u_long err_cnt; /* number of error repititions */ 36254359Sroberto u_long err_suppressed; /* number of suppressed messages */ 36354359Sroberto struct errorregression *err_stage; /* current error stage */ 36454359Sroberto}; 36554359Sroberto 36654359Sroberto/**=========================================================================== 36754359Sroberto ** refclock instance data 36854359Sroberto **/ 36954359Sroberto 37054359Srobertostruct parseunit 37154359Sroberto{ 37254359Sroberto /* 37354359Sroberto * NTP management 37454359Sroberto */ 37554359Sroberto struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ 37654359Sroberto struct refclockproc *generic; /* backlink to refclockproc structure */ 37754359Sroberto 37854359Sroberto /* 37954359Sroberto * PARSE io 38054359Sroberto */ 38154359Sroberto bind_t *binding; /* io handling binding */ 38254359Sroberto 38354359Sroberto /* 38454359Sroberto * parse state 38554359Sroberto */ 38654359Sroberto parse_t parseio; /* io handling structure (user level parsing) */ 38754359Sroberto 38854359Sroberto /* 38954359Sroberto * type specific parameters 39054359Sroberto */ 39154359Sroberto struct parse_clockinfo *parse_type; /* link to clock description */ 39254359Sroberto 39354359Sroberto /* 39454359Sroberto * clock state handling/reporting 39554359Sroberto */ 39654359Sroberto u_char flags; /* flags (leap_control) */ 39754359Sroberto u_long lastchange; /* time (ntp) when last state change accured */ 39854359Sroberto u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ 39956746Sroberto u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */ 40054359Sroberto u_short lastformat; /* last format used */ 40154359Sroberto u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ 402182007Sroberto u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */ 403182007Sroberto double ppsphaseadjust; /* phase adjustment of PPS time stamp */ 404182007Sroberto u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ 40554359Sroberto u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ 406182007Sroberto int ppsfd; /* fd to ise for PPS io */ 407182007Sroberto#ifdef HAVE_PPSAPI 408182007Sroberto pps_handle_t ppshandle; /* store PPSAPI handle */ 409182007Sroberto pps_params_t ppsparams; /* current PPS parameters */ 410182007Sroberto int hardppsstate; /* current hard pps state */ 411182007Sroberto#endif 412182007Sroberto parsetime_t timedata; /* last (parse module) data */ 41354359Sroberto void *localdata; /* optional local, receiver-specific data */ 41454359Sroberto unsigned long localstate; /* private local state */ 41554359Sroberto struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ 41654359Sroberto struct ctl_var *kv; /* additional pseudo variables */ 41754359Sroberto u_long laststatistic; /* time when staticstics where output */ 41854359Sroberto}; 41954359Sroberto 42054359Sroberto 42154359Sroberto/**=========================================================================== 42254359Sroberto ** Clockinfo section all parameter for specific clock types 42354359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters 42454359Sroberto **/ 42554359Sroberto 42654359Srobertostatic void poll_dpoll P((struct parseunit *)); 42754359Srobertostatic void poll_poll P((struct peer *)); 42854359Srobertostatic int poll_init P((struct parseunit *)); 42954359Sroberto 43054359Srobertotypedef struct poll_info 43154359Sroberto{ 43254359Sroberto u_long rate; /* poll rate - once every "rate" seconds - 0 off */ 43354359Sroberto const char *string; /* string to send for polling */ 43454359Sroberto u_long count; /* number of characters in string */ 43554359Sroberto} poll_info_t; 43654359Sroberto 43754359Sroberto#define NO_CL_FLAGS 0 43854359Sroberto#define NO_POLL 0 43954359Sroberto#define NO_INIT 0 44054359Sroberto#define NO_END 0 44154359Sroberto#define NO_EVENT 0 442182007Sroberto#define NO_LCLDATA 0 44354359Sroberto#define NO_MESSAGE 0 44454359Sroberto#define NO_PPSDELAY 0 44554359Sroberto 44654359Sroberto#define DCF_ID "DCF" /* generic DCF */ 44754359Sroberto#define DCF_A_ID "DCFa" /* AM demodulation */ 44854359Sroberto#define DCF_P_ID "DCFp" /* psuedo random phase shift */ 44954359Sroberto#define GPS_ID "GPS" /* GPS receiver */ 45054359Sroberto 45154359Sroberto#define NOCLOCK_ROOTDELAY 0.0 45254359Sroberto#define NOCLOCK_BASEDELAY 0.0 45354359Sroberto#define NOCLOCK_DESCRIPTION 0 45454359Sroberto#define NOCLOCK_MAXUNSYNC 0 45554359Sroberto#define NOCLOCK_CFLAG 0 45654359Sroberto#define NOCLOCK_IFLAG 0 45754359Sroberto#define NOCLOCK_OFLAG 0 45854359Sroberto#define NOCLOCK_LFLAG 0 45954359Sroberto#define NOCLOCK_ID "TILT" 46054359Sroberto#define NOCLOCK_POLL NO_POLL 46154359Sroberto#define NOCLOCK_INIT NO_INIT 46254359Sroberto#define NOCLOCK_END NO_END 463182007Sroberto#define NOCLOCK_DATA NO_LCLDATA 46454359Sroberto#define NOCLOCK_FORMAT "" 46554359Sroberto#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 46654359Sroberto#define NOCLOCK_SAMPLES 0 46754359Sroberto#define NOCLOCK_KEEP 0 46854359Sroberto 46954359Sroberto#define DCF_TYPE CTL_SST_TS_LF 47054359Sroberto#define GPS_TYPE CTL_SST_TS_UHF 47154359Sroberto 47254359Sroberto/* 47354359Sroberto * receiver specific constants 47454359Sroberto */ 47554359Sroberto#define MBG_SPEED (B9600) 476182007Sroberto#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB) 47754359Sroberto#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) 47854359Sroberto#define MBG_OFLAG 0 47954359Sroberto#define MBG_LFLAG 0 48054359Sroberto#define MBG_FLAGS PARSE_F_PPSONSECOND 48154359Sroberto 48254359Sroberto/* 48354359Sroberto * Meinberg DCF77 receivers 48454359Sroberto */ 48554359Sroberto#define DCFUA31_ROOTDELAY 0.0 /* 0 */ 48654359Sroberto#define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ 48754359Sroberto#define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" 48854359Sroberto#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ 48954359Sroberto#define DCFUA31_SPEED MBG_SPEED 49054359Sroberto#define DCFUA31_CFLAG MBG_CFLAG 49154359Sroberto#define DCFUA31_IFLAG MBG_IFLAG 49254359Sroberto#define DCFUA31_OFLAG MBG_OFLAG 49354359Sroberto#define DCFUA31_LFLAG MBG_LFLAG 49454359Sroberto#define DCFUA31_SAMPLES 5 49554359Sroberto#define DCFUA31_KEEP 3 49654359Sroberto#define DCFUA31_FORMAT "Meinberg Standard" 49754359Sroberto 49854359Sroberto/* 49954359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver 50054359Sroberto */ 50154359Sroberto#define DCFPZF535_ROOTDELAY 0.0 50254359Sroberto#define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 50354359Sroberto#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" 50454359Sroberto#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours 50554359Sroberto * @ 5e-8df/f we have accumulated 50654359Sroberto * at most 2.16 ms (thus we move to 50754359Sroberto * NTP synchronisation */ 50854359Sroberto#define DCFPZF535_SPEED MBG_SPEED 50954359Sroberto#define DCFPZF535_CFLAG MBG_CFLAG 51054359Sroberto#define DCFPZF535_IFLAG MBG_IFLAG 51154359Sroberto#define DCFPZF535_OFLAG MBG_OFLAG 51254359Sroberto#define DCFPZF535_LFLAG MBG_LFLAG 51354359Sroberto#define DCFPZF535_SAMPLES 5 51454359Sroberto#define DCFPZF535_KEEP 3 51554359Sroberto#define DCFPZF535_FORMAT "Meinberg Standard" 51654359Sroberto 51754359Sroberto/* 51854359Sroberto * Meinberg DCF PZF535/OCXO receiver 51954359Sroberto */ 52054359Sroberto#define DCFPZF535OCXO_ROOTDELAY 0.0 52154359Sroberto#define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 52254359Sroberto#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" 52354359Sroberto#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 52454359Sroberto * @ 5e-9df/f we have accumulated 52554359Sroberto * at most an error of 1.73 ms 52654359Sroberto * (thus we move to NTP synchronisation) */ 52754359Sroberto#define DCFPZF535OCXO_SPEED MBG_SPEED 52854359Sroberto#define DCFPZF535OCXO_CFLAG MBG_CFLAG 52954359Sroberto#define DCFPZF535OCXO_IFLAG MBG_IFLAG 53054359Sroberto#define DCFPZF535OCXO_OFLAG MBG_OFLAG 53154359Sroberto#define DCFPZF535OCXO_LFLAG MBG_LFLAG 53254359Sroberto#define DCFPZF535OCXO_SAMPLES 5 53354359Sroberto#define DCFPZF535OCXO_KEEP 3 53454359Sroberto#define DCFPZF535OCXO_FORMAT "Meinberg Standard" 53554359Sroberto 53654359Sroberto/* 53754359Sroberto * Meinberg GPS16X receiver 53854359Sroberto */ 53954359Srobertostatic void gps16x_message P((struct parseunit *, parsetime_t *)); 54054359Srobertostatic int gps16x_poll_init P((struct parseunit *)); 54154359Sroberto 54254359Sroberto#define GPS16X_ROOTDELAY 0.0 /* nothing here */ 54354359Sroberto#define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 54454359Sroberto#define GPS16X_DESCRIPTION "Meinberg GPS16x receiver" 54554359Sroberto#define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 54654359Sroberto * @ 5e-9df/f we have accumulated 54754359Sroberto * at most an error of 1.73 ms 54854359Sroberto * (thus we move to NTP synchronisation) */ 54954359Sroberto#define GPS16X_SPEED B19200 55054359Sroberto#define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) 55154359Sroberto#define GPS16X_IFLAG (IGNBRK|IGNPAR) 55254359Sroberto#define GPS16X_OFLAG MBG_OFLAG 55354359Sroberto#define GPS16X_LFLAG MBG_LFLAG 55454359Sroberto#define GPS16X_POLLRATE 6 55554359Sroberto#define GPS16X_POLLCMD "" 55654359Sroberto#define GPS16X_CMDSIZE 0 55754359Sroberto 55854359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; 55954359Sroberto 56054359Sroberto#define GPS16X_INIT gps16x_poll_init 56154359Sroberto#define GPS16X_POLL 0 56254359Sroberto#define GPS16X_END 0 56354359Sroberto#define GPS16X_DATA ((void *)(&gps16x_pollinfo)) 56454359Sroberto#define GPS16X_MESSAGE gps16x_message 56554359Sroberto#define GPS16X_ID GPS_ID 56654359Sroberto#define GPS16X_FORMAT "Meinberg GPS Extended" 56754359Sroberto#define GPS16X_SAMPLES 5 56854359Sroberto#define GPS16X_KEEP 3 56954359Sroberto 57054359Sroberto/* 57154359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) 57254359Sroberto * 57354359Sroberto * This is really not the hottest clock - but before you have nothing ... 57454359Sroberto */ 57554359Sroberto#define DCF7000_ROOTDELAY 0.0 /* 0 */ 57654359Sroberto#define DCF7000_BASEDELAY 0.405 /* slow blow */ 57754359Sroberto#define DCF7000_DESCRIPTION "ELV DCF7000" 57854359Sroberto#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ 57954359Sroberto#define DCF7000_SPEED (B9600) 58054359Sroberto#define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) 58154359Sroberto#define DCF7000_IFLAG (IGNBRK) 58254359Sroberto#define DCF7000_OFLAG 0 58354359Sroberto#define DCF7000_LFLAG 0 58454359Sroberto#define DCF7000_SAMPLES 5 58554359Sroberto#define DCF7000_KEEP 3 58654359Sroberto#define DCF7000_FORMAT "ELV DCF7000" 58754359Sroberto 58854359Sroberto/* 58954359Sroberto * Schmid DCF Receiver Kit 59054359Sroberto * 59154359Sroberto * When the WSDCF clock is operating optimally we want the primary clock 59254359Sroberto * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer 59354359Sroberto * structure is set to 290 ms and we compute delays which are at least 59454359Sroberto * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format 59554359Sroberto */ 59654359Sroberto#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ 59754359Sroberto#define WS_POLLCMD "\163" 59854359Sroberto#define WS_CMDSIZE 1 59954359Sroberto 60054359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; 60154359Sroberto 60254359Sroberto#define WSDCF_INIT poll_init 60354359Sroberto#define WSDCF_POLL poll_dpoll 60454359Sroberto#define WSDCF_END 0 60554359Sroberto#define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) 60654359Sroberto#define WSDCF_ROOTDELAY 0.0 /* 0 */ 60754359Sroberto#define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ 60854359Sroberto#define WSDCF_DESCRIPTION "WS/DCF Receiver" 60954359Sroberto#define WSDCF_FORMAT "Schmid" 61054359Sroberto#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ 61154359Sroberto#define WSDCF_SPEED (B1200) 61254359Sroberto#define WSDCF_CFLAG (CS8|CREAD|CLOCAL) 61354359Sroberto#define WSDCF_IFLAG 0 61454359Sroberto#define WSDCF_OFLAG 0 61554359Sroberto#define WSDCF_LFLAG 0 61654359Sroberto#define WSDCF_SAMPLES 5 61754359Sroberto#define WSDCF_KEEP 3 61854359Sroberto 61954359Sroberto/* 62054359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants 62154359Sroberto */ 62254359Sroberto#define RAWDCF_FLAGS 0 62354359Sroberto#define RAWDCF_ROOTDELAY 0.0 /* 0 */ 62454359Sroberto#define RAWDCF_BASEDELAY 0.258 62554359Sroberto#define RAWDCF_FORMAT "RAW DCF77 Timecode" 62654359Sroberto#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ 62754359Sroberto#define RAWDCF_SPEED (B50) 62854359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ 62954359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */ 63054359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) 63154359Sroberto#else 63254359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) 63354359Sroberto#endif 63454359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ 63554359Sroberto# define RAWDCF_IFLAG 0 63654359Sroberto#else 63754359Sroberto# define RAWDCF_IFLAG (IGNPAR) 63854359Sroberto#endif 63954359Sroberto#define RAWDCF_OFLAG 0 64054359Sroberto#define RAWDCF_LFLAG 0 64154359Sroberto#define RAWDCF_SAMPLES 20 64254359Sroberto#define RAWDCF_KEEP 12 64354359Sroberto#define RAWDCF_INIT 0 64454359Sroberto 64554359Sroberto/* 64654359Sroberto * RAW DCF variants 64754359Sroberto */ 64854359Sroberto/* 64954359Sroberto * Conrad receiver 65054359Sroberto * 65154359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad 65254359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232 65354359Sroberto */ 65454359Sroberto#define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ 65554359Sroberto#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" 65654359Sroberto 657182007Sroberto/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */ 658182007Sroberto#define GUDE_EMC_USB_V20_SPEED (B4800) 659182007Sroberto#define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */ 660182007Sroberto#define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)" 661182007Sroberto 66254359Sroberto/* 66354359Sroberto * TimeBrick receiver 66454359Sroberto */ 66554359Sroberto#define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ 66654359Sroberto#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" 66754359Sroberto 66854359Sroberto/* 66954359Sroberto * IGEL:clock receiver 67054359Sroberto */ 67154359Sroberto#define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ 67254359Sroberto#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" 67354359Sroberto#define IGELCLOCK_SPEED (B1200) 67454359Sroberto#define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) 67554359Sroberto 67654359Sroberto/* 67754359Sroberto * RAWDCF receivers that need to be powered from DTR 67854359Sroberto * (like Expert mouse clock) 67954359Sroberto */ 68056746Srobertostatic int rawdcf_init_1 P((struct parseunit *)); 68156746Sroberto#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 68256746Sroberto#define RAWDCFDTRSET_INIT rawdcf_init_1 68354359Sroberto 68454359Sroberto/* 68556746Sroberto * RAWDCF receivers that need to be powered from 68656746Sroberto * DTR CLR and RTS SET 68754359Sroberto */ 68856746Srobertostatic int rawdcf_init_2 P((struct parseunit *)); 68956746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 69056746Sroberto#define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2 69154359Sroberto 69254359Sroberto/* 69354359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols) 69454359Sroberto */ 69554359Sroberto#ifndef TRIM_POLLRATE 69654359Sroberto#define TRIM_POLLRATE 0 /* only true direct polling */ 69754359Sroberto#endif 69854359Sroberto 69954359Sroberto#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" 70054359Sroberto#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) 70154359Sroberto 70254359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; 70354359Srobertostatic int trimbletaip_init P((struct parseunit *)); 70454359Srobertostatic void trimbletaip_event P((struct parseunit *, int)); 70554359Sroberto 70654359Sroberto/* query time & UTC correction data */ 70754359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; 70854359Sroberto 70954359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; 71054359Srobertostatic int trimbletsip_init P((struct parseunit *)); 71154359Srobertostatic void trimbletsip_end P((struct parseunit *)); 71254359Srobertostatic void trimbletsip_message P((struct parseunit *, parsetime_t *)); 71354359Srobertostatic void trimbletsip_event P((struct parseunit *, int)); 71454359Sroberto 71554359Sroberto#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ 716182007Sroberto#define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME 71754359Sroberto 71854359Sroberto#define TRIMBLETAIP_SPEED (B4800) 71954359Sroberto#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) 72054359Sroberto#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) 72154359Sroberto#define TRIMBLETAIP_OFLAG (OPOST|ONLCR) 72254359Sroberto#define TRIMBLETAIP_LFLAG (0) 72354359Sroberto 72454359Sroberto#define TRIMBLETSIP_SPEED (B9600) 72554359Sroberto#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) 72654359Sroberto#define TRIMBLETSIP_IFLAG (IGNBRK) 72754359Sroberto#define TRIMBLETSIP_OFLAG (0) 72854359Sroberto#define TRIMBLETSIP_LFLAG (ICANON) 72954359Sroberto 73054359Sroberto#define TRIMBLETSIP_SAMPLES 5 73154359Sroberto#define TRIMBLETSIP_KEEP 3 73254359Sroberto#define TRIMBLETAIP_SAMPLES 5 73354359Sroberto#define TRIMBLETAIP_KEEP 3 73454359Sroberto 73554359Sroberto#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) 73654359Sroberto#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) 73754359Sroberto 73854359Sroberto#define TRIMBLETAIP_POLL poll_dpoll 73954359Sroberto#define TRIMBLETSIP_POLL poll_dpoll 74054359Sroberto 74154359Sroberto#define TRIMBLETAIP_INIT trimbletaip_init 74254359Sroberto#define TRIMBLETSIP_INIT trimbletsip_init 74354359Sroberto 74454359Sroberto#define TRIMBLETAIP_EVENT trimbletaip_event 74554359Sroberto 74654359Sroberto#define TRIMBLETSIP_EVENT trimbletsip_event 74754359Sroberto#define TRIMBLETSIP_MESSAGE trimbletsip_message 74854359Sroberto 74954359Sroberto#define TRIMBLETAIP_END 0 75054359Sroberto#define TRIMBLETSIP_END trimbletsip_end 75154359Sroberto 75254359Sroberto#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) 75354359Sroberto#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) 75454359Sroberto 75554359Sroberto#define TRIMBLETAIP_ID GPS_ID 75654359Sroberto#define TRIMBLETSIP_ID GPS_ID 75754359Sroberto 75854359Sroberto#define TRIMBLETAIP_FORMAT "Trimble TAIP" 75954359Sroberto#define TRIMBLETSIP_FORMAT "Trimble TSIP" 76054359Sroberto 76154359Sroberto#define TRIMBLETAIP_ROOTDELAY 0x0 76254359Sroberto#define TRIMBLETSIP_ROOTDELAY 0x0 76354359Sroberto 76454359Sroberto#define TRIMBLETAIP_BASEDELAY 0.0 76554359Sroberto#define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ 76654359Sroberto 76754359Sroberto#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" 76854359Sroberto#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" 76954359Sroberto 77054359Sroberto#define TRIMBLETAIP_MAXUNSYNC 0 77154359Sroberto#define TRIMBLETSIP_MAXUNSYNC 0 77254359Sroberto 77354359Sroberto#define TRIMBLETAIP_EOL '<' 77454359Sroberto 77554359Sroberto/* 77654359Sroberto * RadioCode Clocks RCC 800 receiver 77754359Sroberto */ 77854359Sroberto#define RCC_POLLRATE 0 /* only true direct polling */ 77954359Sroberto#define RCC_POLLCMD "\r" 78054359Sroberto#define RCC_CMDSIZE 1 78154359Sroberto 78254359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; 78354359Sroberto#define RCC8000_FLAGS 0 78454359Sroberto#define RCC8000_POLL poll_dpoll 78554359Sroberto#define RCC8000_INIT poll_init 78654359Sroberto#define RCC8000_END 0 78754359Sroberto#define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) 78854359Sroberto#define RCC8000_ROOTDELAY 0.0 78954359Sroberto#define RCC8000_BASEDELAY 0.0 79054359Sroberto#define RCC8000_ID "MSF" 79154359Sroberto#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" 79254359Sroberto#define RCC8000_FORMAT "Radiocode RCC8000" 79354359Sroberto#define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ 79454359Sroberto#define RCC8000_SPEED (B2400) 79554359Sroberto#define RCC8000_CFLAG (CS8|CREAD|CLOCAL) 79654359Sroberto#define RCC8000_IFLAG (IGNBRK|IGNPAR) 79754359Sroberto#define RCC8000_OFLAG 0 79854359Sroberto#define RCC8000_LFLAG 0 79954359Sroberto#define RCC8000_SAMPLES 5 80054359Sroberto#define RCC8000_KEEP 3 80154359Sroberto 80254359Sroberto/* 80354359Sroberto * Hopf Radio clock 6021 Format 80454359Sroberto * 80554359Sroberto */ 80654359Sroberto#define HOPF6021_ROOTDELAY 0.0 80754359Sroberto#define HOPF6021_BASEDELAY 0.0 80854359Sroberto#define HOPF6021_DESCRIPTION "HOPF 6021" 80954359Sroberto#define HOPF6021_FORMAT "hopf Funkuhr 6021" 81054359Sroberto#define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ 81154359Sroberto#define HOPF6021_SPEED (B9600) 81254359Sroberto#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) 81354359Sroberto#define HOPF6021_IFLAG (IGNBRK|ISTRIP) 81454359Sroberto#define HOPF6021_OFLAG 0 81554359Sroberto#define HOPF6021_LFLAG 0 81654359Sroberto#define HOPF6021_FLAGS 0 81754359Sroberto#define HOPF6021_SAMPLES 5 81854359Sroberto#define HOPF6021_KEEP 3 81954359Sroberto 82054359Sroberto/* 82154359Sroberto * Diem's Computime Radio Clock Receiver 82254359Sroberto */ 82354359Sroberto#define COMPUTIME_FLAGS 0 82454359Sroberto#define COMPUTIME_ROOTDELAY 0.0 82554359Sroberto#define COMPUTIME_BASEDELAY 0.0 82654359Sroberto#define COMPUTIME_ID DCF_ID 82754359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver" 82854359Sroberto#define COMPUTIME_FORMAT "Diem's Computime Radio Clock" 82954359Sroberto#define COMPUTIME_TYPE DCF_TYPE 83054359Sroberto#define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 83154359Sroberto#define COMPUTIME_SPEED (B9600) 83254359Sroberto#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) 83354359Sroberto#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) 83454359Sroberto#define COMPUTIME_OFLAG 0 83554359Sroberto#define COMPUTIME_LFLAG 0 83654359Sroberto#define COMPUTIME_SAMPLES 5 83754359Sroberto#define COMPUTIME_KEEP 3 83854359Sroberto 83954359Sroberto/* 84054359Sroberto * Varitext Radio Clock Receiver 84154359Sroberto */ 84254359Sroberto#define VARITEXT_FLAGS 0 84354359Sroberto#define VARITEXT_ROOTDELAY 0.0 84454359Sroberto#define VARITEXT_BASEDELAY 0.0 84554359Sroberto#define VARITEXT_ID "MSF" 84654359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver" 84754359Sroberto#define VARITEXT_FORMAT "Varitext Radio Clock" 84854359Sroberto#define VARITEXT_TYPE DCF_TYPE 84954359Sroberto#define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 85054359Sroberto#define VARITEXT_SPEED (B9600) 85154359Sroberto#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) 85254359Sroberto#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ 85354359Sroberto#define VARITEXT_OFLAG 0 85454359Sroberto#define VARITEXT_LFLAG 0 85554359Sroberto#define VARITEXT_SAMPLES 32 85654359Sroberto#define VARITEXT_KEEP 20 85754359Sroberto 85854359Srobertostatic struct parse_clockinfo 85954359Sroberto{ 86054359Sroberto u_long cl_flags; /* operation flags (io modes) */ 86154359Sroberto void (*cl_poll) P((struct parseunit *)); /* active poll routine */ 86254359Sroberto int (*cl_init) P((struct parseunit *)); /* active poll init routine */ 86354359Sroberto void (*cl_event) P((struct parseunit *, int)); /* special event handling (e.g. reset clock) */ 86454359Sroberto void (*cl_end) P((struct parseunit *)); /* active poll end routine */ 86554359Sroberto void (*cl_message) P((struct parseunit *, parsetime_t *)); /* process a lower layer message */ 86654359Sroberto void *cl_data; /* local data area for "poll" mechanism */ 86754359Sroberto double cl_rootdelay; /* rootdelay */ 86854359Sroberto double cl_basedelay; /* current offset by which the RS232 86954359Sroberto time code is delayed from the actual time */ 87054359Sroberto const char *cl_id; /* ID code */ 87154359Sroberto const char *cl_description; /* device name */ 87254359Sroberto const char *cl_format; /* fixed format */ 87354359Sroberto u_char cl_type; /* clock type (ntp control) */ 874132451Sroberto u_long cl_maxunsync; /* time to trust oscillator after losing synch */ 87554359Sroberto u_long cl_speed; /* terminal input & output baudrate */ 87654359Sroberto u_long cl_cflag; /* terminal control flags */ 87754359Sroberto u_long cl_iflag; /* terminal input flags */ 87854359Sroberto u_long cl_oflag; /* terminal output flags */ 87954359Sroberto u_long cl_lflag; /* terminal local flags */ 88054359Sroberto u_long cl_samples; /* samples for median filter */ 88154359Sroberto u_long cl_keep; /* samples for median filter to keep */ 88254359Sroberto} parse_clockinfo[] = 88354359Sroberto{ 88454359Sroberto { /* mode 0 */ 88554359Sroberto MBG_FLAGS, 88654359Sroberto NO_POLL, 88754359Sroberto NO_INIT, 88854359Sroberto NO_EVENT, 88954359Sroberto NO_END, 89054359Sroberto NO_MESSAGE, 891182007Sroberto NO_LCLDATA, 89254359Sroberto DCFPZF535_ROOTDELAY, 89354359Sroberto DCFPZF535_BASEDELAY, 89454359Sroberto DCF_P_ID, 89554359Sroberto DCFPZF535_DESCRIPTION, 89654359Sroberto DCFPZF535_FORMAT, 89754359Sroberto DCF_TYPE, 89854359Sroberto DCFPZF535_MAXUNSYNC, 89954359Sroberto DCFPZF535_SPEED, 90054359Sroberto DCFPZF535_CFLAG, 90154359Sroberto DCFPZF535_IFLAG, 90254359Sroberto DCFPZF535_OFLAG, 90354359Sroberto DCFPZF535_LFLAG, 90454359Sroberto DCFPZF535_SAMPLES, 90554359Sroberto DCFPZF535_KEEP 90654359Sroberto }, 90754359Sroberto { /* mode 1 */ 90854359Sroberto MBG_FLAGS, 90954359Sroberto NO_POLL, 91054359Sroberto NO_INIT, 91154359Sroberto NO_EVENT, 91254359Sroberto NO_END, 91354359Sroberto NO_MESSAGE, 914182007Sroberto NO_LCLDATA, 91554359Sroberto DCFPZF535OCXO_ROOTDELAY, 91654359Sroberto DCFPZF535OCXO_BASEDELAY, 91754359Sroberto DCF_P_ID, 91854359Sroberto DCFPZF535OCXO_DESCRIPTION, 91954359Sroberto DCFPZF535OCXO_FORMAT, 92054359Sroberto DCF_TYPE, 92154359Sroberto DCFPZF535OCXO_MAXUNSYNC, 92254359Sroberto DCFPZF535OCXO_SPEED, 92354359Sroberto DCFPZF535OCXO_CFLAG, 92454359Sroberto DCFPZF535OCXO_IFLAG, 92554359Sroberto DCFPZF535OCXO_OFLAG, 92654359Sroberto DCFPZF535OCXO_LFLAG, 92754359Sroberto DCFPZF535OCXO_SAMPLES, 92854359Sroberto DCFPZF535OCXO_KEEP 92954359Sroberto }, 93054359Sroberto { /* mode 2 */ 93154359Sroberto MBG_FLAGS, 93254359Sroberto NO_POLL, 93354359Sroberto NO_INIT, 93454359Sroberto NO_EVENT, 93554359Sroberto NO_END, 93654359Sroberto NO_MESSAGE, 937182007Sroberto NO_LCLDATA, 93854359Sroberto DCFUA31_ROOTDELAY, 93954359Sroberto DCFUA31_BASEDELAY, 94054359Sroberto DCF_A_ID, 94154359Sroberto DCFUA31_DESCRIPTION, 94254359Sroberto DCFUA31_FORMAT, 94354359Sroberto DCF_TYPE, 94454359Sroberto DCFUA31_MAXUNSYNC, 94554359Sroberto DCFUA31_SPEED, 94654359Sroberto DCFUA31_CFLAG, 94754359Sroberto DCFUA31_IFLAG, 94854359Sroberto DCFUA31_OFLAG, 94954359Sroberto DCFUA31_LFLAG, 95054359Sroberto DCFUA31_SAMPLES, 95154359Sroberto DCFUA31_KEEP 95254359Sroberto }, 95354359Sroberto { /* mode 3 */ 95454359Sroberto MBG_FLAGS, 95554359Sroberto NO_POLL, 95654359Sroberto NO_INIT, 95754359Sroberto NO_EVENT, 95854359Sroberto NO_END, 95954359Sroberto NO_MESSAGE, 960182007Sroberto NO_LCLDATA, 96154359Sroberto DCF7000_ROOTDELAY, 96254359Sroberto DCF7000_BASEDELAY, 96354359Sroberto DCF_A_ID, 96454359Sroberto DCF7000_DESCRIPTION, 96554359Sroberto DCF7000_FORMAT, 96654359Sroberto DCF_TYPE, 96754359Sroberto DCF7000_MAXUNSYNC, 96854359Sroberto DCF7000_SPEED, 96954359Sroberto DCF7000_CFLAG, 97054359Sroberto DCF7000_IFLAG, 97154359Sroberto DCF7000_OFLAG, 97254359Sroberto DCF7000_LFLAG, 97354359Sroberto DCF7000_SAMPLES, 97454359Sroberto DCF7000_KEEP 97554359Sroberto }, 97654359Sroberto { /* mode 4 */ 97754359Sroberto NO_CL_FLAGS, 97854359Sroberto WSDCF_POLL, 97954359Sroberto WSDCF_INIT, 98054359Sroberto NO_EVENT, 98154359Sroberto WSDCF_END, 98254359Sroberto NO_MESSAGE, 98354359Sroberto WSDCF_DATA, 98454359Sroberto WSDCF_ROOTDELAY, 98554359Sroberto WSDCF_BASEDELAY, 98654359Sroberto DCF_A_ID, 98754359Sroberto WSDCF_DESCRIPTION, 98854359Sroberto WSDCF_FORMAT, 98954359Sroberto DCF_TYPE, 99054359Sroberto WSDCF_MAXUNSYNC, 99154359Sroberto WSDCF_SPEED, 99254359Sroberto WSDCF_CFLAG, 99354359Sroberto WSDCF_IFLAG, 99454359Sroberto WSDCF_OFLAG, 99554359Sroberto WSDCF_LFLAG, 99654359Sroberto WSDCF_SAMPLES, 99754359Sroberto WSDCF_KEEP 99854359Sroberto }, 99954359Sroberto { /* mode 5 */ 100054359Sroberto RAWDCF_FLAGS, 100154359Sroberto NO_POLL, 100254359Sroberto RAWDCF_INIT, 100354359Sroberto NO_EVENT, 100454359Sroberto NO_END, 100554359Sroberto NO_MESSAGE, 1006182007Sroberto NO_LCLDATA, 100754359Sroberto RAWDCF_ROOTDELAY, 100854359Sroberto CONRAD_BASEDELAY, 100954359Sroberto DCF_A_ID, 101054359Sroberto CONRAD_DESCRIPTION, 101154359Sroberto RAWDCF_FORMAT, 101254359Sroberto DCF_TYPE, 101354359Sroberto RAWDCF_MAXUNSYNC, 101454359Sroberto RAWDCF_SPEED, 101554359Sroberto RAWDCF_CFLAG, 101654359Sroberto RAWDCF_IFLAG, 101754359Sroberto RAWDCF_OFLAG, 101854359Sroberto RAWDCF_LFLAG, 101954359Sroberto RAWDCF_SAMPLES, 102054359Sroberto RAWDCF_KEEP 102154359Sroberto }, 102254359Sroberto { /* mode 6 */ 102354359Sroberto RAWDCF_FLAGS, 102454359Sroberto NO_POLL, 102554359Sroberto RAWDCF_INIT, 102654359Sroberto NO_EVENT, 102754359Sroberto NO_END, 102854359Sroberto NO_MESSAGE, 1029182007Sroberto NO_LCLDATA, 103054359Sroberto RAWDCF_ROOTDELAY, 103154359Sroberto TIMEBRICK_BASEDELAY, 103254359Sroberto DCF_A_ID, 103354359Sroberto TIMEBRICK_DESCRIPTION, 103454359Sroberto RAWDCF_FORMAT, 103554359Sroberto DCF_TYPE, 103654359Sroberto RAWDCF_MAXUNSYNC, 103754359Sroberto RAWDCF_SPEED, 103854359Sroberto RAWDCF_CFLAG, 103954359Sroberto RAWDCF_IFLAG, 104054359Sroberto RAWDCF_OFLAG, 104154359Sroberto RAWDCF_LFLAG, 104254359Sroberto RAWDCF_SAMPLES, 104354359Sroberto RAWDCF_KEEP 104454359Sroberto }, 104554359Sroberto { /* mode 7 */ 104654359Sroberto MBG_FLAGS, 104754359Sroberto GPS16X_POLL, 104854359Sroberto GPS16X_INIT, 104954359Sroberto NO_EVENT, 105054359Sroberto GPS16X_END, 105154359Sroberto GPS16X_MESSAGE, 105254359Sroberto GPS16X_DATA, 105354359Sroberto GPS16X_ROOTDELAY, 105454359Sroberto GPS16X_BASEDELAY, 105554359Sroberto GPS16X_ID, 105654359Sroberto GPS16X_DESCRIPTION, 105754359Sroberto GPS16X_FORMAT, 105854359Sroberto GPS_TYPE, 105954359Sroberto GPS16X_MAXUNSYNC, 106054359Sroberto GPS16X_SPEED, 106154359Sroberto GPS16X_CFLAG, 106254359Sroberto GPS16X_IFLAG, 106354359Sroberto GPS16X_OFLAG, 106454359Sroberto GPS16X_LFLAG, 106554359Sroberto GPS16X_SAMPLES, 106654359Sroberto GPS16X_KEEP 106754359Sroberto }, 106854359Sroberto { /* mode 8 */ 106954359Sroberto RAWDCF_FLAGS, 107054359Sroberto NO_POLL, 107154359Sroberto NO_INIT, 107254359Sroberto NO_EVENT, 107354359Sroberto NO_END, 107454359Sroberto NO_MESSAGE, 1075182007Sroberto NO_LCLDATA, 107654359Sroberto RAWDCF_ROOTDELAY, 107754359Sroberto IGELCLOCK_BASEDELAY, 107854359Sroberto DCF_A_ID, 107954359Sroberto IGELCLOCK_DESCRIPTION, 108054359Sroberto RAWDCF_FORMAT, 108154359Sroberto DCF_TYPE, 108254359Sroberto RAWDCF_MAXUNSYNC, 108354359Sroberto IGELCLOCK_SPEED, 108454359Sroberto IGELCLOCK_CFLAG, 108554359Sroberto RAWDCF_IFLAG, 108654359Sroberto RAWDCF_OFLAG, 108754359Sroberto RAWDCF_LFLAG, 108854359Sroberto RAWDCF_SAMPLES, 108954359Sroberto RAWDCF_KEEP 109054359Sroberto }, 109154359Sroberto { /* mode 9 */ 109254359Sroberto TRIMBLETAIP_FLAGS, 109354359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 109454359Sroberto NO_POLL, 109554359Sroberto#else 109654359Sroberto TRIMBLETAIP_POLL, 109754359Sroberto#endif 109854359Sroberto TRIMBLETAIP_INIT, 109954359Sroberto TRIMBLETAIP_EVENT, 110054359Sroberto TRIMBLETAIP_END, 110154359Sroberto NO_MESSAGE, 110254359Sroberto TRIMBLETAIP_DATA, 110354359Sroberto TRIMBLETAIP_ROOTDELAY, 110454359Sroberto TRIMBLETAIP_BASEDELAY, 110554359Sroberto TRIMBLETAIP_ID, 110654359Sroberto TRIMBLETAIP_DESCRIPTION, 110754359Sroberto TRIMBLETAIP_FORMAT, 110854359Sroberto GPS_TYPE, 110954359Sroberto TRIMBLETAIP_MAXUNSYNC, 111054359Sroberto TRIMBLETAIP_SPEED, 111154359Sroberto TRIMBLETAIP_CFLAG, 111254359Sroberto TRIMBLETAIP_IFLAG, 111354359Sroberto TRIMBLETAIP_OFLAG, 111454359Sroberto TRIMBLETAIP_LFLAG, 111554359Sroberto TRIMBLETAIP_SAMPLES, 111654359Sroberto TRIMBLETAIP_KEEP 111754359Sroberto }, 111854359Sroberto { /* mode 10 */ 111954359Sroberto TRIMBLETSIP_FLAGS, 112054359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 112154359Sroberto NO_POLL, 112254359Sroberto#else 112354359Sroberto TRIMBLETSIP_POLL, 112454359Sroberto#endif 112554359Sroberto TRIMBLETSIP_INIT, 112654359Sroberto TRIMBLETSIP_EVENT, 112754359Sroberto TRIMBLETSIP_END, 112854359Sroberto TRIMBLETSIP_MESSAGE, 112954359Sroberto TRIMBLETSIP_DATA, 113054359Sroberto TRIMBLETSIP_ROOTDELAY, 113154359Sroberto TRIMBLETSIP_BASEDELAY, 113254359Sroberto TRIMBLETSIP_ID, 113354359Sroberto TRIMBLETSIP_DESCRIPTION, 113454359Sroberto TRIMBLETSIP_FORMAT, 113554359Sroberto GPS_TYPE, 113654359Sroberto TRIMBLETSIP_MAXUNSYNC, 113754359Sroberto TRIMBLETSIP_SPEED, 113854359Sroberto TRIMBLETSIP_CFLAG, 113954359Sroberto TRIMBLETSIP_IFLAG, 114054359Sroberto TRIMBLETSIP_OFLAG, 114154359Sroberto TRIMBLETSIP_LFLAG, 114254359Sroberto TRIMBLETSIP_SAMPLES, 114354359Sroberto TRIMBLETSIP_KEEP 114454359Sroberto }, 114554359Sroberto { /* mode 11 */ 114654359Sroberto NO_CL_FLAGS, 114754359Sroberto RCC8000_POLL, 114854359Sroberto RCC8000_INIT, 114954359Sroberto NO_EVENT, 115054359Sroberto RCC8000_END, 115154359Sroberto NO_MESSAGE, 115254359Sroberto RCC8000_DATA, 115354359Sroberto RCC8000_ROOTDELAY, 115454359Sroberto RCC8000_BASEDELAY, 115554359Sroberto RCC8000_ID, 115654359Sroberto RCC8000_DESCRIPTION, 115754359Sroberto RCC8000_FORMAT, 115854359Sroberto DCF_TYPE, 115954359Sroberto RCC8000_MAXUNSYNC, 116054359Sroberto RCC8000_SPEED, 116154359Sroberto RCC8000_CFLAG, 116254359Sroberto RCC8000_IFLAG, 116354359Sroberto RCC8000_OFLAG, 116454359Sroberto RCC8000_LFLAG, 116554359Sroberto RCC8000_SAMPLES, 116654359Sroberto RCC8000_KEEP 116754359Sroberto }, 116854359Sroberto { /* mode 12 */ 116954359Sroberto HOPF6021_FLAGS, 117054359Sroberto NO_POLL, 117154359Sroberto NO_INIT, 117254359Sroberto NO_EVENT, 117354359Sroberto NO_END, 117454359Sroberto NO_MESSAGE, 1175182007Sroberto NO_LCLDATA, 117654359Sroberto HOPF6021_ROOTDELAY, 117754359Sroberto HOPF6021_BASEDELAY, 117854359Sroberto DCF_ID, 117954359Sroberto HOPF6021_DESCRIPTION, 118054359Sroberto HOPF6021_FORMAT, 118154359Sroberto DCF_TYPE, 118254359Sroberto HOPF6021_MAXUNSYNC, 118354359Sroberto HOPF6021_SPEED, 118454359Sroberto HOPF6021_CFLAG, 118554359Sroberto HOPF6021_IFLAG, 118654359Sroberto HOPF6021_OFLAG, 118754359Sroberto HOPF6021_LFLAG, 118854359Sroberto HOPF6021_SAMPLES, 118954359Sroberto HOPF6021_KEEP 119054359Sroberto }, 119154359Sroberto { /* mode 13 */ 119254359Sroberto COMPUTIME_FLAGS, 119354359Sroberto NO_POLL, 119454359Sroberto NO_INIT, 119554359Sroberto NO_EVENT, 119654359Sroberto NO_END, 119754359Sroberto NO_MESSAGE, 1198182007Sroberto NO_LCLDATA, 119954359Sroberto COMPUTIME_ROOTDELAY, 120054359Sroberto COMPUTIME_BASEDELAY, 120154359Sroberto COMPUTIME_ID, 120254359Sroberto COMPUTIME_DESCRIPTION, 120354359Sroberto COMPUTIME_FORMAT, 120454359Sroberto COMPUTIME_TYPE, 120554359Sroberto COMPUTIME_MAXUNSYNC, 120654359Sroberto COMPUTIME_SPEED, 120754359Sroberto COMPUTIME_CFLAG, 120854359Sroberto COMPUTIME_IFLAG, 120954359Sroberto COMPUTIME_OFLAG, 121054359Sroberto COMPUTIME_LFLAG, 121154359Sroberto COMPUTIME_SAMPLES, 121254359Sroberto COMPUTIME_KEEP 121354359Sroberto }, 121454359Sroberto { /* mode 14 */ 121554359Sroberto RAWDCF_FLAGS, 121654359Sroberto NO_POLL, 121756746Sroberto RAWDCFDTRSET_INIT, 121854359Sroberto NO_EVENT, 121954359Sroberto NO_END, 122054359Sroberto NO_MESSAGE, 1221182007Sroberto NO_LCLDATA, 122254359Sroberto RAWDCF_ROOTDELAY, 122354359Sroberto RAWDCF_BASEDELAY, 122454359Sroberto DCF_A_ID, 122556746Sroberto RAWDCFDTRSET_DESCRIPTION, 122654359Sroberto RAWDCF_FORMAT, 122754359Sroberto DCF_TYPE, 122854359Sroberto RAWDCF_MAXUNSYNC, 122954359Sroberto RAWDCF_SPEED, 123054359Sroberto RAWDCF_CFLAG, 123154359Sroberto RAWDCF_IFLAG, 123254359Sroberto RAWDCF_OFLAG, 123354359Sroberto RAWDCF_LFLAG, 123454359Sroberto RAWDCF_SAMPLES, 123554359Sroberto RAWDCF_KEEP 123654359Sroberto }, 123754359Sroberto { /* mode 15 */ 123856746Sroberto 0, /* operation flags (io modes) */ 123982498Sroberto NO_POLL, /* active poll routine */ 124082498Sroberto NO_INIT, /* active poll init routine */ 124156746Sroberto NO_EVENT, /* special event handling (e.g. reset clock) */ 124256746Sroberto NO_END, /* active poll end routine */ 124356746Sroberto NO_MESSAGE, /* process a lower layer message */ 1244182007Sroberto NO_LCLDATA, /* local data area for "poll" mechanism */ 124556746Sroberto 0, /* rootdelay */ 124682498Sroberto 11.0 /* bits */ / 9600, /* current offset by which the RS232 124756746Sroberto time code is delayed from the actual time */ 124856746Sroberto DCF_ID, /* ID code */ 124956746Sroberto "WHARTON 400A Series clock", /* device name */ 125082498Sroberto "WHARTON 400A Series clock Output Format 1", /* fixed format */ 125156746Sroberto /* Must match a format-name in a libparse/clk_xxx.c file */ 125256746Sroberto DCF_TYPE, /* clock type (ntp control) */ 1253132451Sroberto (1*60*60), /* time to trust oscillator after losing synch */ 125456746Sroberto B9600, /* terminal input & output baudrate */ 125556746Sroberto (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ 125656746Sroberto 0, /* terminal input flags */ 125756746Sroberto 0, /* terminal output flags */ 125856746Sroberto 0, /* terminal local flags */ 125956746Sroberto 5, /* samples for median filter */ 126056746Sroberto 3, /* samples for median filter to keep */ 126154359Sroberto }, 126256746Sroberto { /* mode 16 - RAWDCF RTS set, DTR clr */ 126356746Sroberto RAWDCF_FLAGS, 126456746Sroberto NO_POLL, 126556746Sroberto RAWDCFDTRCLRRTSSET_INIT, 126656746Sroberto NO_EVENT, 126756746Sroberto NO_END, 126856746Sroberto NO_MESSAGE, 1269182007Sroberto NO_LCLDATA, 127056746Sroberto RAWDCF_ROOTDELAY, 127156746Sroberto RAWDCF_BASEDELAY, 127256746Sroberto DCF_A_ID, 127356746Sroberto RAWDCFDTRCLRRTSSET_DESCRIPTION, 127456746Sroberto RAWDCF_FORMAT, 127556746Sroberto DCF_TYPE, 127656746Sroberto RAWDCF_MAXUNSYNC, 127756746Sroberto RAWDCF_SPEED, 127856746Sroberto RAWDCF_CFLAG, 127956746Sroberto RAWDCF_IFLAG, 128056746Sroberto RAWDCF_OFLAG, 128156746Sroberto RAWDCF_LFLAG, 128256746Sroberto RAWDCF_SAMPLES, 128356746Sroberto RAWDCF_KEEP 128456746Sroberto }, 128556746Sroberto { /* mode 17 */ 128654359Sroberto VARITEXT_FLAGS, 128754359Sroberto NO_POLL, 128854359Sroberto NO_INIT, 128954359Sroberto NO_EVENT, 129054359Sroberto NO_END, 129154359Sroberto NO_MESSAGE, 1292182007Sroberto NO_LCLDATA, 129354359Sroberto VARITEXT_ROOTDELAY, 129454359Sroberto VARITEXT_BASEDELAY, 129554359Sroberto VARITEXT_ID, 129654359Sroberto VARITEXT_DESCRIPTION, 129754359Sroberto VARITEXT_FORMAT, 129854359Sroberto VARITEXT_TYPE, 129954359Sroberto VARITEXT_MAXUNSYNC, 130054359Sroberto VARITEXT_SPEED, 130154359Sroberto VARITEXT_CFLAG, 130254359Sroberto VARITEXT_IFLAG, 130354359Sroberto VARITEXT_OFLAG, 130454359Sroberto VARITEXT_LFLAG, 130554359Sroberto VARITEXT_SAMPLES, 130654359Sroberto VARITEXT_KEEP 1307182007Sroberto }, 1308182007Sroberto { /* mode 18 */ 1309182007Sroberto MBG_FLAGS, 1310182007Sroberto NO_POLL, 1311182007Sroberto NO_INIT, 1312182007Sroberto NO_EVENT, 1313182007Sroberto GPS16X_END, 1314182007Sroberto GPS16X_MESSAGE, 1315182007Sroberto GPS16X_DATA, 1316182007Sroberto GPS16X_ROOTDELAY, 1317182007Sroberto GPS16X_BASEDELAY, 1318182007Sroberto GPS16X_ID, 1319182007Sroberto GPS16X_DESCRIPTION, 1320182007Sroberto GPS16X_FORMAT, 1321182007Sroberto GPS_TYPE, 1322182007Sroberto GPS16X_MAXUNSYNC, 1323182007Sroberto GPS16X_SPEED, 1324182007Sroberto GPS16X_CFLAG, 1325182007Sroberto GPS16X_IFLAG, 1326182007Sroberto GPS16X_OFLAG, 1327182007Sroberto GPS16X_LFLAG, 1328182007Sroberto GPS16X_SAMPLES, 1329182007Sroberto GPS16X_KEEP 1330182007Sroberto }, 1331182007Sroberto { /* mode 19 */ 1332182007Sroberto RAWDCF_FLAGS, 1333182007Sroberto NO_POLL, 1334182007Sroberto RAWDCF_INIT, 1335182007Sroberto NO_EVENT, 1336182007Sroberto NO_END, 1337182007Sroberto NO_MESSAGE, 1338182007Sroberto NO_LCLDATA, 1339182007Sroberto RAWDCF_ROOTDELAY, 1340182007Sroberto GUDE_EMC_USB_V20_BASEDELAY, 1341182007Sroberto DCF_A_ID, 1342182007Sroberto GUDE_EMC_USB_V20_DESCRIPTION, 1343182007Sroberto RAWDCF_FORMAT, 1344182007Sroberto DCF_TYPE, 1345182007Sroberto RAWDCF_MAXUNSYNC, 1346182007Sroberto GUDE_EMC_USB_V20_SPEED, 1347182007Sroberto RAWDCF_CFLAG, 1348182007Sroberto RAWDCF_IFLAG, 1349182007Sroberto RAWDCF_OFLAG, 1350182007Sroberto RAWDCF_LFLAG, 1351182007Sroberto RAWDCF_SAMPLES, 1352182007Sroberto RAWDCF_KEEP 1353182007Sroberto }, 135454359Sroberto}; 135554359Sroberto 135654359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); 135754359Sroberto 1358132451Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) 135954359Sroberto#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) 136054359Sroberto#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) 1361132451Sroberto#define CLK_PPS(x) (((x)->ttl) & 0x80) 136254359Sroberto 136354359Sroberto/* 136454359Sroberto * Other constant stuff 136554359Sroberto */ 136654359Sroberto#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ 136754359Sroberto 136854359Sroberto#define PARSESTATISTICS (60*60) /* output state statistics every hour */ 136954359Sroberto 137054359Srobertostatic int notice = 0; 137154359Sroberto 137254359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) 137354359Sroberto 137454359Srobertostatic void parse_event P((struct parseunit *, int)); 137554359Srobertostatic void parse_process P((struct parseunit *, parsetime_t *)); 137654359Srobertostatic void clear_err P((struct parseunit *, u_long)); 137754359Srobertostatic int list_err P((struct parseunit *, u_long)); 137854359Srobertostatic char * l_mktime P((u_long)); 137954359Sroberto 138054359Sroberto/**=========================================================================== 138154359Sroberto ** implementation error message regression module 138254359Sroberto **/ 138354359Srobertostatic void 138454359Srobertoclear_err( 138554359Sroberto struct parseunit *parse, 138654359Sroberto u_long lstate 138754359Sroberto ) 138854359Sroberto{ 138954359Sroberto if (lstate == ERR_ALL) 139054359Sroberto { 139154359Sroberto int i; 139254359Sroberto 139354359Sroberto for (i = 0; i < ERR_CNT; i++) 139454359Sroberto { 139554359Sroberto parse->errors[i].err_stage = err_tbl[i]; 139654359Sroberto parse->errors[i].err_cnt = 0; 139754359Sroberto parse->errors[i].err_last = 0; 139854359Sroberto parse->errors[i].err_started = 0; 139954359Sroberto parse->errors[i].err_suppressed = 0; 140054359Sroberto } 140154359Sroberto } 140254359Sroberto else 140354359Sroberto { 140454359Sroberto parse->errors[lstate].err_stage = err_tbl[lstate]; 140554359Sroberto parse->errors[lstate].err_cnt = 0; 140654359Sroberto parse->errors[lstate].err_last = 0; 140754359Sroberto parse->errors[lstate].err_started = 0; 140854359Sroberto parse->errors[lstate].err_suppressed = 0; 140954359Sroberto } 141054359Sroberto} 141154359Sroberto 141254359Srobertostatic int 141354359Srobertolist_err( 141454359Sroberto struct parseunit *parse, 141554359Sroberto u_long lstate 141654359Sroberto ) 141754359Sroberto{ 141854359Sroberto int do_it; 141954359Sroberto struct errorinfo *err = &parse->errors[lstate]; 142054359Sroberto 142154359Sroberto if (err->err_started == 0) 142254359Sroberto { 142354359Sroberto err->err_started = current_time; 142454359Sroberto } 142554359Sroberto 142654359Sroberto do_it = (current_time - err->err_last) >= err->err_stage->err_delay; 142754359Sroberto 142854359Sroberto if (do_it) 142954359Sroberto err->err_cnt++; 143054359Sroberto 143154359Sroberto if (err->err_stage->err_count && 143254359Sroberto (err->err_cnt >= err->err_stage->err_count)) 143354359Sroberto { 143454359Sroberto err->err_stage++; 143554359Sroberto err->err_cnt = 0; 143654359Sroberto } 143754359Sroberto 143854359Sroberto if (!err->err_cnt && do_it) 143954359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", 144054359Sroberto CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); 144154359Sroberto 144254359Sroberto if (!do_it) 144354359Sroberto err->err_suppressed++; 144454359Sroberto else 144554359Sroberto err->err_last = current_time; 144654359Sroberto 144754359Sroberto if (do_it && err->err_suppressed) 144854359Sroberto { 144954359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", 145054359Sroberto CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", 145154359Sroberto l_mktime(current_time - err->err_started)); 145254359Sroberto err->err_suppressed = 0; 145354359Sroberto } 145454359Sroberto 145554359Sroberto return do_it; 145654359Sroberto} 145754359Sroberto 145854359Sroberto/*-------------------------------------------------- 145954359Sroberto * mkreadable - make a printable ascii string (without 146054359Sroberto * embedded quotes so that the ntpq protocol isn't 146154359Sroberto * fooled 146254359Sroberto */ 146354359Sroberto#ifndef isprint 146454359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) 146554359Sroberto#endif 146654359Sroberto 146754359Srobertostatic char * 146854359Srobertomkreadable( 146954359Sroberto char *buffer, 147054359Sroberto long blen, 147154359Sroberto const char *src, 147254359Sroberto u_long srclen, 147354359Sroberto int hex 147454359Sroberto ) 147554359Sroberto{ 147654359Sroberto char *b = buffer; 147754359Sroberto char *endb = (char *)0; 147854359Sroberto 147954359Sroberto if (blen < 4) 148054359Sroberto return (char *)0; /* don't bother with mini buffers */ 148154359Sroberto 148254359Sroberto endb = buffer + blen - 4; 148354359Sroberto 148454359Sroberto blen--; /* account for '\0' */ 148554359Sroberto 148654359Sroberto while (blen && srclen--) 148754359Sroberto { 148854359Sroberto if (!hex && /* no binary only */ 148954359Sroberto (*src != '\\') && /* no plain \ */ 149054359Sroberto (*src != '"') && /* no " */ 149154359Sroberto isprint((int)*src)) /* only printables */ 149254359Sroberto { /* they are easy... */ 149354359Sroberto *buffer++ = *src++; 149454359Sroberto blen--; 149554359Sroberto } 149654359Sroberto else 149754359Sroberto { 149854359Sroberto if (blen < 4) 149954359Sroberto { 150054359Sroberto while (blen--) 150154359Sroberto { 150254359Sroberto *buffer++ = '.'; 150354359Sroberto } 150454359Sroberto *buffer = '\0'; 150554359Sroberto return b; 150654359Sroberto } 150754359Sroberto else 150854359Sroberto { 150954359Sroberto if (*src == '\\') 151054359Sroberto { 151154359Sroberto strcpy(buffer,"\\\\"); 151254359Sroberto buffer += 2; 151354359Sroberto blen -= 2; 151454359Sroberto src++; 151554359Sroberto } 151654359Sroberto else 151754359Sroberto { 151854359Sroberto sprintf(buffer, "\\x%02x", *src++); 151954359Sroberto blen -= 4; 152054359Sroberto buffer += 4; 152154359Sroberto } 152254359Sroberto } 152354359Sroberto } 152454359Sroberto if (srclen && !blen && endb) /* overflow - set last chars to ... */ 152554359Sroberto strcpy(endb, "..."); 152654359Sroberto } 152754359Sroberto 152854359Sroberto *buffer = '\0'; 152954359Sroberto return b; 153054359Sroberto} 153154359Sroberto 153254359Sroberto 153354359Sroberto/*-------------------------------------------------- 153454359Sroberto * mkascii - make a printable ascii string 153554359Sroberto * assumes (unless defined better) 7-bit ASCII 153654359Sroberto */ 153754359Srobertostatic char * 153854359Srobertomkascii( 153954359Sroberto char *buffer, 154054359Sroberto long blen, 154154359Sroberto const char *src, 154254359Sroberto u_long srclen 154354359Sroberto ) 154454359Sroberto{ 154554359Sroberto return mkreadable(buffer, blen, src, srclen, 0); 154654359Sroberto} 154754359Sroberto 154854359Sroberto/**=========================================================================== 154954359Sroberto ** implementation of i/o handling methods 155054359Sroberto ** (all STREAM, partial STREAM, user level) 155154359Sroberto **/ 155254359Sroberto 155354359Sroberto/* 155454359Sroberto * define possible io handling methods 155554359Sroberto */ 155654359Sroberto#ifdef STREAM 155754359Srobertostatic int ppsclock_init P((struct parseunit *)); 155854359Srobertostatic int stream_init P((struct parseunit *)); 155954359Srobertostatic void stream_end P((struct parseunit *)); 156054359Srobertostatic int stream_enable P((struct parseunit *)); 156154359Srobertostatic int stream_disable P((struct parseunit *)); 156254359Srobertostatic int stream_setcs P((struct parseunit *, parsectl_t *)); 156354359Srobertostatic int stream_getfmt P((struct parseunit *, parsectl_t *)); 156454359Srobertostatic int stream_setfmt P((struct parseunit *, parsectl_t *)); 156554359Srobertostatic int stream_timecode P((struct parseunit *, parsectl_t *)); 156654359Srobertostatic void stream_receive P((struct recvbuf *)); 156754359Sroberto#endif 156854359Sroberto 156954359Srobertostatic int local_init P((struct parseunit *)); 157054359Srobertostatic void local_end P((struct parseunit *)); 157154359Srobertostatic int local_nop P((struct parseunit *)); 157254359Srobertostatic int local_setcs P((struct parseunit *, parsectl_t *)); 157354359Srobertostatic int local_getfmt P((struct parseunit *, parsectl_t *)); 157454359Srobertostatic int local_setfmt P((struct parseunit *, parsectl_t *)); 157554359Srobertostatic int local_timecode P((struct parseunit *, parsectl_t *)); 157654359Srobertostatic void local_receive P((struct recvbuf *)); 157754359Srobertostatic int local_input P((struct recvbuf *)); 157854359Sroberto 157954359Srobertostatic bind_t io_bindings[] = 158054359Sroberto{ 158154359Sroberto#ifdef STREAM 158254359Sroberto { 158354359Sroberto "parse STREAM", 158454359Sroberto stream_init, 158554359Sroberto stream_end, 158654359Sroberto stream_setcs, 158754359Sroberto stream_disable, 158854359Sroberto stream_enable, 158954359Sroberto stream_getfmt, 159054359Sroberto stream_setfmt, 159154359Sroberto stream_timecode, 159254359Sroberto stream_receive, 159354359Sroberto 0, 159454359Sroberto }, 159554359Sroberto { 159654359Sroberto "ppsclock STREAM", 159754359Sroberto ppsclock_init, 159854359Sroberto local_end, 159954359Sroberto local_setcs, 160054359Sroberto local_nop, 160154359Sroberto local_nop, 160254359Sroberto local_getfmt, 160354359Sroberto local_setfmt, 160454359Sroberto local_timecode, 160554359Sroberto local_receive, 160654359Sroberto local_input, 160754359Sroberto }, 160854359Sroberto#endif 160954359Sroberto { 161054359Sroberto "normal", 161154359Sroberto local_init, 161254359Sroberto local_end, 161354359Sroberto local_setcs, 161454359Sroberto local_nop, 161554359Sroberto local_nop, 161654359Sroberto local_getfmt, 161754359Sroberto local_setfmt, 161854359Sroberto local_timecode, 161954359Sroberto local_receive, 162054359Sroberto local_input, 162154359Sroberto }, 162254359Sroberto { 162354359Sroberto (char *)0, 162454359Sroberto } 162554359Sroberto}; 162654359Sroberto 162754359Sroberto#ifdef STREAM 162854359Sroberto 162954359Sroberto#define fix_ts(_X_) \ 163054359Sroberto if ((&(_X_))->tv.tv_usec >= 1000000) \ 163154359Sroberto { \ 163254359Sroberto (&(_X_))->tv.tv_usec -= 1000000; \ 163354359Sroberto (&(_X_))->tv.tv_sec += 1; \ 163454359Sroberto } 163554359Sroberto 163654359Sroberto#define cvt_ts(_X_, _Y_) \ 163754359Sroberto { \ 163854359Sroberto l_fp ts; \ 163954359Sroberto fix_ts((_X_)); \ 164054359Sroberto if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \ 164154359Sroberto { \ 164254359Sroberto ERR(ERR_BADDATA) \ 164354359Sroberto msyslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%ld.%06ld) ", (_Y_), (long)(&(_X_))->tv.tv_sec, (long)(&(_X_))->tv.tv_usec);\ 164454359Sroberto return; \ 164554359Sroberto } \ 164654359Sroberto else \ 164754359Sroberto { \ 164854359Sroberto (&(_X_))->fp = ts; \ 164954359Sroberto } \ 165054359Sroberto } 165154359Sroberto 165254359Sroberto/*-------------------------------------------------- 165354359Sroberto * ppsclock STREAM init 165454359Sroberto */ 165554359Srobertostatic int 165654359Srobertoppsclock_init( 165754359Sroberto struct parseunit *parse 165854359Sroberto ) 165954359Sroberto{ 166054359Sroberto static char m1[] = "ppsclocd"; 166154359Sroberto static char m2[] = "ppsclock"; 166254359Sroberto 166354359Sroberto /* 166454359Sroberto * now push the parse streams module 166554359Sroberto * it will ensure exclusive access to the device 166654359Sroberto */ 1667182007Sroberto if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 && 1668182007Sroberto ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1) 166954359Sroberto { 167054359Sroberto if (errno != EINVAL) 167156746Sroberto { 167256746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 167356746Sroberto CLK_UNIT(parse->peer)); 167454359Sroberto } 167554359Sroberto return 0; 167654359Sroberto } 167754359Sroberto if (!local_init(parse)) 167854359Sroberto { 1679182007Sroberto (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0); 168054359Sroberto return 0; 168154359Sroberto } 168254359Sroberto 168354359Sroberto parse->flags |= PARSE_PPSCLOCK; 168454359Sroberto return 1; 168554359Sroberto} 168654359Sroberto 168754359Sroberto/*-------------------------------------------------- 168854359Sroberto * parse STREAM init 168954359Sroberto */ 169054359Srobertostatic int 169154359Srobertostream_init( 169254359Sroberto struct parseunit *parse 169354359Sroberto ) 169454359Sroberto{ 169554359Sroberto static char m1[] = "parse"; 169654359Sroberto /* 169754359Sroberto * now push the parse streams module 169854359Sroberto * to test whether it is there (neat interface 8-( ) 169954359Sroberto */ 170054359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 170154359Sroberto { 170254359Sroberto if (errno != EINVAL) /* accept non-existence */ 170356746Sroberto { 170456746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 170554359Sroberto } 170654359Sroberto return 0; 170754359Sroberto } 170854359Sroberto else 170954359Sroberto { 171054359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 171154359Sroberto /* empty loop */; 171254359Sroberto 171354359Sroberto /* 171454359Sroberto * now push it a second time after we have removed all 171554359Sroberto * module garbage 171654359Sroberto */ 171754359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 171854359Sroberto { 171954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 172054359Sroberto return 0; 172154359Sroberto } 172254359Sroberto else 172354359Sroberto { 172454359Sroberto return 1; 172554359Sroberto } 172654359Sroberto } 172754359Sroberto} 172854359Sroberto 172954359Sroberto/*-------------------------------------------------- 173054359Sroberto * parse STREAM end 173154359Sroberto */ 173254359Srobertostatic void 173354359Srobertostream_end( 173454359Sroberto struct parseunit *parse 173554359Sroberto ) 173654359Sroberto{ 173754359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 173854359Sroberto /* empty loop */; 173954359Sroberto} 174054359Sroberto 174154359Sroberto/*-------------------------------------------------- 174254359Sroberto * STREAM setcs 174354359Sroberto */ 174454359Srobertostatic int 174554359Srobertostream_setcs( 174654359Sroberto struct parseunit *parse, 174754359Sroberto parsectl_t *tcl 174854359Sroberto ) 174954359Sroberto{ 175054359Sroberto struct strioctl strioc; 175154359Sroberto 175254359Sroberto strioc.ic_cmd = PARSEIOC_SETCS; 175354359Sroberto strioc.ic_timout = 0; 175454359Sroberto strioc.ic_dp = (char *)tcl; 175554359Sroberto strioc.ic_len = sizeof (*tcl); 175654359Sroberto 175754359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 175854359Sroberto { 175954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 176054359Sroberto return 0; 176154359Sroberto } 176254359Sroberto return 1; 176354359Sroberto} 176454359Sroberto 176554359Sroberto/*-------------------------------------------------- 176654359Sroberto * STREAM enable 176754359Sroberto */ 176854359Srobertostatic int 176954359Srobertostream_enable( 177054359Sroberto struct parseunit *parse 177154359Sroberto ) 177254359Sroberto{ 177354359Sroberto struct strioctl strioc; 177454359Sroberto 177554359Sroberto strioc.ic_cmd = PARSEIOC_ENABLE; 177654359Sroberto strioc.ic_timout = 0; 177754359Sroberto strioc.ic_dp = (char *)0; 177854359Sroberto strioc.ic_len = 0; 177954359Sroberto 178054359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 178154359Sroberto { 178254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 178354359Sroberto return 0; 178454359Sroberto } 178554359Sroberto parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 178654359Sroberto return 1; 178754359Sroberto} 178854359Sroberto 178954359Sroberto/*-------------------------------------------------- 179054359Sroberto * STREAM disable 179154359Sroberto */ 179254359Srobertostatic int 179354359Srobertostream_disable( 179454359Sroberto struct parseunit *parse 179554359Sroberto ) 179654359Sroberto{ 179754359Sroberto struct strioctl strioc; 179854359Sroberto 179954359Sroberto strioc.ic_cmd = PARSEIOC_DISABLE; 180054359Sroberto strioc.ic_timout = 0; 180154359Sroberto strioc.ic_dp = (char *)0; 180254359Sroberto strioc.ic_len = 0; 180354359Sroberto 180454359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 180554359Sroberto { 180654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 180754359Sroberto return 0; 180854359Sroberto } 180954359Sroberto parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 181054359Sroberto return 1; 181154359Sroberto} 181254359Sroberto 181354359Sroberto/*-------------------------------------------------- 181454359Sroberto * STREAM getfmt 181554359Sroberto */ 181654359Srobertostatic int 181754359Srobertostream_getfmt( 181854359Sroberto struct parseunit *parse, 181954359Sroberto parsectl_t *tcl 182054359Sroberto ) 182154359Sroberto{ 182254359Sroberto struct strioctl strioc; 182354359Sroberto 182454359Sroberto strioc.ic_cmd = PARSEIOC_GETFMT; 182554359Sroberto strioc.ic_timout = 0; 182654359Sroberto strioc.ic_dp = (char *)tcl; 182754359Sroberto strioc.ic_len = sizeof (*tcl); 182854359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 182954359Sroberto { 183054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 183154359Sroberto return 0; 183254359Sroberto } 183354359Sroberto return 1; 183454359Sroberto} 183554359Sroberto 183654359Sroberto/*-------------------------------------------------- 183754359Sroberto * STREAM setfmt 183854359Sroberto */ 183954359Srobertostatic int 184054359Srobertostream_setfmt( 184154359Sroberto struct parseunit *parse, 184254359Sroberto parsectl_t *tcl 184354359Sroberto ) 184454359Sroberto{ 184554359Sroberto struct strioctl strioc; 184654359Sroberto 184754359Sroberto strioc.ic_cmd = PARSEIOC_SETFMT; 184854359Sroberto strioc.ic_timout = 0; 184954359Sroberto strioc.ic_dp = (char *)tcl; 185054359Sroberto strioc.ic_len = sizeof (*tcl); 185154359Sroberto 185254359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 185354359Sroberto { 185454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 185554359Sroberto return 0; 185654359Sroberto } 185754359Sroberto return 1; 185854359Sroberto} 185954359Sroberto 186054359Sroberto 186154359Sroberto/*-------------------------------------------------- 186254359Sroberto * STREAM timecode 186354359Sroberto */ 186454359Srobertostatic int 186554359Srobertostream_timecode( 186654359Sroberto struct parseunit *parse, 186754359Sroberto parsectl_t *tcl 186854359Sroberto ) 186954359Sroberto{ 187054359Sroberto struct strioctl strioc; 187154359Sroberto 187254359Sroberto strioc.ic_cmd = PARSEIOC_TIMECODE; 187354359Sroberto strioc.ic_timout = 0; 187454359Sroberto strioc.ic_dp = (char *)tcl; 187554359Sroberto strioc.ic_len = sizeof (*tcl); 187654359Sroberto 187754359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 187854359Sroberto { 187954359Sroberto ERR(ERR_INTERNAL) 188054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 188154359Sroberto return 0; 188254359Sroberto } 188354359Sroberto clear_err(parse, ERR_INTERNAL); 188454359Sroberto return 1; 188554359Sroberto} 188654359Sroberto 188754359Sroberto/*-------------------------------------------------- 188854359Sroberto * STREAM receive 188954359Sroberto */ 189054359Srobertostatic void 189154359Srobertostream_receive( 189254359Sroberto struct recvbuf *rbufp 189354359Sroberto ) 189454359Sroberto{ 189554359Sroberto struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 189654359Sroberto parsetime_t parsetime; 189754359Sroberto 189854359Sroberto if (!parse->peer) 189954359Sroberto return; 190054359Sroberto 190154359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 190254359Sroberto { 190354359Sroberto ERR(ERR_BADIO) 190454359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 190554359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 190654359Sroberto parse_event(parse, CEVNT_BADREPLY); 190754359Sroberto return; 190854359Sroberto } 190954359Sroberto clear_err(parse, ERR_BADIO); 191054359Sroberto 191154359Sroberto memmove((caddr_t)&parsetime, 191254359Sroberto (caddr_t)rbufp->recv_buffer, 191354359Sroberto sizeof(parsetime_t)); 191454359Sroberto 191554359Sroberto#ifdef DEBUG 191654359Sroberto if (debug > 3) 191754359Sroberto { 191854359Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 191954359Sroberto CLK_UNIT(parse->peer), 192054359Sroberto (unsigned int)parsetime.parse_status, 192154359Sroberto (unsigned int)parsetime.parse_state, 1922182007Sroberto (unsigned long)parsetime.parse_time.tv.tv_sec, 1923182007Sroberto (unsigned long)parsetime.parse_time.tv.tv_usec, 1924182007Sroberto (unsigned long)parsetime.parse_stime.tv.tv_sec, 1925182007Sroberto (unsigned long)parsetime.parse_stime.tv.tv_usec, 1926182007Sroberto (unsigned long)parsetime.parse_ptime.tv.tv_sec, 1927182007Sroberto (unsigned long)parsetime.parse_ptime.tv.tv_usec); 192854359Sroberto } 192954359Sroberto#endif 193054359Sroberto 193154359Sroberto /* 193254359Sroberto * switch time stamp world - be sure to normalize small usec field 193354359Sroberto * errors. 193454359Sroberto */ 193554359Sroberto 193654359Sroberto cvt_ts(parsetime.parse_stime, "parse_stime"); 193754359Sroberto 193854359Sroberto if (PARSE_TIMECODE(parsetime.parse_state)) 193954359Sroberto { 194054359Sroberto cvt_ts(parsetime.parse_time, "parse_time"); 194154359Sroberto } 194254359Sroberto 194354359Sroberto if (PARSE_PPS(parsetime.parse_state)) 194454359Sroberto cvt_ts(parsetime.parse_ptime, "parse_ptime"); 194554359Sroberto 194654359Sroberto parse_process(parse, &parsetime); 194754359Sroberto} 194854359Sroberto#endif 194954359Sroberto 195054359Sroberto/*-------------------------------------------------- 195154359Sroberto * local init 195254359Sroberto */ 195354359Srobertostatic int 195454359Srobertolocal_init( 195554359Sroberto struct parseunit *parse 195654359Sroberto ) 195754359Sroberto{ 195854359Sroberto return parse_ioinit(&parse->parseio); 195954359Sroberto} 196054359Sroberto 196154359Sroberto/*-------------------------------------------------- 196254359Sroberto * local end 196354359Sroberto */ 196454359Srobertostatic void 196554359Srobertolocal_end( 196654359Sroberto struct parseunit *parse 196754359Sroberto ) 196854359Sroberto{ 196954359Sroberto parse_ioend(&parse->parseio); 197054359Sroberto} 197154359Sroberto 197254359Sroberto 197354359Sroberto/*-------------------------------------------------- 197454359Sroberto * local nop 197554359Sroberto */ 197654359Srobertostatic int 197754359Srobertolocal_nop( 197854359Sroberto struct parseunit *parse 197954359Sroberto ) 198054359Sroberto{ 198154359Sroberto return 1; 198254359Sroberto} 198354359Sroberto 198454359Sroberto/*-------------------------------------------------- 198554359Sroberto * local setcs 198654359Sroberto */ 198754359Srobertostatic int 198854359Srobertolocal_setcs( 198954359Sroberto struct parseunit *parse, 199054359Sroberto parsectl_t *tcl 199154359Sroberto ) 199254359Sroberto{ 199354359Sroberto return parse_setcs(tcl, &parse->parseio); 199454359Sroberto} 199554359Sroberto 199654359Sroberto/*-------------------------------------------------- 199754359Sroberto * local getfmt 199854359Sroberto */ 199954359Srobertostatic int 200054359Srobertolocal_getfmt( 200154359Sroberto struct parseunit *parse, 200254359Sroberto parsectl_t *tcl 200354359Sroberto ) 200454359Sroberto{ 200554359Sroberto return parse_getfmt(tcl, &parse->parseio); 200654359Sroberto} 200754359Sroberto 200854359Sroberto/*-------------------------------------------------- 200954359Sroberto * local setfmt 201054359Sroberto */ 201154359Srobertostatic int 201254359Srobertolocal_setfmt( 201354359Sroberto struct parseunit *parse, 201454359Sroberto parsectl_t *tcl 201554359Sroberto ) 201654359Sroberto{ 201754359Sroberto return parse_setfmt(tcl, &parse->parseio); 201854359Sroberto} 201954359Sroberto 202054359Sroberto/*-------------------------------------------------- 202154359Sroberto * local timecode 202254359Sroberto */ 202354359Srobertostatic int 202454359Srobertolocal_timecode( 202554359Sroberto struct parseunit *parse, 202654359Sroberto parsectl_t *tcl 202754359Sroberto ) 202854359Sroberto{ 202954359Sroberto return parse_timecode(tcl, &parse->parseio); 203054359Sroberto} 203154359Sroberto 203254359Sroberto 203354359Sroberto/*-------------------------------------------------- 203454359Sroberto * local input 203554359Sroberto */ 203654359Srobertostatic int 203754359Srobertolocal_input( 203854359Sroberto struct recvbuf *rbufp 203954359Sroberto ) 204054359Sroberto{ 204154359Sroberto struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 204254359Sroberto int count; 204354359Sroberto unsigned char *s; 204454359Sroberto timestamp_t ts; 204554359Sroberto 204654359Sroberto if (!parse->peer) 204754359Sroberto return 0; 204854359Sroberto 204954359Sroberto /* 205054359Sroberto * eat all characters, parsing then and feeding complete samples 205154359Sroberto */ 205254359Sroberto count = rbufp->recv_length; 205354359Sroberto s = (unsigned char *)rbufp->recv_buffer; 205454359Sroberto ts.fp = rbufp->recv_time; 205554359Sroberto 205654359Sroberto while (count--) 205754359Sroberto { 205854359Sroberto if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 205954359Sroberto { 2060182007Sroberto struct recvbuf *buf; 206154359Sroberto 206254359Sroberto /* 206354359Sroberto * got something good to eat 206454359Sroberto */ 206554359Sroberto if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 206654359Sroberto { 2067182007Sroberto#ifdef HAVE_PPSAPI 2068182007Sroberto if (parse->flags & PARSE_PPSCLOCK) 2069182007Sroberto { 2070182007Sroberto struct timespec pps_timeout; 2071182007Sroberto pps_info_t pps_info; 2072182007Sroberto 2073182007Sroberto pps_timeout.tv_sec = 0; 2074182007Sroberto pps_timeout.tv_nsec = 0; 2075182007Sroberto 2076182007Sroberto if (time_pps_fetch(parse->ppshandle, PPS_TSFMT_TSPEC, &pps_info, 2077182007Sroberto &pps_timeout) == 0) 2078182007Sroberto { 2079182007Sroberto if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial) 2080182007Sroberto { 2081182007Sroberto double dtemp; 2082182007Sroberto 2083182007Sroberto struct timespec pts; 2084182007Sroberto /* 2085182007Sroberto * add PPS time stamp if available via ppsclock module 2086182007Sroberto * and not supplied already. 2087182007Sroberto */ 2088182007Sroberto if (parse->flags & PARSE_CLEAR) 2089182007Sroberto pts = pps_info.clear_timestamp; 2090182007Sroberto else 2091182007Sroberto pts = pps_info.assert_timestamp; 2092182007Sroberto 2093182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970; 2094182007Sroberto 2095182007Sroberto dtemp = pts.tv_nsec / 1e9; 2096182007Sroberto if (dtemp < 0.) { 2097182007Sroberto dtemp += 1; 2098182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui--; 2099182007Sroberto } 2100182007Sroberto if (dtemp > 1.) { 2101182007Sroberto dtemp -= 1; 2102182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui++; 2103182007Sroberto } 2104182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC; 2105182007Sroberto 2106182007Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2107182007Sroberto#ifdef DEBUG 2108182007Sroberto if (debug > 3) 2109182007Sroberto { 2110182007Sroberto printf( 2111182007Sroberto "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n", 2112182007Sroberto rbufp->fd, 2113182007Sroberto (long)pps_info.assert_sequence + (long)pps_info.clear_sequence, 2114182007Sroberto lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6)); 2115182007Sroberto } 2116182007Sroberto#endif 2117182007Sroberto } 2118182007Sroberto#ifdef DEBUG 2119182007Sroberto else 2120182007Sroberto { 2121182007Sroberto if (debug > 3) 2122182007Sroberto { 2123182007Sroberto printf( 2124182007Sroberto "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2125182007Sroberto rbufp->fd, 2126182007Sroberto (long)pps_info.assert_sequence, (long)pps_info.clear_sequence); 2127182007Sroberto } 2128182007Sroberto } 2129182007Sroberto#endif 2130182007Sroberto parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence; 2131182007Sroberto } 2132182007Sroberto#ifdef DEBUG 2133182007Sroberto else 2134182007Sroberto { 2135182007Sroberto if (debug > 3) 2136182007Sroberto { 2137182007Sroberto printf( 2138182007Sroberto "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n", 2139182007Sroberto rbufp->fd, 2140182007Sroberto errno); 2141182007Sroberto } 2142182007Sroberto } 2143182007Sroberto#endif 2144182007Sroberto } 2145182007Sroberto#else 214654359Sroberto#ifdef TIOCDCDTIMESTAMP 214754359Sroberto struct timeval dcd_time; 214854359Sroberto 2149182007Sroberto if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 215054359Sroberto { 215154359Sroberto l_fp tstmp; 215254359Sroberto 215354359Sroberto TVTOTS(&dcd_time, &tstmp); 215454359Sroberto tstmp.l_ui += JAN_1970; 215554359Sroberto L_SUB(&ts.fp, &tstmp); 215654359Sroberto if (ts.fp.l_ui == 0) 215754359Sroberto { 215854359Sroberto#ifdef DEBUG 215954359Sroberto if (debug) 216054359Sroberto { 216154359Sroberto printf( 216254359Sroberto "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 2163182007Sroberto parse->ppsfd, 216454359Sroberto lfptoa(&tstmp, 6)); 216554359Sroberto printf(" sigio %s\n", 216654359Sroberto lfptoa(&ts.fp, 6)); 216754359Sroberto } 216854359Sroberto#endif 216954359Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 217054359Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 217154359Sroberto } 217254359Sroberto } 217354359Sroberto#else /* TIOCDCDTIMESTAMP */ 217454359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 217554359Sroberto if (parse->flags & PARSE_PPSCLOCK) 2176182007Sroberto { 2177182007Sroberto l_fp tts; 2178182007Sroberto struct ppsclockev ev; 217954359Sroberto 218054359Sroberto#ifdef HAVE_CIOGETEV 2181182007Sroberto if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0) 218254359Sroberto#endif 218354359Sroberto#ifdef HAVE_TIOCGPPSEV 2184182007Sroberto if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0) 218554359Sroberto#endif 218654359Sroberto { 2187182007Sroberto if (ev.serial != parse->ppsserial) 2188182007Sroberto { 2189182007Sroberto /* 2190182007Sroberto * add PPS time stamp if available via ppsclock module 2191182007Sroberto * and not supplied already. 2192182007Sroberto */ 2193182007Sroberto if (!buftvtots((const char *)&ev.tv, &tts)) 219454359Sroberto { 2195182007Sroberto ERR(ERR_BADDATA) 2196182007Sroberto msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 219754359Sroberto } 2198182007Sroberto else 2199182007Sroberto { 2200182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tts; 2201182007Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2202182007Sroberto } 2203182007Sroberto } 2204182007Sroberto parse->ppsserial = ev.serial; 220554359Sroberto } 2206182007Sroberto } 220754359Sroberto#endif 220854359Sroberto#endif /* TIOCDCDTIMESTAMP */ 2209182007Sroberto#endif /* !HAVE_PPSAPI */ 221054359Sroberto } 221154359Sroberto if (count) 221254359Sroberto { /* simulate receive */ 2213182007Sroberto buf = get_free_recv_buffer(); 2214182007Sroberto if (buf != NULL) { 2215182007Sroberto memmove((caddr_t)buf->recv_buffer, 2216182007Sroberto (caddr_t)&parse->parseio.parse_dtime, 2217182007Sroberto sizeof(parsetime_t)); 2218182007Sroberto buf->recv_length = sizeof(parsetime_t); 2219182007Sroberto buf->recv_time = rbufp->recv_time; 2220182007Sroberto buf->srcadr = rbufp->srcadr; 2221182007Sroberto buf->dstadr = rbufp->dstadr; 2222182007Sroberto buf->receiver = rbufp->receiver; 2223182007Sroberto buf->fd = rbufp->fd; 2224182007Sroberto buf->X_from_where = rbufp->X_from_where; 2225182007Sroberto add_full_recv_buffer(buf); 2226182007Sroberto } 222754359Sroberto parse_iodone(&parse->parseio); 222854359Sroberto } 222954359Sroberto else 223054359Sroberto { 223156746Sroberto memmove((caddr_t)rbufp->recv_buffer, 223256746Sroberto (caddr_t)&parse->parseio.parse_dtime, 223356746Sroberto sizeof(parsetime_t)); 223456746Sroberto parse_iodone(&parse->parseio); 223554359Sroberto rbufp->recv_length = sizeof(parsetime_t); 223654359Sroberto return 1; /* got something & in place return */ 223754359Sroberto } 223854359Sroberto } 223954359Sroberto } 224054359Sroberto return 0; /* nothing to pass up */ 224154359Sroberto} 224254359Sroberto 224354359Sroberto/*-------------------------------------------------- 224454359Sroberto * local receive 224554359Sroberto */ 224654359Srobertostatic void 224754359Srobertolocal_receive( 224854359Sroberto struct recvbuf *rbufp 224954359Sroberto ) 225054359Sroberto{ 225154359Sroberto struct parseunit *parse = (struct parseunit *)((void *)rbufp->recv_srcclock); 225254359Sroberto parsetime_t parsetime; 225354359Sroberto 225454359Sroberto if (!parse->peer) 225554359Sroberto return; 225654359Sroberto 225754359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 225854359Sroberto { 225954359Sroberto ERR(ERR_BADIO) 226054359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 226154359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 226254359Sroberto parse_event(parse, CEVNT_BADREPLY); 226354359Sroberto return; 226454359Sroberto } 226554359Sroberto clear_err(parse, ERR_BADIO); 226654359Sroberto 226754359Sroberto memmove((caddr_t)&parsetime, 226854359Sroberto (caddr_t)rbufp->recv_buffer, 226954359Sroberto sizeof(parsetime_t)); 227054359Sroberto 227154359Sroberto#ifdef DEBUG 227254359Sroberto if (debug > 3) 227354359Sroberto { 2274182007Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n", 227554359Sroberto CLK_UNIT(parse->peer), 227654359Sroberto (unsigned int)parsetime.parse_status, 227754359Sroberto (unsigned int)parsetime.parse_state, 2278182007Sroberto (unsigned long)parsetime.parse_time.fp.l_ui, 2279182007Sroberto (unsigned long)parsetime.parse_time.fp.l_uf, 2280182007Sroberto (unsigned long)parsetime.parse_stime.fp.l_ui, 2281182007Sroberto (unsigned long)parsetime.parse_stime.fp.l_uf, 2282182007Sroberto (unsigned long)parsetime.parse_ptime.fp.l_ui, 2283182007Sroberto (unsigned long)parsetime.parse_ptime.fp.l_uf); 228454359Sroberto } 228554359Sroberto#endif 228654359Sroberto 228754359Sroberto parse_process(parse, &parsetime); 228854359Sroberto} 228954359Sroberto 229054359Sroberto/*-------------------------------------------------- 229154359Sroberto * init_iobinding - find and initialize lower layers 229254359Sroberto */ 229354359Srobertostatic bind_t * 229454359Srobertoinit_iobinding( 229554359Sroberto struct parseunit *parse 229654359Sroberto ) 229754359Sroberto{ 229854359Sroberto bind_t *b = io_bindings; 229954359Sroberto 230054359Sroberto while (b->bd_description != (char *)0) 230154359Sroberto { 230254359Sroberto if ((*b->bd_init)(parse)) 230354359Sroberto { 230454359Sroberto return b; 230554359Sroberto } 230654359Sroberto b++; 230754359Sroberto } 230854359Sroberto return (bind_t *)0; 230954359Sroberto} 231054359Sroberto 231154359Sroberto/**=========================================================================== 231254359Sroberto ** support routines 231354359Sroberto **/ 231454359Sroberto 231554359Sroberto/*-------------------------------------------------- 231654359Sroberto * convert a flag field to a string 231754359Sroberto */ 231854359Srobertostatic char * 231954359Srobertoparsestate( 232054359Sroberto u_long lstate, 2321182007Sroberto char *buffer, 2322182007Sroberto int size 232354359Sroberto ) 232454359Sroberto{ 232554359Sroberto static struct bits 232654359Sroberto { 232754359Sroberto u_long bit; 232854359Sroberto const char *name; 232954359Sroberto } flagstrings[] = 233054359Sroberto { 233156746Sroberto { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 233256746Sroberto { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 233356746Sroberto { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 233456746Sroberto { PARSEB_DST, "DST" }, 233556746Sroberto { PARSEB_UTC, "UTC DISPLAY" }, 233656746Sroberto { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 233756746Sroberto { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 233854359Sroberto { PARSEB_LEAPSECOND, "LEAP SECOND" }, 233956746Sroberto { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" }, 234056746Sroberto { PARSEB_TIMECODE, "TIME CODE" }, 234156746Sroberto { PARSEB_PPS, "PPS" }, 234256746Sroberto { PARSEB_POSITION, "POSITION" }, 234354359Sroberto { 0 } 234454359Sroberto }; 234554359Sroberto 234654359Sroberto static struct sbits 234754359Sroberto { 234854359Sroberto u_long bit; 234954359Sroberto const char *name; 235054359Sroberto } sflagstrings[] = 235154359Sroberto { 235254359Sroberto { PARSEB_S_LEAP, "LEAP INDICATION" }, 235354359Sroberto { PARSEB_S_PPS, "PPS SIGNAL" }, 235454359Sroberto { PARSEB_S_ANTENNA, "ANTENNA" }, 235554359Sroberto { PARSEB_S_POSITION, "POSITION" }, 235654359Sroberto { 0 } 235754359Sroberto }; 235854359Sroberto int i; 2359182007Sroberto char *s, *t; 236054359Sroberto 2361182007Sroberto 236254359Sroberto *buffer = '\0'; 2363182007Sroberto s = t = buffer; 236454359Sroberto 236554359Sroberto i = 0; 236654359Sroberto while (flagstrings[i].bit) 236754359Sroberto { 236854359Sroberto if (flagstrings[i].bit & lstate) 236954359Sroberto { 2370182007Sroberto if (s != t) 2371182007Sroberto strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 2372182007Sroberto strncat(t, flagstrings[i].name, BUFFER_SIZES(buffer, t, size)); 2373182007Sroberto t += strlen(t); 237454359Sroberto } 237554359Sroberto i++; 237654359Sroberto } 237754359Sroberto 237854359Sroberto if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) 237954359Sroberto { 2380182007Sroberto if (s != t) 2381182007Sroberto strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 238254359Sroberto 2383182007Sroberto t += strlen(t); 238454359Sroberto 2385182007Sroberto strncpy(t, "(", BUFFER_SIZES(buffer, t, size)); 238654359Sroberto 2387182007Sroberto s = t = t + strlen(t); 238854359Sroberto 238954359Sroberto i = 0; 239054359Sroberto while (sflagstrings[i].bit) 239154359Sroberto { 239254359Sroberto if (sflagstrings[i].bit & lstate) 239354359Sroberto { 239454359Sroberto if (t != s) 239554359Sroberto { 2396182007Sroberto strncpy(t, "; ", BUFFER_SIZES(buffer, t, size)); 239754359Sroberto t += 2; 239854359Sroberto } 239954359Sroberto 2400182007Sroberto strncpy(t, sflagstrings[i].name, BUFFER_SIZES(buffer, t, size)); 240154359Sroberto t += strlen(t); 240254359Sroberto } 240354359Sroberto i++; 240454359Sroberto } 2405182007Sroberto strncpy(t, ")", BUFFER_SIZES(buffer, t, size)); 240654359Sroberto } 240754359Sroberto return buffer; 240854359Sroberto} 240954359Sroberto 241054359Sroberto/*-------------------------------------------------- 241154359Sroberto * convert a status flag field to a string 241254359Sroberto */ 241354359Srobertostatic char * 241454359Srobertoparsestatus( 241554359Sroberto u_long lstate, 2416182007Sroberto char *buffer, 2417182007Sroberto int size 241854359Sroberto ) 241954359Sroberto{ 242054359Sroberto static struct bits 242154359Sroberto { 242254359Sroberto u_long bit; 242354359Sroberto const char *name; 242454359Sroberto } flagstrings[] = 242554359Sroberto { 242654359Sroberto { CVT_OK, "CONVERSION SUCCESSFUL" }, 242754359Sroberto { CVT_NONE, "NO CONVERSION" }, 242854359Sroberto { CVT_FAIL, "CONVERSION FAILED" }, 242954359Sroberto { CVT_BADFMT, "ILLEGAL FORMAT" }, 243054359Sroberto { CVT_BADDATE, "DATE ILLEGAL" }, 243154359Sroberto { CVT_BADTIME, "TIME ILLEGAL" }, 243254359Sroberto { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 243354359Sroberto { 0 } 243454359Sroberto }; 243554359Sroberto int i; 243654359Sroberto 243754359Sroberto *buffer = '\0'; 243854359Sroberto 243954359Sroberto i = 0; 244054359Sroberto while (flagstrings[i].bit) 244154359Sroberto { 244254359Sroberto if (flagstrings[i].bit & lstate) 244354359Sroberto { 244454359Sroberto if (buffer[0]) 2445182007Sroberto strncat(buffer, "; ", size); 2446182007Sroberto strncat(buffer, flagstrings[i].name, size); 244754359Sroberto } 244854359Sroberto i++; 244954359Sroberto } 245054359Sroberto 245154359Sroberto return buffer; 245254359Sroberto} 245354359Sroberto 245454359Sroberto/*-------------------------------------------------- 245554359Sroberto * convert a clock status flag field to a string 245654359Sroberto */ 245754359Srobertostatic const char * 245854359Srobertoclockstatus( 245954359Sroberto u_long lstate 246054359Sroberto ) 246154359Sroberto{ 246254359Sroberto static char buffer[20]; 246354359Sroberto static struct status 246454359Sroberto { 246554359Sroberto u_long value; 246654359Sroberto const char *name; 246754359Sroberto } flagstrings[] = 246854359Sroberto { 246954359Sroberto { CEVNT_NOMINAL, "NOMINAL" }, 247054359Sroberto { CEVNT_TIMEOUT, "NO RESPONSE" }, 247154359Sroberto { CEVNT_BADREPLY,"BAD FORMAT" }, 247254359Sroberto { CEVNT_FAULT, "FAULT" }, 247354359Sroberto { CEVNT_PROP, "PROPAGATION DELAY" }, 247454359Sroberto { CEVNT_BADDATE, "ILLEGAL DATE" }, 247554359Sroberto { CEVNT_BADTIME, "ILLEGAL TIME" }, 247654359Sroberto { (unsigned)~0L } 247754359Sroberto }; 247854359Sroberto int i; 247954359Sroberto 248054359Sroberto i = 0; 248154359Sroberto while (flagstrings[i].value != ~0) 248254359Sroberto { 248354359Sroberto if (flagstrings[i].value == lstate) 248454359Sroberto { 248554359Sroberto return flagstrings[i].name; 248654359Sroberto } 248754359Sroberto i++; 248854359Sroberto } 248954359Sroberto 2490182007Sroberto snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate); 249154359Sroberto 249254359Sroberto return buffer; 249354359Sroberto} 249454359Sroberto 249554359Sroberto 249654359Sroberto/*-------------------------------------------------- 249754359Sroberto * l_mktime - make representation of a relative time 249854359Sroberto */ 249954359Srobertostatic char * 250054359Srobertol_mktime( 250154359Sroberto u_long delta 250254359Sroberto ) 250354359Sroberto{ 250454359Sroberto u_long tmp, m, s; 250554359Sroberto static char buffer[40]; 2506182007Sroberto char *t; 250754359Sroberto 250854359Sroberto buffer[0] = '\0'; 250954359Sroberto 251054359Sroberto if ((tmp = delta / (60*60*24)) != 0) 251154359Sroberto { 2512182007Sroberto snprintf(buffer, BUFFER_SIZE(buffer, buffer), "%ldd+", (u_long)tmp); 251354359Sroberto delta -= tmp * 60*60*24; 251454359Sroberto } 251554359Sroberto 251654359Sroberto s = delta % 60; 251754359Sroberto delta /= 60; 251854359Sroberto m = delta % 60; 251954359Sroberto delta /= 60; 252054359Sroberto 2521182007Sroberto t = buffer + strlen(buffer); 252254359Sroberto 2523182007Sroberto snprintf(t, BUFFER_SIZE(buffer, t), "%02d:%02d:%02d", 2524182007Sroberto (int)delta, (int)m, (int)s); 2525182007Sroberto 252654359Sroberto return buffer; 252754359Sroberto} 252854359Sroberto 252954359Sroberto 253054359Sroberto/*-------------------------------------------------- 253154359Sroberto * parse_statistics - list summary of clock states 253254359Sroberto */ 253354359Srobertostatic void 253454359Srobertoparse_statistics( 253554359Sroberto struct parseunit *parse 253654359Sroberto ) 253754359Sroberto{ 253854359Sroberto int i; 253954359Sroberto 254054359Sroberto NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 254154359Sroberto { 254254359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 254354359Sroberto CLK_UNIT(parse->peer), 254454359Sroberto l_mktime(current_time - parse->generic->timestarted)); 254554359Sroberto 254654359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 254754359Sroberto CLK_UNIT(parse->peer), 254854359Sroberto clockstatus(parse->generic->currentstatus)); 254954359Sroberto 255054359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 255154359Sroberto { 255254359Sroberto u_long s_time; 255354359Sroberto u_long percent, d = current_time - parse->generic->timestarted; 255454359Sroberto 255554359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 255654359Sroberto 255754359Sroberto while (((u_long)(~0) / 10000) < percent) 255854359Sroberto { 255954359Sroberto percent /= 10; 256054359Sroberto d /= 10; 256154359Sroberto } 256254359Sroberto 256354359Sroberto if (d) 256454359Sroberto percent = (percent * 10000) / d; 256554359Sroberto else 256654359Sroberto percent = 10000; 256754359Sroberto 256854359Sroberto if (s_time) 256954359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 257054359Sroberto CLK_UNIT(parse->peer), 257154359Sroberto clockstatus((unsigned int)i), 257254359Sroberto l_mktime(s_time), 257354359Sroberto percent / 100, percent % 100); 257454359Sroberto } 257554359Sroberto } 257654359Sroberto} 257754359Sroberto 257854359Sroberto/*-------------------------------------------------- 257954359Sroberto * cparse_statistics - wrapper for statistics call 258054359Sroberto */ 258154359Srobertostatic void 258254359Srobertocparse_statistics( 2583182007Sroberto struct parseunit *parse 258454359Sroberto ) 258554359Sroberto{ 258654359Sroberto if (parse->laststatistic + PARSESTATISTICS < current_time) 258754359Sroberto parse_statistics(parse); 258854359Sroberto parse->laststatistic = current_time; 258954359Sroberto} 259054359Sroberto 259154359Sroberto/**=========================================================================== 259254359Sroberto ** ntp interface routines 259354359Sroberto **/ 259454359Sroberto 259554359Sroberto/*-------------------------------------------------- 259654359Sroberto * parse_shutdown - shut down a PARSE clock 259754359Sroberto */ 259854359Srobertostatic void 259954359Srobertoparse_shutdown( 260054359Sroberto int unit, 260154359Sroberto struct peer *peer 260254359Sroberto ) 260354359Sroberto{ 2604182007Sroberto struct parseunit *parse = (struct parseunit *)0; 260554359Sroberto 2606182007Sroberto if (peer && peer->procptr) 2607182007Sroberto parse = (struct parseunit *)peer->procptr->unitptr; 2608182007Sroberto 2609182007Sroberto if (!parse) 261054359Sroberto { 2611182007Sroberto /* nothing to clean up */ 261254359Sroberto return; 261354359Sroberto } 261454359Sroberto 2615182007Sroberto if (!parse->peer) 2616182007Sroberto { 2617182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit); 2618182007Sroberto return; 2619182007Sroberto } 2620182007Sroberto 2621182007Sroberto#ifdef HAVE_PPSAPI 2622182007Sroberto if (parse->flags & PARSE_PPSCLOCK) 2623182007Sroberto { 2624182007Sroberto (void)time_pps_destroy(parse->ppshandle); 2625182007Sroberto } 2626182007Sroberto#endif 2627182007Sroberto if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2628182007Sroberto (void)close(parse->ppsfd); /* close separate PPS source */ 2629182007Sroberto 263054359Sroberto /* 263154359Sroberto * print statistics a last time and 263254359Sroberto * stop statistics machine 263354359Sroberto */ 263454359Sroberto parse_statistics(parse); 263554359Sroberto 263654359Sroberto if (parse->parse_type->cl_end) 263754359Sroberto { 263854359Sroberto parse->parse_type->cl_end(parse); 263954359Sroberto } 264054359Sroberto 2641182007Sroberto /* 2642182007Sroberto * cleanup before leaving this world 2643182007Sroberto */ 264454359Sroberto if (parse->binding) 264554359Sroberto PARSE_END(parse); 264654359Sroberto 264754359Sroberto /* 264854359Sroberto * Tell the I/O module to turn us off. We're history. 264954359Sroberto */ 265054359Sroberto io_closeclock(&parse->generic->io); 265154359Sroberto 265254359Sroberto free_varlist(parse->kv); 265354359Sroberto 265454359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 265554359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 265654359Sroberto CLK_UNIT(parse->peer), parse->parse_type->cl_description); 265754359Sroberto 265854359Sroberto parse->peer = (struct peer *)0; /* unused now */ 2659182007Sroberto peer->procptr->unitptr = (caddr_t)0; 266054359Sroberto free(parse); 266154359Sroberto} 266254359Sroberto 2663182007Sroberto#ifdef HAVE_PPSAPI 2664182007Sroberto/*---------------------------------------- 2665182007Sroberto * set up HARDPPS via PPSAPI 2666182007Sroberto */ 2667182007Srobertostatic void 2668182007Srobertoparse_hardpps( 2669182007Sroberto struct parseunit *parse, 2670182007Sroberto int mode 2671182007Sroberto ) 2672182007Sroberto{ 2673182007Sroberto if (parse->hardppsstate == mode) 2674182007Sroberto return; 2675182007Sroberto 2676182007Sroberto if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) { 2677182007Sroberto int i = 0; 2678182007Sroberto 2679182007Sroberto if (mode == PARSE_HARDPPS_ENABLE) 2680182007Sroberto { 2681182007Sroberto if (parse->flags & PARSE_CLEAR) 2682182007Sroberto i = PPS_CAPTURECLEAR; 2683182007Sroberto else 2684182007Sroberto i = PPS_CAPTUREASSERT; 2685182007Sroberto } 2686182007Sroberto 2687182007Sroberto if (time_pps_kcbind(parse->ppshandle, PPS_KC_HARDPPS, i, 2688182007Sroberto PPS_TSFMT_TSPEC) < 0) { 2689182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m", 2690182007Sroberto CLK_UNIT(parse->peer)); 2691182007Sroberto } else { 2692182007Sroberto NLOG(NLOG_CLOCKINFO) 2693182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled", 2694182007Sroberto CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis"); 2695182007Sroberto /* 2696182007Sroberto * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS 2697182007Sroberto */ 2698182007Sroberto if (mode == PARSE_HARDPPS_ENABLE) 2699182007Sroberto pps_enable = 1; 2700182007Sroberto } 2701182007Sroberto } 2702182007Sroberto 2703182007Sroberto parse->hardppsstate = mode; 2704182007Sroberto} 2705182007Sroberto 2706182007Sroberto/*---------------------------------------- 2707182007Sroberto * set up PPS via PPSAPI 2708182007Sroberto */ 2709182007Srobertostatic int 2710182007Srobertoparse_ppsapi( 2711182007Sroberto struct parseunit *parse 2712182007Sroberto ) 2713182007Sroberto{ 2714182007Sroberto int cap, mode, mode1; 2715182007Sroberto char *cp; 2716182007Sroberto 2717182007Sroberto parse->flags &= ~PARSE_PPSCLOCK; 2718182007Sroberto 2719182007Sroberto if (time_pps_getcap(parse->ppshandle, &cap) < 0) { 2720182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m", 2721182007Sroberto CLK_UNIT(parse->peer)); 2722182007Sroberto 2723182007Sroberto return 0; 2724182007Sroberto } 2725182007Sroberto 2726182007Sroberto if (time_pps_getparams(parse->ppshandle, &parse->ppsparams) < 0) { 2727182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getparams failed: %m", 2728182007Sroberto CLK_UNIT(parse->peer)); 2729182007Sroberto return 0; 2730182007Sroberto } 2731182007Sroberto 2732182007Sroberto /* nb. only turn things on, if someone else has turned something 2733182007Sroberto * on before we get here, leave it alone! 2734182007Sroberto */ 2735182007Sroberto 2736182007Sroberto if (parse->flags & PARSE_CLEAR) { 2737182007Sroberto cp = "CLEAR"; 2738182007Sroberto mode = PPS_CAPTURECLEAR; 2739182007Sroberto mode1 = PPS_OFFSETCLEAR; 2740182007Sroberto } else { 2741182007Sroberto cp = "ASSERT"; 2742182007Sroberto mode = PPS_CAPTUREASSERT; 2743182007Sroberto mode1 = PPS_OFFSETASSERT; 2744182007Sroberto } 2745182007Sroberto 2746182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2747182007Sroberto CLK_UNIT(parse->peer), cp); 2748182007Sroberto 2749182007Sroberto if (!(mode & cap)) { 2750182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: FAILED to initialize PPS to %s (PPS API capabilities=0x%x)", 2751182007Sroberto CLK_UNIT(parse->peer), cp, cap); 2752182007Sroberto 2753182007Sroberto return 0; 2754182007Sroberto } 2755182007Sroberto 2756182007Sroberto if (!(mode1 & cap)) { 2757182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)", 2758182007Sroberto CLK_UNIT(parse->peer), cp, cap); 2759182007Sroberto mode1 = 0; 2760182007Sroberto } else { 2761182007Sroberto if (mode1 == PPS_OFFSETCLEAR) 2762182007Sroberto { 2763182007Sroberto parse->ppsparams.clear_offset.tv_sec = -parse->ppsphaseadjust; 2764182007Sroberto parse->ppsparams.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2765182007Sroberto } 2766182007Sroberto 2767182007Sroberto if (mode1 == PPS_OFFSETASSERT) 2768182007Sroberto { 2769182007Sroberto parse->ppsparams.assert_offset.tv_sec = -parse->ppsphaseadjust; 2770182007Sroberto parse->ppsparams.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2771182007Sroberto } 2772182007Sroberto } 2773182007Sroberto 2774182007Sroberto /* only set what is legal */ 2775182007Sroberto 2776182007Sroberto parse->ppsparams.mode = (mode | mode1 | PPS_TSFMT_TSPEC) & cap; 2777182007Sroberto 2778182007Sroberto if (time_pps_setparams(parse->ppshandle, &parse->ppsparams) < 0) { 2779182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m", 2780182007Sroberto CLK_UNIT(parse->peer)); 2781182007Sroberto return 0; 2782182007Sroberto } 2783182007Sroberto 2784182007Sroberto parse->flags |= PARSE_PPSCLOCK; 2785182007Sroberto return 1; 2786182007Sroberto} 2787182007Sroberto#else 2788182007Sroberto#define parse_hardpps(_PARSE_, _MODE_) /* empty */ 2789182007Sroberto#endif 2790182007Sroberto 279154359Sroberto/*-------------------------------------------------- 279254359Sroberto * parse_start - open the PARSE devices and initialize data for processing 279354359Sroberto */ 279454359Srobertostatic int 279554359Srobertoparse_start( 279654359Sroberto int sysunit, 279754359Sroberto struct peer *peer 279854359Sroberto ) 279954359Sroberto{ 280054359Sroberto u_int unit; 280154359Sroberto int fd232; 280254359Sroberto#ifdef HAVE_TERMIOS 280354359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 280454359Sroberto#endif 280554359Sroberto#ifdef HAVE_SYSV_TTYS 280654359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 280754359Sroberto#endif 280854359Sroberto struct parseunit * parse; 280954359Sroberto char parsedev[sizeof(PARSEDEVICE)+20]; 2810182007Sroberto char parseppsdev[sizeof(PARSEPPSDEVICE)+20]; 281154359Sroberto parsectl_t tmp_ctl; 281254359Sroberto u_int type; 281354359Sroberto 2814182007Sroberto /* 2815182007Sroberto * get out Copyright information once 2816182007Sroberto */ 2817182007Sroberto if (!notice) 2818182007Sroberto { 2819182007Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2820182007Sroberto msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2006, Frank Kardel"); 2821182007Sroberto notice = 1; 2822182007Sroberto } 2823182007Sroberto 282454359Sroberto type = CLK_TYPE(peer); 282554359Sroberto unit = CLK_UNIT(peer); 282654359Sroberto 282754359Sroberto if ((type == ~0) || (parse_clockinfo[type].cl_description == (char *)0)) 282854359Sroberto { 282954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 283054359Sroberto unit, CLK_REALTYPE(peer), ncltypes-1); 283154359Sroberto return 0; 283254359Sroberto } 283354359Sroberto 283454359Sroberto /* 283554359Sroberto * Unit okay, attempt to open the device. 283654359Sroberto */ 2837182007Sroberto (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit); 2838182007Sroberto (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit); 283954359Sroberto 284054359Sroberto#ifndef O_NOCTTY 284154359Sroberto#define O_NOCTTY 0 284254359Sroberto#endif 284354359Sroberto 284454359Sroberto fd232 = open(parsedev, O_RDWR | O_NOCTTY 284554359Sroberto#ifdef O_NONBLOCK 284654359Sroberto | O_NONBLOCK 284754359Sroberto#endif 284854359Sroberto , 0777); 284954359Sroberto 285054359Sroberto if (fd232 == -1) 285154359Sroberto { 285254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 285354359Sroberto return 0; 285454359Sroberto } 285554359Sroberto 285654359Sroberto parse = (struct parseunit *)emalloc(sizeof(struct parseunit)); 285754359Sroberto 285854359Sroberto memset((char *)parse, 0, sizeof(struct parseunit)); 285954359Sroberto 286054359Sroberto parse->generic = peer->procptr; /* link up */ 286154359Sroberto parse->generic->unitptr = (caddr_t)parse; /* link down */ 286254359Sroberto 286354359Sroberto /* 286454359Sroberto * Set up the structures 286554359Sroberto */ 286654359Sroberto parse->generic->timestarted = current_time; 286754359Sroberto parse->lastchange = current_time; 286854359Sroberto 286954359Sroberto parse->flags = 0; 287054359Sroberto parse->pollneeddata = 0; 287154359Sroberto parse->laststatistic = current_time; 287254359Sroberto parse->lastformat = (unsigned short)~0; /* assume no format known */ 2873182007Sroberto parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 287454359Sroberto parse->lastmissed = 0; /* assume got everything */ 287554359Sroberto parse->ppsserial = 0; 2876182007Sroberto parse->ppsfd = -1; 287754359Sroberto parse->localdata = (void *)0; 287854359Sroberto parse->localstate = 0; 287954359Sroberto parse->kv = (struct ctl_var *)0; 288054359Sroberto 288154359Sroberto clear_err(parse, ERR_ALL); 288254359Sroberto 288354359Sroberto parse->parse_type = &parse_clockinfo[type]; 288454359Sroberto 2885182007Sroberto parse->maxunsync = parse->parse_type->cl_maxunsync; 2886182007Sroberto 288754359Sroberto parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 288854359Sroberto 288954359Sroberto parse->generic->fudgetime2 = 0.0; 2890182007Sroberto parse->ppsphaseadjust = parse->generic->fudgetime2; 289154359Sroberto 2892182007Sroberto parse->generic->clockdesc = parse->parse_type->cl_description; 289354359Sroberto 289454359Sroberto peer->rootdelay = parse->parse_type->cl_rootdelay; 289554359Sroberto peer->sstclktype = parse->parse_type->cl_type; 289654359Sroberto peer->precision = sys_precision; 289754359Sroberto 289854359Sroberto peer->stratum = STRATUM_REFCLOCK; 2899182007Sroberto 290054359Sroberto if (peer->stratum <= 1) 290154359Sroberto memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 290254359Sroberto else 290354359Sroberto parse->generic->refid = htonl(PARSEHSREFID); 290454359Sroberto 290554359Sroberto parse->generic->io.fd = fd232; 290654359Sroberto 290754359Sroberto parse->peer = peer; /* marks it also as busy */ 290854359Sroberto 290954359Sroberto /* 291054359Sroberto * configure terminal line 291154359Sroberto */ 291254359Sroberto if (TTY_GETATTR(fd232, &tio) == -1) 291354359Sroberto { 291454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 291554359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 291654359Sroberto return 0; 291754359Sroberto } 291854359Sroberto else 291954359Sroberto { 292054359Sroberto#ifndef _PC_VDISABLE 292154359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 292254359Sroberto#else 292354359Sroberto int disablec; 292454359Sroberto errno = 0; /* pathconf can deliver -1 without changing errno ! */ 292554359Sroberto 292654359Sroberto disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 292754359Sroberto if (disablec == -1 && errno) 292854359Sroberto { 292954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 293054359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 293154359Sroberto } 293254359Sroberto else 293354359Sroberto if (disablec != -1) 293454359Sroberto memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 293554359Sroberto#endif 293654359Sroberto 293754359Sroberto#if defined (VMIN) || defined(VTIME) 293854359Sroberto if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 293954359Sroberto { 294054359Sroberto#ifdef VMIN 294154359Sroberto tio.c_cc[VMIN] = 1; 294254359Sroberto#endif 294354359Sroberto#ifdef VTIME 294454359Sroberto tio.c_cc[VTIME] = 0; 294554359Sroberto#endif 294654359Sroberto } 294754359Sroberto#endif 294854359Sroberto 294954359Sroberto tio.c_cflag = parse_clockinfo[type].cl_cflag; 295054359Sroberto tio.c_iflag = parse_clockinfo[type].cl_iflag; 295154359Sroberto tio.c_oflag = parse_clockinfo[type].cl_oflag; 295254359Sroberto tio.c_lflag = parse_clockinfo[type].cl_lflag; 295354359Sroberto 295454359Sroberto 295554359Sroberto#ifdef HAVE_TERMIOS 295654359Sroberto if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || 295754359Sroberto (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) 295854359Sroberto { 295954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 296054359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 296154359Sroberto return 0; 296254359Sroberto } 296354359Sroberto#else 296454359Sroberto tio.c_cflag |= parse_clockinfo[type].cl_speed; 296554359Sroberto#endif 296654359Sroberto 2967182007Sroberto /* 2968182007Sroberto * set up pps device 2969182007Sroberto * if the PARSEPPSDEVICE can be opened that will be used 2970182007Sroberto * for PPS else PARSEDEVICE will be used 2971182007Sroberto */ 2972182007Sroberto parse->ppsfd = open(parseppsdev, O_RDWR | O_NOCTTY 2973182007Sroberto#ifdef O_NONBLOCK 2974182007Sroberto | O_NONBLOCK 2975182007Sroberto#endif 2976182007Sroberto , 0777); 2977182007Sroberto 2978182007Sroberto if (parse->ppsfd == -1) 2979182007Sroberto { 2980182007Sroberto parse->ppsfd = fd232; 2981182007Sroberto } 2982182007Sroberto 2983182007Sroberto/* 2984182007Sroberto * Linux PPS - the old way 2985182007Sroberto */ 298654359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 298754359Sroberto { 2988182007Sroberto struct serial_struct ss; 2989182007Sroberto if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 || 2990182007Sroberto ( 299154359Sroberto#ifdef ASYNC_LOW_LATENCY 2992182007Sroberto ss.flags |= ASYNC_LOW_LATENCY, 299354359Sroberto#endif 2994182007Sroberto#ifndef HAVE_PPSAPI 299554359Sroberto#ifdef ASYNC_PPS_CD_NEG 2996182007Sroberto ss.flags |= ASYNC_PPS_CD_NEG, 299754359Sroberto#endif 2998182007Sroberto#endif 2999182007Sroberto ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) { 3000182007Sroberto msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd); 3001182007Sroberto msyslog(LOG_NOTICE, 3002182007Sroberto "refclock_parse: optional PPS processing not available"); 3003182007Sroberto } else { 3004182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3005182007Sroberto#ifdef ASYNC_PPS_CD_NEG 3006182007Sroberto NLOG(NLOG_CLOCKINFO) 3007182007Sroberto msyslog(LOG_INFO, 3008182007Sroberto "refclock_parse: PPS detection on"); 3009182007Sroberto#endif 3010182007Sroberto } 301154359Sroberto } 301254359Sroberto#endif 3013182007Sroberto 3014182007Sroberto/* 3015182007Sroberto * SUN the Solaris way 3016182007Sroberto */ 301754359Sroberto#ifdef HAVE_TIOCSPPS /* SUN PPS support */ 301854359Sroberto if (CLK_PPS(parse->peer)) 3019182007Sroberto { 3020182007Sroberto int i = 1; 302154359Sroberto 3022182007Sroberto if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0) 3023182007Sroberto { 3024182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3025182007Sroberto } 3026182007Sroberto } 302754359Sroberto#endif 302854359Sroberto 3029182007Sroberto/* 3030182007Sroberto * PPS via PPSAPI 3031182007Sroberto */ 3032182007Sroberto#if defined(HAVE_PPSAPI) 3033182007Sroberto parse->hardppsstate = PARSE_HARDPPS_DISABLE; 3034182007Sroberto if (CLK_PPS(parse->peer)) 3035182007Sroberto { 3036182007Sroberto if (time_pps_create(parse->ppsfd, &parse->ppshandle) < 0) 3037182007Sroberto { 3038182007Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer)); 3039182007Sroberto } 3040182007Sroberto else 3041182007Sroberto { 3042182007Sroberto parse_ppsapi(parse); 3043182007Sroberto } 3044182007Sroberto } 3045182007Sroberto#endif 3046182007Sroberto 304754359Sroberto if (TTY_SETATTR(fd232, &tio) == -1) 304854359Sroberto { 304954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 305054359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 305154359Sroberto return 0; 305254359Sroberto } 305354359Sroberto } 305454359Sroberto 305554359Sroberto /* 3056182007Sroberto * pick correct input machine 305754359Sroberto */ 305854359Sroberto parse->generic->io.srcclock = (caddr_t)parse; 305954359Sroberto parse->generic->io.datalen = 0; 306054359Sroberto 306154359Sroberto parse->binding = init_iobinding(parse); 306254359Sroberto 306354359Sroberto if (parse->binding == (bind_t *)0) 306454359Sroberto { 306554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 306654359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 306754359Sroberto return 0; /* well, ok - special initialisation broke */ 306854359Sroberto } 306954359Sroberto 3070182007Sroberto parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 3071182007Sroberto parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 3072182007Sroberto 307354359Sroberto /* 307454359Sroberto * as we always(?) get 8 bit chars we want to be 307554359Sroberto * sure, that the upper bits are zero for less 307654359Sroberto * than 8 bit I/O - so we pass that information on. 307754359Sroberto * note that there can be only one bit count format 307854359Sroberto * per file descriptor 307954359Sroberto */ 308054359Sroberto 308154359Sroberto switch (tio.c_cflag & CSIZE) 308254359Sroberto { 308354359Sroberto case CS5: 308454359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 308554359Sroberto break; 308654359Sroberto 308754359Sroberto case CS6: 308854359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 308954359Sroberto break; 309054359Sroberto 309154359Sroberto case CS7: 309254359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 309354359Sroberto break; 309454359Sroberto 309554359Sroberto case CS8: 309654359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 309754359Sroberto break; 309854359Sroberto } 309954359Sroberto 310054359Sroberto if (!PARSE_SETCS(parse, &tmp_ctl)) 310154359Sroberto { 310254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 310354359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 310454359Sroberto return 0; /* well, ok - special initialisation broke */ 310554359Sroberto } 310654359Sroberto 3107182007Sroberto strncpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 310854359Sroberto tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); 310954359Sroberto 311054359Sroberto if (!PARSE_SETFMT(parse, &tmp_ctl)) 311154359Sroberto { 311254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 311354359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 311454359Sroberto return 0; /* well, ok - special initialisation broke */ 311554359Sroberto } 311654359Sroberto 311754359Sroberto /* 311854359Sroberto * get rid of all IO accumulated so far 311954359Sroberto */ 312054359Sroberto#ifdef HAVE_TERMIOS 312154359Sroberto (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 312254359Sroberto#else 3123182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH) 312454359Sroberto { 312554359Sroberto int flshcmd = TCIOFLUSH; 312654359Sroberto 312754359Sroberto (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 312854359Sroberto } 312954359Sroberto#endif 313054359Sroberto#endif 313156746Sroberto 313254359Sroberto /* 313354359Sroberto * try to do any special initializations 313454359Sroberto */ 313554359Sroberto if (parse->parse_type->cl_init) 313654359Sroberto { 313754359Sroberto if (parse->parse_type->cl_init(parse)) 313854359Sroberto { 313954359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 314054359Sroberto return 0; /* well, ok - special initialisation broke */ 314154359Sroberto } 314254359Sroberto } 314354359Sroberto 314454359Sroberto /* 3145182007Sroberto * Insert in async io device list. 314654359Sroberto */ 3147182007Sroberto if (!io_addclock(&parse->generic->io)) 314854359Sroberto { 3149182007Sroberto msyslog(LOG_ERR, 3150182007Sroberto "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 3151182007Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3152182007Sroberto return 0; 315354359Sroberto } 315454359Sroberto 315554359Sroberto /* 315654359Sroberto * print out configuration 315754359Sroberto */ 315854359Sroberto NLOG(NLOG_CLOCKINFO) 315954359Sroberto { 316054359Sroberto /* conditional if clause for conditional syslog */ 3161182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added", 316254359Sroberto CLK_UNIT(parse->peer), 3163182007Sroberto parse->parse_type->cl_description, parsedev, 3164182007Sroberto (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev); 316554359Sroberto 3166182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d", 316754359Sroberto CLK_UNIT(parse->peer), 3168182007Sroberto parse->peer->stratum, 3169182007Sroberto l_mktime(parse->maxunsync), parse->peer->precision); 317054359Sroberto 3171182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling", 317254359Sroberto CLK_UNIT(parse->peer), 317354359Sroberto parse->parse_type->cl_rootdelay, 317454359Sroberto parse->generic->fudgetime1, 3175182007Sroberto parse->ppsphaseadjust, 3176182007Sroberto parse->binding->bd_description); 317754359Sroberto 3178182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 317954359Sroberto parse->parse_type->cl_format); 3180182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer), 3181182007Sroberto CLK_PPS(parse->peer) ? "" : "NO ", 3182182007Sroberto CLK_PPS(parse->peer) ? 3183182007Sroberto#ifdef PPS_METHOD 3184182007Sroberto " (implementation " PPS_METHOD ")" 3185182007Sroberto#else 3186182007Sroberto "" 318754359Sroberto#endif 3188182007Sroberto : "" 3189182007Sroberto ); 319054359Sroberto } 319154359Sroberto 319254359Sroberto return 1; 319354359Sroberto} 319454359Sroberto 319554359Sroberto/*-------------------------------------------------- 3196182007Sroberto * parse_ctl - process changes on flags/time values 3197182007Sroberto */ 3198182007Srobertostatic void 3199182007Srobertoparse_ctl( 3200182007Sroberto struct parseunit *parse, 3201182007Sroberto struct refclockstat *in 3202182007Sroberto ) 3203182007Sroberto{ 3204182007Sroberto if (in) 3205182007Sroberto { 3206182007Sroberto if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3207182007Sroberto { 3208182007Sroberto parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) | 3209182007Sroberto (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)); 3210182007Sroberto#if defined(HAVE_PPSAPI) 3211182007Sroberto if (CLK_PPS(parse->peer)) 3212182007Sroberto { 3213182007Sroberto parse_ppsapi(parse); 3214182007Sroberto } 3215182007Sroberto#endif 3216182007Sroberto } 3217182007Sroberto 3218182007Sroberto if (in->haveflags & CLK_HAVETIME1) 3219182007Sroberto { 3220182007Sroberto parse->generic->fudgetime1 = in->fudgetime1; 3221182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s", 3222182007Sroberto CLK_UNIT(parse->peer), 3223182007Sroberto parse->generic->fudgetime1); 3224182007Sroberto } 3225182007Sroberto 3226182007Sroberto if (in->haveflags & CLK_HAVETIME2) 3227182007Sroberto { 3228182007Sroberto parse->generic->fudgetime2 = in->fudgetime2; 3229182007Sroberto if (parse->flags & PARSE_TRUSTTIME) 3230182007Sroberto { 3231182007Sroberto parse->maxunsync = (u_long)ABS(in->fudgetime2); 3232182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s", 3233182007Sroberto CLK_UNIT(parse->peer), 3234182007Sroberto l_mktime(parse->maxunsync)); 3235182007Sroberto } 3236182007Sroberto else 3237182007Sroberto { 3238182007Sroberto parse->ppsphaseadjust = in->fudgetime2; 3239182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s", 3240182007Sroberto CLK_UNIT(parse->peer), 3241182007Sroberto parse->ppsphaseadjust); 3242182007Sroberto#if defined(HAVE_PPSAPI) 3243182007Sroberto if (CLK_PPS(parse->peer)) 3244182007Sroberto { 3245182007Sroberto parse_ppsapi(parse); 3246182007Sroberto } 3247182007Sroberto#endif 3248182007Sroberto } 3249182007Sroberto } 3250182007Sroberto } 3251182007Sroberto} 3252182007Sroberto 3253182007Sroberto/*-------------------------------------------------- 325454359Sroberto * parse_poll - called by the transmit procedure 325554359Sroberto */ 325654359Srobertostatic void 325754359Srobertoparse_poll( 325854359Sroberto int unit, 325954359Sroberto struct peer *peer 326054359Sroberto ) 326154359Sroberto{ 326254359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 326354359Sroberto 326454359Sroberto if (peer != parse->peer) 326554359Sroberto { 326654359Sroberto msyslog(LOG_ERR, 326754359Sroberto "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 326854359Sroberto unit); 326954359Sroberto return; 327054359Sroberto } 327154359Sroberto 327254359Sroberto /* 327354359Sroberto * Update clock stat counters 327454359Sroberto */ 327554359Sroberto parse->generic->polls++; 327654359Sroberto 327756746Sroberto if (parse->pollneeddata && 327856746Sroberto ((current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 327954359Sroberto { 328054359Sroberto /* 328156746Sroberto * start worrying when exceeding a poll inteval 328254359Sroberto * bad news - didn't get a response last time 328354359Sroberto */ 328454359Sroberto parse->lastmissed = current_time; 328554359Sroberto parse_event(parse, CEVNT_TIMEOUT); 328654359Sroberto 328754359Sroberto ERR(ERR_NODATA) 3288182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer)); 328954359Sroberto } 329054359Sroberto 329154359Sroberto /* 329254359Sroberto * we just mark that we want the next sample for the clock filter 329354359Sroberto */ 329456746Sroberto parse->pollneeddata = current_time; 329554359Sroberto 329654359Sroberto if (parse->parse_type->cl_poll) 329754359Sroberto { 329854359Sroberto parse->parse_type->cl_poll(parse); 329954359Sroberto } 330054359Sroberto 330154359Sroberto cparse_statistics(parse); 330254359Sroberto 330354359Sroberto return; 330454359Sroberto} 330554359Sroberto 330654359Sroberto#define LEN_STATES 300 /* length of state string */ 330754359Sroberto 330854359Sroberto/*-------------------------------------------------- 330954359Sroberto * parse_control - set fudge factors, return statistics 331054359Sroberto */ 331154359Srobertostatic void 331254359Srobertoparse_control( 331354359Sroberto int unit, 331454359Sroberto struct refclockstat *in, 331554359Sroberto struct refclockstat *out, 331654359Sroberto struct peer *peer 331754359Sroberto ) 331854359Sroberto{ 3319182007Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 332054359Sroberto parsectl_t tmpctl; 332154359Sroberto 332254359Sroberto static char outstatus[400]; /* status output buffer */ 332354359Sroberto 332454359Sroberto if (out) 332554359Sroberto { 332654359Sroberto out->lencode = 0; 332754359Sroberto out->p_lastcode = 0; 332854359Sroberto out->kv_list = (struct ctl_var *)0; 332954359Sroberto } 333054359Sroberto 333154359Sroberto if (!parse || !parse->peer) 333254359Sroberto { 333354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 333454359Sroberto unit); 333554359Sroberto return; 333654359Sroberto } 333754359Sroberto 333854359Sroberto unit = CLK_UNIT(parse->peer); 333954359Sroberto 3340182007Sroberto /* 3341182007Sroberto * handle changes 3342182007Sroberto */ 3343182007Sroberto parse_ctl(parse, in); 3344182007Sroberto 3345182007Sroberto /* 3346182007Sroberto * supply data 3347182007Sroberto */ 334854359Sroberto if (out) 334954359Sroberto { 335054359Sroberto u_long sum = 0; 3351182007Sroberto char *tt, *start; 335254359Sroberto int i; 335354359Sroberto 335454359Sroberto outstatus[0] = '\0'; 335554359Sroberto 335654359Sroberto out->type = REFCLK_PARSE; 335754359Sroberto 335854359Sroberto /* 3359182007Sroberto * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1 3360182007Sroberto */ 3361182007Sroberto parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust; 3362182007Sroberto 3363182007Sroberto /* 336454359Sroberto * figure out skew between PPS and RS232 - just for informational 3365182007Sroberto * purposes 336654359Sroberto */ 3367182007Sroberto if (PARSE_SYNC(parse->timedata.parse_state)) 336854359Sroberto { 3369182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state)) 337054359Sroberto { 337154359Sroberto l_fp off; 337254359Sroberto 337354359Sroberto /* 337454359Sroberto * we have a PPS and RS232 signal - calculate the skew 337554359Sroberto * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 337654359Sroberto */ 3377182007Sroberto off = parse->timedata.parse_stime.fp; 3378182007Sroberto L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */ 337954359Sroberto tt = add_var(&out->kv_list, 80, RO); 3380182007Sroberto snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6)); 338154359Sroberto } 338254359Sroberto } 338354359Sroberto 3384182007Sroberto if (PARSE_PPS(parse->timedata.parse_state)) 338554359Sroberto { 338654359Sroberto tt = add_var(&out->kv_list, 80, RO|DEF); 3387182007Sroberto snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp)); 338854359Sroberto } 338954359Sroberto 3390182007Sroberto start = tt = add_var(&out->kv_list, 128, RO|DEF); 3391182007Sroberto snprintf(tt, 128, "refclock_time=\""); 339254359Sroberto tt += strlen(tt); 339354359Sroberto 3394182007Sroberto if (parse->timedata.parse_time.fp.l_ui == 0) 339554359Sroberto { 3396182007Sroberto strncpy(tt, "<UNDEFINED>\"", BUFFER_SIZES(start, tt, 128)); 339754359Sroberto } 339854359Sroberto else 339954359Sroberto { 3400182007Sroberto snprintf(tt, 128, "%s\"", gmprettydate(&parse->timedata.parse_time.fp)); 340154359Sroberto } 340254359Sroberto 340354359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 340454359Sroberto { 340554359Sroberto ERR(ERR_INTERNAL) 340654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 340754359Sroberto } 340854359Sroberto else 340954359Sroberto { 3410182007Sroberto start = tt = add_var(&out->kv_list, 512, RO|DEF); 3411182007Sroberto snprintf(tt, 512, "refclock_status=\""); 341254359Sroberto tt += strlen(tt); 341354359Sroberto 341454359Sroberto /* 341554359Sroberto * copy PPS flags from last read transaction (informational only) 341654359Sroberto */ 3417182007Sroberto tmpctl.parsegettc.parse_state |= parse->timedata.parse_state & 341854359Sroberto (PARSEB_PPS|PARSEB_S_PPS); 341954359Sroberto 3420182007Sroberto (void) parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 342154359Sroberto 3422182007Sroberto strncat(tt, "\"", BUFFER_SIZES(start, tt, 512)); 342354359Sroberto 342454359Sroberto if (tmpctl.parsegettc.parse_count) 342554359Sroberto mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 3426182007Sroberto tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count)); 342754359Sroberto 342854359Sroberto } 342954359Sroberto 343054359Sroberto tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 343154359Sroberto 343254359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 343354359Sroberto { 343454359Sroberto ERR(ERR_INTERNAL) 343554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 343654359Sroberto } 343754359Sroberto else 343854359Sroberto { 343954359Sroberto tt = add_var(&out->kv_list, 80, RO|DEF); 3440182007Sroberto snprintf(tt, 80, "refclock_format=\""); 344154359Sroberto 344254359Sroberto strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count); 3443182007Sroberto strncat(tt,"\"", 80); 344454359Sroberto } 344554359Sroberto 344654359Sroberto /* 344754359Sroberto * gather state statistics 344854359Sroberto */ 344954359Sroberto 345054359Sroberto start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3451182007Sroberto strncpy(tt, "refclock_states=\"", LEN_STATES); 345254359Sroberto tt += strlen(tt); 345354359Sroberto 345454359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 345554359Sroberto { 345654359Sroberto u_long s_time; 345754359Sroberto u_long d = current_time - parse->generic->timestarted; 345854359Sroberto u_long percent; 345954359Sroberto 346054359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 346154359Sroberto 346254359Sroberto while (((u_long)(~0) / 10000) < percent) 346354359Sroberto { 346454359Sroberto percent /= 10; 346554359Sroberto d /= 10; 346654359Sroberto } 346754359Sroberto 346854359Sroberto if (d) 346954359Sroberto percent = (percent * 10000) / d; 347054359Sroberto else 347154359Sroberto percent = 10000; 347254359Sroberto 347354359Sroberto if (s_time) 347454359Sroberto { 347554359Sroberto char item[80]; 347654359Sroberto int count; 347754359Sroberto 3478182007Sroberto snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 347954359Sroberto sum ? "; " : "", 348054359Sroberto (parse->generic->currentstatus == i) ? "*" : "", 348154359Sroberto clockstatus((unsigned int)i), 348254359Sroberto l_mktime(s_time), 348354359Sroberto (int)(percent / 100), (int)(percent % 100)); 348454359Sroberto if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) 348554359Sroberto { 3486182007Sroberto strncpy(tt, item, BUFFER_SIZES(start, tt, LEN_STATES)); 348754359Sroberto tt += count; 348854359Sroberto } 348954359Sroberto sum += s_time; 349054359Sroberto } 349154359Sroberto } 349254359Sroberto 3493182007Sroberto snprintf(tt, BUFFER_SIZES(start, tt, LEN_STATES), "; running time: %s\"", l_mktime(sum)); 349454359Sroberto 349554359Sroberto tt = add_var(&out->kv_list, 32, RO); 3496182007Sroberto snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 349754359Sroberto 349854359Sroberto tt = add_var(&out->kv_list, 80, RO); 3499182007Sroberto snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 350054359Sroberto 350154359Sroberto tt = add_var(&out->kv_list, 128, RO); 3502182007Sroberto snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 350354359Sroberto 350454359Sroberto { 350554359Sroberto struct ctl_var *k; 350654359Sroberto 350754359Sroberto k = parse->kv; 350854359Sroberto while (k && !(k->flags & EOV)) 350954359Sroberto { 351054359Sroberto set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 351154359Sroberto k++; 351254359Sroberto } 351354359Sroberto } 351454359Sroberto 351554359Sroberto out->lencode = strlen(outstatus); 351654359Sroberto out->p_lastcode = outstatus; 351754359Sroberto } 351854359Sroberto} 351954359Sroberto 352054359Sroberto/**=========================================================================== 352154359Sroberto ** processing routines 352254359Sroberto **/ 352354359Sroberto 352454359Sroberto/*-------------------------------------------------- 352554359Sroberto * event handling - note that nominal events will also be posted 3526182007Sroberto * keep track of state dwelling times 352754359Sroberto */ 352854359Srobertostatic void 352954359Srobertoparse_event( 353054359Sroberto struct parseunit *parse, 353154359Sroberto int event 353254359Sroberto ) 353354359Sroberto{ 353454359Sroberto if (parse->generic->currentstatus != (u_char) event) 353554359Sroberto { 353654359Sroberto parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 353754359Sroberto parse->lastchange = current_time; 353854359Sroberto 353954359Sroberto if (parse->parse_type->cl_event) 354054359Sroberto parse->parse_type->cl_event(parse, event); 354154359Sroberto 3542182007Sroberto if (event == CEVNT_NOMINAL) 354354359Sroberto { 354454359Sroberto NLOG(NLOG_CLOCKSTATUS) 354554359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 354654359Sroberto CLK_UNIT(parse->peer)); 354754359Sroberto } 354854359Sroberto 3549182007Sroberto refclock_report(parse->peer, event); 355054359Sroberto } 355154359Sroberto} 355254359Sroberto 355354359Sroberto/*-------------------------------------------------- 355454359Sroberto * process a PARSE time sample 355554359Sroberto */ 355654359Srobertostatic void 355754359Srobertoparse_process( 355854359Sroberto struct parseunit *parse, 355954359Sroberto parsetime_t *parsetime 356054359Sroberto ) 356154359Sroberto{ 356254359Sroberto l_fp off, rectime, reftime; 356354359Sroberto double fudge; 356454359Sroberto 356554359Sroberto /* 356654359Sroberto * check for changes in conversion status 356754359Sroberto * (only one for each new status !) 356854359Sroberto */ 356954359Sroberto if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 357054359Sroberto ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3571182007Sroberto (parse->timedata.parse_status != parsetime->parse_status)) 357254359Sroberto { 357354359Sroberto char buffer[400]; 357454359Sroberto 357554359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 357654359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3577182007Sroberto CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 357854359Sroberto 357954359Sroberto if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 358054359Sroberto { 358154359Sroberto /* 358254359Sroberto * tell more about the story - list time code 358354359Sroberto * there is a slight change for a race condition and 358454359Sroberto * the time code might be overwritten by the next packet 358554359Sroberto */ 358654359Sroberto parsectl_t tmpctl; 358754359Sroberto 358854359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 358954359Sroberto { 359054359Sroberto ERR(ERR_INTERNAL) 359154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 359254359Sroberto } 359354359Sroberto else 359454359Sroberto { 359554359Sroberto ERR(ERR_BADDATA) 3596182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 359754359Sroberto CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); 359854359Sroberto } 359954359Sroberto } 360054359Sroberto } 360154359Sroberto 360254359Sroberto /* 360354359Sroberto * examine status and post appropriate events 360454359Sroberto */ 360554359Sroberto if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 360654359Sroberto { 360754359Sroberto /* 360854359Sroberto * got bad data - tell the rest of the system 360954359Sroberto */ 361054359Sroberto switch (parsetime->parse_status & CVT_MASK) 361154359Sroberto { 361254359Sroberto case CVT_NONE: 361354359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 361454359Sroberto parse->parse_type->cl_message) 361554359Sroberto parse->parse_type->cl_message(parse, parsetime); 3616182007Sroberto /* 3617182007Sroberto * save PPS information that comes piggyback 3618182007Sroberto */ 3619182007Sroberto if (PARSE_PPS(parsetime->parse_state)) 3620182007Sroberto { 3621182007Sroberto parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3622182007Sroberto parse->timedata.parse_ptime = parsetime->parse_ptime; 3623182007Sroberto } 362454359Sroberto break; /* well, still waiting - timeout is handled at higher levels */ 362554359Sroberto 362654359Sroberto case CVT_FAIL: 362754359Sroberto if (parsetime->parse_status & CVT_BADFMT) 362854359Sroberto { 362954359Sroberto parse_event(parse, CEVNT_BADREPLY); 363054359Sroberto } 363154359Sroberto else 363254359Sroberto if (parsetime->parse_status & CVT_BADDATE) 363354359Sroberto { 363454359Sroberto parse_event(parse, CEVNT_BADDATE); 363554359Sroberto } 363654359Sroberto else 363754359Sroberto if (parsetime->parse_status & CVT_BADTIME) 363854359Sroberto { 363954359Sroberto parse_event(parse, CEVNT_BADTIME); 364054359Sroberto } 364154359Sroberto else 364254359Sroberto { 364354359Sroberto parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 364454359Sroberto } 364554359Sroberto } 364654359Sroberto return; /* skip the rest - useless */ 364754359Sroberto } 364854359Sroberto 364954359Sroberto /* 365054359Sroberto * check for format changes 365154359Sroberto * (in case somebody has swapped clocks 8-) 365254359Sroberto */ 365354359Sroberto if (parse->lastformat != parsetime->parse_format) 365454359Sroberto { 365554359Sroberto parsectl_t tmpctl; 365654359Sroberto 365754359Sroberto tmpctl.parseformat.parse_format = parsetime->parse_format; 365854359Sroberto 365954359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 366054359Sroberto { 366154359Sroberto ERR(ERR_INTERNAL) 366254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 366354359Sroberto } 366454359Sroberto else 366554359Sroberto { 366654359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 366754359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 366854359Sroberto CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 366954359Sroberto } 367054359Sroberto parse->lastformat = parsetime->parse_format; 367154359Sroberto } 367254359Sroberto 367354359Sroberto /* 367454359Sroberto * now, any changes ? 367554359Sroberto */ 3676182007Sroberto if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3677182007Sroberto ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 367854359Sroberto { 367954359Sroberto char tmp1[200]; 368054359Sroberto char tmp2[200]; 368154359Sroberto /* 3682182007Sroberto * something happend - except for PPS events 368354359Sroberto */ 368454359Sroberto 3685182007Sroberto (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3686182007Sroberto (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 368754359Sroberto 368854359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 368954359Sroberto msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 369054359Sroberto CLK_UNIT(parse->peer), tmp2, tmp1); 369154359Sroberto } 369254359Sroberto 369354359Sroberto /* 3694182007Sroberto * carry on PPS information if still usable 3695182007Sroberto */ 3696182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3697182007Sroberto { 3698182007Sroberto parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3699182007Sroberto parsetime->parse_ptime = parse->timedata.parse_ptime; 3700182007Sroberto } 3701182007Sroberto 3702182007Sroberto /* 370354359Sroberto * remember for future 370454359Sroberto */ 3705182007Sroberto parse->timedata = *parsetime; 370654359Sroberto 370754359Sroberto /* 370854359Sroberto * check to see, whether the clock did a complete powerup or lost PZF signal 370954359Sroberto * and post correct events for current condition 371054359Sroberto */ 371154359Sroberto if (PARSE_POWERUP(parsetime->parse_state)) 371254359Sroberto { 371354359Sroberto /* 371454359Sroberto * this is bad, as we have completely lost synchronisation 371554359Sroberto * well this is a problem with the receiver here 371654359Sroberto * for PARSE Meinberg DCF77 receivers the lost synchronisation 371754359Sroberto * is true as it is the powerup state and the time is taken 371854359Sroberto * from a crude real time clock chip 371954359Sroberto * for the PZF series this is only partly true, as 372054359Sroberto * PARSE_POWERUP only means that the pseudo random 372154359Sroberto * phase shift sequence cannot be found. this is only 372254359Sroberto * bad, if we have never seen the clock in the SYNC 372354359Sroberto * state, where the PHASE and EPOCH are correct. 372454359Sroberto * for reporting events the above business does not 372554359Sroberto * really matter, but we can use the time code 372654359Sroberto * even in the POWERUP state after having seen 372754359Sroberto * the clock in the synchronized state (PZF class 372854359Sroberto * receivers) unless we have had a telegram disruption 372954359Sroberto * after having seen the clock in the SYNC state. we 373054359Sroberto * thus require having seen the clock in SYNC state 373154359Sroberto * *after* having missed telegrams (noresponse) from 373254359Sroberto * the clock. one problem remains: we might use erroneously 373354359Sroberto * POWERUP data if the disruption is shorter than 1 polling 373454359Sroberto * interval. fortunately powerdowns last usually longer than 64 373554359Sroberto * seconds and the receiver is at least 2 minutes in the 373654359Sroberto * POWERUP or NOSYNC state before switching to SYNC 373754359Sroberto */ 373854359Sroberto parse_event(parse, CEVNT_FAULT); 373954359Sroberto NLOG(NLOG_CLOCKSTATUS) 374054359Sroberto ERR(ERR_BADSTATUS) 374154359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED", 374254359Sroberto CLK_UNIT(parse->peer)); 374354359Sroberto } 374454359Sroberto else 374554359Sroberto { 374654359Sroberto /* 374754359Sroberto * we have two states left 374854359Sroberto * 374954359Sroberto * SYNC: 375054359Sroberto * this state means that the EPOCH (timecode) and PHASE 375154359Sroberto * information has be read correctly (at least two 375254359Sroberto * successive PARSE timecodes were received correctly) 375354359Sroberto * this is the best possible state - full trust 375454359Sroberto * 375554359Sroberto * NOSYNC: 375654359Sroberto * The clock should be on phase with respect to the second 375754359Sroberto * signal, but the timecode has not been received correctly within 375854359Sroberto * at least the last two minutes. this is a sort of half baked state 375954359Sroberto * for PARSE Meinberg DCF77 clocks this is bad news (clock running 376054359Sroberto * without timecode confirmation) 376154359Sroberto * PZF 535 has also no time confirmation, but the phase should be 376254359Sroberto * very precise as the PZF signal can be decoded 376354359Sroberto */ 376454359Sroberto 376554359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 376654359Sroberto { 376754359Sroberto /* 376854359Sroberto * currently completely synchronized - best possible state 376954359Sroberto */ 377054359Sroberto parse->lastsync = current_time; 377154359Sroberto clear_err(parse, ERR_BADSTATUS); 377254359Sroberto } 377354359Sroberto else 377454359Sroberto { 377554359Sroberto /* 377654359Sroberto * we have had some problems receiving the time code 377754359Sroberto */ 377854359Sroberto parse_event(parse, CEVNT_PROP); 377954359Sroberto NLOG(NLOG_CLOCKSTATUS) 378054359Sroberto ERR(ERR_BADSTATUS) 378154359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 378254359Sroberto CLK_UNIT(parse->peer)); 378354359Sroberto } 378454359Sroberto } 378554359Sroberto 378654359Sroberto fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 378754359Sroberto 378854359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 378954359Sroberto { 379054359Sroberto rectime = parsetime->parse_stime.fp; 379154359Sroberto off = reftime = parsetime->parse_time.fp; 379254359Sroberto 379354359Sroberto L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 379454359Sroberto 379554359Sroberto#ifdef DEBUG 379654359Sroberto if (debug > 3) 379754359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 379854359Sroberto CLK_UNIT(parse->peer), 379954359Sroberto prettydate(&reftime), 380054359Sroberto prettydate(&rectime), 380154359Sroberto lfptoa(&off,6)); 380254359Sroberto#endif 380354359Sroberto } 380454359Sroberto 380554359Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 380654359Sroberto { 380754359Sroberto l_fp offset; 3808182007Sroberto double ppsphaseadjust = parse->ppsphaseadjust; 380954359Sroberto 3810182007Sroberto#ifdef HAVE_PPSAPI 381154359Sroberto /* 3812182007Sroberto * set fudge = 0.0 if already included in PPS time stamps 3813182007Sroberto */ 3814182007Sroberto if (parse->ppsparams.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 3815182007Sroberto { 3816182007Sroberto ppsphaseadjust = 0.0; 3817182007Sroberto } 3818182007Sroberto#endif 3819182007Sroberto 3820182007Sroberto /* 382154359Sroberto * we have a PPS signal - much better than the RS232 stuff (we hope) 382254359Sroberto */ 382354359Sroberto offset = parsetime->parse_ptime.fp; 382454359Sroberto 382554359Sroberto#ifdef DEBUG 382654359Sroberto if (debug > 3) 382754359Sroberto printf("PARSE receiver #%d: PPStime %s\n", 382854359Sroberto CLK_UNIT(parse->peer), 382954359Sroberto prettydate(&offset)); 383054359Sroberto#endif 383154359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 383254359Sroberto { 383354359Sroberto if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) && 383454359Sroberto M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f)) 383554359Sroberto { 3836182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 383754359Sroberto 383854359Sroberto /* 383954359Sroberto * RS232 offsets within [-0.5..0.5[ - take PPS offsets 384054359Sroberto */ 384154359Sroberto 384254359Sroberto if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 384354359Sroberto { 384454359Sroberto reftime = off = offset; 384554359Sroberto if (reftime.l_uf & (unsigned)0x80000000) 384654359Sroberto reftime.l_ui++; 384754359Sroberto reftime.l_uf = 0; 384856746Sroberto 384954359Sroberto 385054359Sroberto /* 385154359Sroberto * implied on second offset 385254359Sroberto */ 385354359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 385454359Sroberto off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 385554359Sroberto } 385654359Sroberto else 385754359Sroberto { 385854359Sroberto /* 385954359Sroberto * time code describes pulse 386054359Sroberto */ 386154359Sroberto reftime = off = parsetime->parse_time.fp; 386254359Sroberto 386354359Sroberto L_SUB(&off, &offset); /* true offset */ 386454359Sroberto } 386554359Sroberto } 386654359Sroberto /* 386754359Sroberto * take RS232 offset when PPS when out of bounds 386854359Sroberto */ 386954359Sroberto } 387054359Sroberto else 387154359Sroberto { 3872182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 387354359Sroberto /* 387454359Sroberto * Well, no time code to guide us - assume on second pulse 387554359Sroberto * and pray, that we are within [-0.5..0.5[ 387654359Sroberto */ 387754359Sroberto off = offset; 387854359Sroberto reftime = offset; 387954359Sroberto if (reftime.l_uf & (unsigned)0x80000000) 388054359Sroberto reftime.l_ui++; 388154359Sroberto reftime.l_uf = 0; 388254359Sroberto /* 388354359Sroberto * implied on second offset 388454359Sroberto */ 388554359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 388654359Sroberto off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */ 388754359Sroberto } 388854359Sroberto } 388954359Sroberto else 389054359Sroberto { 389154359Sroberto if (!PARSE_TIMECODE(parsetime->parse_state)) 389254359Sroberto { 389354359Sroberto /* 389454359Sroberto * Well, no PPS, no TIMECODE, no more work ... 389554359Sroberto */ 389654359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 389754359Sroberto parse->parse_type->cl_message) 389854359Sroberto parse->parse_type->cl_message(parse, parsetime); 389954359Sroberto return; 390054359Sroberto } 390154359Sroberto } 390254359Sroberto 390354359Sroberto#ifdef DEBUG 390454359Sroberto if (debug > 3) 390554359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 390654359Sroberto CLK_UNIT(parse->peer), 390754359Sroberto prettydate(&reftime), 390854359Sroberto prettydate(&rectime), 390954359Sroberto lfptoa(&off,6)); 391054359Sroberto#endif 391154359Sroberto 391254359Sroberto 391354359Sroberto rectime = reftime; 391454359Sroberto L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 391554359Sroberto 391654359Sroberto#ifdef DEBUG 391754359Sroberto if (debug > 3) 391854359Sroberto printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 391954359Sroberto CLK_UNIT(parse->peer), 392054359Sroberto prettydate(&reftime), 392154359Sroberto prettydate(&rectime)); 392254359Sroberto#endif 392354359Sroberto 392454359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 392554359Sroberto parse->parse_type->cl_message) 392654359Sroberto parse->parse_type->cl_message(parse, parsetime); 392754359Sroberto 392854359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 392954359Sroberto { 393054359Sroberto /* 393154359Sroberto * log OK status 393254359Sroberto */ 393354359Sroberto parse_event(parse, CEVNT_NOMINAL); 393454359Sroberto } 393554359Sroberto 393654359Sroberto clear_err(parse, ERR_BADIO); 393754359Sroberto clear_err(parse, ERR_BADDATA); 393854359Sroberto clear_err(parse, ERR_NODATA); 393954359Sroberto clear_err(parse, ERR_INTERNAL); 394054359Sroberto 394154359Sroberto /* 394254359Sroberto * and now stick it into the clock machine 394354359Sroberto * samples are only valid iff lastsync is not too old and 394454359Sroberto * we have seen the clock in sync at least once 394554359Sroberto * after the last time we didn't see an expected data telegram 3946182007Sroberto * at startup being not in sync is also bad just like 3947182007Sroberto * POWERUP state 394854359Sroberto * see the clock states section above for more reasoning 394954359Sroberto */ 3950182007Sroberto if (((current_time - parse->lastsync) > parse->maxunsync) || 3951182007Sroberto (parse->lastsync < parse->lastmissed) || 3952182007Sroberto ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 3953182007Sroberto PARSE_POWERUP(parsetime->parse_state)) 395454359Sroberto { 395554359Sroberto parse->generic->leap = LEAP_NOTINSYNC; 3956182007Sroberto parse->lastsync = 0; /* wait for full sync again */ 395754359Sroberto } 395854359Sroberto else 395954359Sroberto { 396054359Sroberto if (PARSE_LEAPADD(parsetime->parse_state)) 396154359Sroberto { 396254359Sroberto /* 396354359Sroberto * we pick this state also for time code that pass leap warnings 396454359Sroberto * without direction information (as earth is currently slowing 396554359Sroberto * down). 396654359Sroberto */ 396754359Sroberto parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 396854359Sroberto } 396954359Sroberto else 397054359Sroberto if (PARSE_LEAPDEL(parsetime->parse_state)) 397154359Sroberto { 397254359Sroberto parse->generic->leap = LEAP_DELSECOND; 397354359Sroberto } 397454359Sroberto else 397554359Sroberto { 397654359Sroberto parse->generic->leap = LEAP_NOWARNING; 397754359Sroberto } 397854359Sroberto } 3979182007Sroberto 3980182007Sroberto if (parse->generic->leap != LEAP_NOTINSYNC) 3981182007Sroberto { 3982182007Sroberto /* 3983182007Sroberto * only good/trusted samples are interesting 3984182007Sroberto */ 3985182007Sroberto#ifdef DEBUG 3986182007Sroberto if (debug > 2) 3987182007Sroberto { 3988182007Sroberto printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 3989182007Sroberto CLK_UNIT(parse->peer), 3990182007Sroberto prettydate(&reftime), 3991182007Sroberto prettydate(&rectime), 3992182007Sroberto fudge); 3993182007Sroberto } 3994182007Sroberto#endif 3995182007Sroberto parse->generic->lastref = reftime; 3996182007Sroberto 3997182007Sroberto refclock_process_offset(parse->generic, reftime, rectime, fudge); 3998182007Sroberto 3999182007Sroberto /* 4000182007Sroberto * pass PPS information on to PPS clock 4001182007Sroberto */ 4002182007Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4003182007Sroberto { 4004182007Sroberto (void) pps_sample(&parse->timedata.parse_ptime.fp); 4005182007Sroberto parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4006182007Sroberto } 4007182007Sroberto } else { 4008182007Sroberto parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4009182007Sroberto } 4010182007Sroberto 401154359Sroberto /* 4012182007Sroberto * ready, unless the machine wants a sample or 4013182007Sroberto * we are in fast startup mode (peer->dist > MAXDISTANCE) 401454359Sroberto */ 4015182007Sroberto if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 401654359Sroberto return; 401754359Sroberto 401854359Sroberto parse->pollneeddata = 0; 401954359Sroberto 4020182007Sroberto parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4021182007Sroberto 402254359Sroberto refclock_receive(parse->peer); 402354359Sroberto} 402456746Sroberto 402554359Sroberto/**=========================================================================== 402654359Sroberto ** special code for special clocks 402754359Sroberto **/ 402854359Sroberto 402954359Srobertostatic void 403054359Srobertomk_utcinfo( 403154359Sroberto char *t, 403254359Sroberto int wnt, 403354359Sroberto int wnlsf, 403454359Sroberto int dn, 403554359Sroberto int dtls, 4036182007Sroberto int dtlsf, 4037182007Sroberto int size 403854359Sroberto ) 403954359Sroberto{ 404054359Sroberto l_fp leapdate; 4041182007Sroberto char *start = t; 404254359Sroberto 4043182007Sroberto snprintf(t, size, "current correction %d sec", dtls); 404454359Sroberto t += strlen(t); 404554359Sroberto 404654359Sroberto if (wnlsf < 990) 404754359Sroberto wnlsf += 1024; 404854359Sroberto 404954359Sroberto if (wnt < 990) 405054359Sroberto wnt += 1024; 405154359Sroberto 405254359Sroberto gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); 405354359Sroberto 405454359Sroberto if ((dtlsf != dtls) && 405554359Sroberto ((wnlsf - wnt) < 52)) 405654359Sroberto { 4057182007Sroberto snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d", 405854359Sroberto dtlsf - dtls, gmprettydate(&leapdate), dtlsf); 405954359Sroberto } 406054359Sroberto else 406154359Sroberto { 4062182007Sroberto snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s", 406354359Sroberto gmprettydate(&leapdate)); 406454359Sroberto } 406554359Sroberto} 406654359Sroberto 406754359Sroberto#ifdef CLOCK_MEINBERG 406854359Sroberto/**=========================================================================== 406954359Sroberto ** Meinberg GPS166/GPS167 support 407054359Sroberto **/ 407154359Sroberto 407254359Sroberto/*------------------------------------------------------------ 407354359Sroberto * gps16x_message - process GPS16x messages 407454359Sroberto */ 407554359Srobertostatic void 407654359Srobertogps16x_message( 407754359Sroberto struct parseunit *parse, 407854359Sroberto parsetime_t *parsetime 407954359Sroberto ) 408054359Sroberto{ 4081182007Sroberto if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 408254359Sroberto { 408354359Sroberto GPS_MSG_HDR header; 408454359Sroberto unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 408554359Sroberto 408654359Sroberto#ifdef DEBUG 408754359Sroberto if (debug > 2) 408854359Sroberto { 408954359Sroberto char msgbuffer[600]; 409054359Sroberto 409154359Sroberto mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 409254359Sroberto printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 409354359Sroberto CLK_UNIT(parse->peer), 409454359Sroberto parsetime->parse_msglen, 409554359Sroberto msgbuffer); 409654359Sroberto } 409754359Sroberto#endif 409854359Sroberto get_mbg_header(&bufp, &header); 409954359Sroberto if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 410054359Sroberto (header.gps_len == 0 || 410154359Sroberto (header.gps_len < sizeof(parsetime->parse_msg) && 410254359Sroberto header.gps_data_csum == mbg_csum(bufp, header.gps_len)))) 410354359Sroberto { 410454359Sroberto /* 410554359Sroberto * clean message 410654359Sroberto */ 410754359Sroberto switch (header.gps_cmd) 410854359Sroberto { 410954359Sroberto case GPS_SW_REV: 411054359Sroberto { 411154359Sroberto char buffer[64]; 411254359Sroberto SW_REV gps_sw_rev; 411354359Sroberto 411454359Sroberto get_mbg_sw_rev(&bufp, &gps_sw_rev); 4115182007Sroberto snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 411654359Sroberto (gps_sw_rev.code >> 8) & 0xFF, 411754359Sroberto gps_sw_rev.code & 0xFF, 411854359Sroberto gps_sw_rev.name[0] ? " " : "", 411954359Sroberto gps_sw_rev.name); 4120182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 412154359Sroberto } 412254359Sroberto break; 412354359Sroberto 412454359Sroberto case GPS_STAT: 412554359Sroberto { 412654359Sroberto static struct state 412754359Sroberto { 412854359Sroberto unsigned short flag; /* status flag */ 412954359Sroberto unsigned const char *string; /* bit name */ 413054359Sroberto } states[] = 413154359Sroberto { 413254359Sroberto { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" }, 413354359Sroberto { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" }, 413454359Sroberto { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" }, 413554359Sroberto { TM_NO_POS, (const unsigned char *)"NO POSITION" }, 413654359Sroberto { 0, (const unsigned char *)"" } 413754359Sroberto }; 413854359Sroberto unsigned short status; 413954359Sroberto struct state *s = states; 414054359Sroberto char buffer[512]; 414154359Sroberto char *p, *b; 414254359Sroberto 414354359Sroberto status = get_lsb_short(&bufp); 4144182007Sroberto snprintf(buffer, sizeof(buffer), "meinberg_gps_status=\"[0x%04x] ", status); 414554359Sroberto 414654359Sroberto if (status) 414754359Sroberto { 414854359Sroberto p = b = buffer + strlen(buffer); 414954359Sroberto while (s->flag) 415054359Sroberto { 415154359Sroberto if (status & s->flag) 415254359Sroberto { 415354359Sroberto if (p != b) 415454359Sroberto { 415554359Sroberto *p++ = ','; 415654359Sroberto *p++ = ' '; 415754359Sroberto } 415854359Sroberto 4159182007Sroberto strncat(p, (const char *)s->string, sizeof(buffer)); 416054359Sroberto } 416154359Sroberto s++; 416254359Sroberto } 416354359Sroberto 416454359Sroberto *p++ = '"'; 416554359Sroberto *p = '\0'; 416654359Sroberto } 416754359Sroberto else 416854359Sroberto { 4169182007Sroberto strncat(buffer, "<OK>\"", sizeof(buffer)); 417054359Sroberto } 417154359Sroberto 4172182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 417354359Sroberto } 417454359Sroberto break; 417554359Sroberto 417654359Sroberto case GPS_POS_XYZ: 417754359Sroberto { 417854359Sroberto XYZ xyz; 417954359Sroberto char buffer[256]; 418054359Sroberto 418154359Sroberto get_mbg_xyz(&bufp, xyz); 4182182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 418354359Sroberto mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 418454359Sroberto mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 418554359Sroberto mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 418654359Sroberto 418754359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 418854359Sroberto } 418954359Sroberto break; 419054359Sroberto 419154359Sroberto case GPS_POS_LLA: 419254359Sroberto { 419354359Sroberto LLA lla; 419454359Sroberto char buffer[256]; 419554359Sroberto 419654359Sroberto get_mbg_lla(&bufp, lla); 419754359Sroberto 4198182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 419954359Sroberto mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 420054359Sroberto mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 420154359Sroberto mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 420254359Sroberto 420354359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 420454359Sroberto } 420554359Sroberto break; 420654359Sroberto 420754359Sroberto case GPS_TZDL: 420854359Sroberto break; 420954359Sroberto 421054359Sroberto case GPS_PORT_PARM: 421154359Sroberto break; 421254359Sroberto 421354359Sroberto case GPS_SYNTH: 421454359Sroberto break; 421554359Sroberto 421654359Sroberto case GPS_ANT_INFO: 421754359Sroberto { 421854359Sroberto ANT_INFO antinfo; 4219182007Sroberto char buffer[512]; 4220182007Sroberto char *p; 422154359Sroberto 422254359Sroberto get_mbg_antinfo(&bufp, &antinfo); 4223182007Sroberto snprintf(buffer, sizeof(buffer), "meinberg_antenna_status=\""); 422454359Sroberto p = buffer + strlen(buffer); 422554359Sroberto 422654359Sroberto switch (antinfo.status) 422754359Sroberto { 422854359Sroberto case ANT_INVALID: 4229182007Sroberto strncat(p, "<OK>", BUFFER_SIZE(buffer, p)); 423054359Sroberto p += strlen(p); 423154359Sroberto break; 423254359Sroberto 423354359Sroberto case ANT_DISCONN: 4234182007Sroberto strncat(p, "DISCONNECTED since ", BUFFER_SIZE(buffer, p)); 423554359Sroberto NLOG(NLOG_CLOCKSTATUS) 423654359Sroberto ERR(ERR_BADSTATUS) 423754359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 423854359Sroberto CLK_UNIT(parse->peer), p); 423954359Sroberto 424054359Sroberto p += strlen(p); 4241182007Sroberto mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 424254359Sroberto *p = '\0'; 424354359Sroberto break; 424454359Sroberto 424554359Sroberto case ANT_RECONN: 4246182007Sroberto strncat(p, "RECONNECTED on ", BUFFER_SIZE(buffer, p)); 424754359Sroberto p += strlen(p); 4248182007Sroberto mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p)); 4249182007Sroberto snprintf(p, BUFFER_SIZE(buffer, p), ", reconnect clockoffset %c%ld.%07ld s, disconnect time ", 425054359Sroberto (antinfo.delta_t < 0) ? '-' : '+', 425154359Sroberto ABS(antinfo.delta_t) / 10000, 425254359Sroberto ABS(antinfo.delta_t) % 10000); 425354359Sroberto p += strlen(p); 4254182007Sroberto mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 425554359Sroberto *p = '\0'; 425654359Sroberto break; 425754359Sroberto 425854359Sroberto default: 4259182007Sroberto snprintf(p, BUFFER_SIZE(buffer, p), "bad status 0x%04x", antinfo.status); 426054359Sroberto p += strlen(p); 426154359Sroberto break; 426254359Sroberto } 426354359Sroberto 4264182007Sroberto strncat(p, "\"", BUFFER_SIZE(buffer, p)); 426554359Sroberto 4266182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 426754359Sroberto } 426854359Sroberto break; 426954359Sroberto 427054359Sroberto case GPS_UCAP: 427154359Sroberto break; 427254359Sroberto 427354359Sroberto case GPS_CFGH: 427454359Sroberto { 427554359Sroberto CFGH cfgh; 4276182007Sroberto char buffer[512]; 4277182007Sroberto char *p; 427854359Sroberto 427954359Sroberto get_mbg_cfgh(&bufp, &cfgh); 428054359Sroberto if (cfgh.valid) 428154359Sroberto { 428254359Sroberto int i; 428354359Sroberto 428454359Sroberto p = buffer; 4285182007Sroberto strncpy(buffer, "gps_tot_51=\"", BUFFER_SIZE(buffer, p)); 428654359Sroberto p += strlen(p); 4287182007Sroberto mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4288182007Sroberto strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4289182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 429054359Sroberto 429154359Sroberto p = buffer; 4292182007Sroberto strncpy(buffer, "gps_tot_63=\"", BUFFER_SIZE(buffer, p)); 429354359Sroberto p += strlen(p); 4294182007Sroberto mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4295182007Sroberto strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4296182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 429754359Sroberto 429854359Sroberto p = buffer; 4299182007Sroberto strncpy(buffer, "gps_t0a=\"", BUFFER_SIZE(buffer, p)); 430054359Sroberto p += strlen(p); 4301182007Sroberto mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4302182007Sroberto strncpy(p, "\"", BUFFER_SIZE(buffer, p)); 4303182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 430454359Sroberto 4305182007Sroberto for (i = MIN_SVNO; i < MAX_SVNO; i++) 430654359Sroberto { 430754359Sroberto p = buffer; 4308182007Sroberto snprintf(p, BUFFER_SIZE(buffer, p), "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); 430954359Sroberto p += strlen(p); 431054359Sroberto switch (cfgh.cfg[i] & 0x7) 431154359Sroberto { 431254359Sroberto case 0: 4313182007Sroberto strncpy(p, "BLOCK I", BUFFER_SIZE(buffer, p)); 431454359Sroberto break; 431554359Sroberto case 1: 4316182007Sroberto strncpy(p, "BLOCK II", BUFFER_SIZE(buffer, p)); 431754359Sroberto break; 431854359Sroberto default: 4319182007Sroberto strncpy(p, "bad CFG", BUFFER_SIZE(buffer, p)); 432054359Sroberto break; 432154359Sroberto } 4322182007Sroberto strncat(p, "\"", BUFFER_SIZE(buffer, p)); 4323182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 432454359Sroberto 432554359Sroberto p = buffer; 4326182007Sroberto snprintf(p, BUFFER_SIZE(buffer, p), "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); 432754359Sroberto p += strlen(p); 432854359Sroberto switch ((cfgh.health[i] >> 5) & 0x7 ) 432954359Sroberto { 433054359Sroberto case 0: 4331182007Sroberto strncpy(p, "OK;", BUFFER_SIZE(buffer, p)); 433254359Sroberto break; 433354359Sroberto case 1: 4334182007Sroberto strncpy(p, "PARITY;", BUFFER_SIZE(buffer, p)); 433554359Sroberto break; 433654359Sroberto case 2: 4337182007Sroberto strncpy(p, "TLM/HOW;", BUFFER_SIZE(buffer, p)); 433854359Sroberto break; 433954359Sroberto case 3: 4340182007Sroberto strncpy(p, "Z-COUNT;", BUFFER_SIZE(buffer, p)); 434154359Sroberto break; 434254359Sroberto case 4: 4343182007Sroberto strncpy(p, "SUBFRAME 1,2,3;", BUFFER_SIZE(buffer, p)); 434454359Sroberto break; 434554359Sroberto case 5: 4346182007Sroberto strncpy(p, "SUBFRAME 4,5;", BUFFER_SIZE(buffer, p)); 434754359Sroberto break; 434854359Sroberto case 6: 4349182007Sroberto strncpy(p, "UPLOAD BAD;", BUFFER_SIZE(buffer, p)); 435054359Sroberto break; 435154359Sroberto case 7: 4352182007Sroberto strncpy(p, "DATA BAD;", BUFFER_SIZE(buffer, p)); 435354359Sroberto break; 435454359Sroberto } 435554359Sroberto 435654359Sroberto p += strlen(p); 435754359Sroberto 435854359Sroberto switch (cfgh.health[i] & 0x1F) 435954359Sroberto { 436054359Sroberto case 0: 4361182007Sroberto strncpy(p, "SIGNAL OK", BUFFER_SIZE(buffer, p)); 436254359Sroberto break; 436354359Sroberto case 0x1C: 4364182007Sroberto strncpy(p, "SV TEMP OUT", BUFFER_SIZE(buffer, p)); 436554359Sroberto break; 436654359Sroberto case 0x1D: 4367182007Sroberto strncpy(p, "SV WILL BE TEMP OUT", BUFFER_SIZE(buffer, p)); 436854359Sroberto break; 436954359Sroberto case 0x1E: 437054359Sroberto break; 437154359Sroberto case 0x1F: 4372182007Sroberto strncpy(p, "MULTIPLE ERRS", BUFFER_SIZE(buffer, p)); 437354359Sroberto break; 437454359Sroberto default: 4375182007Sroberto strncpy(p, "TRANSMISSION PROBLEMS", BUFFER_SIZE(buffer, p)); 437654359Sroberto break; 437754359Sroberto } 437854359Sroberto 4379182007Sroberto strncat(p, "\"", sizeof(buffer)); 4380182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO); 438154359Sroberto } 438254359Sroberto } 438354359Sroberto } 438454359Sroberto break; 438554359Sroberto 438654359Sroberto case GPS_ALM: 438754359Sroberto break; 438854359Sroberto 438954359Sroberto case GPS_EPH: 439054359Sroberto break; 439154359Sroberto 439254359Sroberto case GPS_UTC: 439354359Sroberto { 439454359Sroberto UTC utc; 439554359Sroberto char buffer[512]; 439654359Sroberto char *p; 439754359Sroberto 439854359Sroberto p = buffer; 439954359Sroberto 440054359Sroberto get_mbg_utc(&bufp, &utc); 440154359Sroberto 440254359Sroberto if (utc.valid) 440354359Sroberto { 4404182007Sroberto strncpy(p, "gps_utc_correction=\"", sizeof(buffer)); 440554359Sroberto p += strlen(p); 4406182007Sroberto mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 4407182007Sroberto strncat(p, "\"", BUFFER_SIZE(buffer, p)); 440854359Sroberto } 440954359Sroberto else 441054359Sroberto { 4411182007Sroberto strncpy(p, "gps_utc_correction=\"<NO UTC DATA>\"", BUFFER_SIZE(buffer, p)); 441254359Sroberto } 4413182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 441454359Sroberto } 441554359Sroberto break; 441654359Sroberto 441754359Sroberto case GPS_IONO: 441854359Sroberto break; 441954359Sroberto 442054359Sroberto case GPS_ASCII_MSG: 442154359Sroberto { 442254359Sroberto ASCII_MSG gps_ascii_msg; 442354359Sroberto char buffer[128]; 442454359Sroberto 442554359Sroberto get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 442654359Sroberto 442754359Sroberto if (gps_ascii_msg.valid) 442854359Sroberto { 442954359Sroberto char buffer1[128]; 443054359Sroberto mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 443154359Sroberto 4432182007Sroberto snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 443354359Sroberto } 443454359Sroberto else 4435182007Sroberto strncpy(buffer, "gps_message=<NONE>", sizeof(buffer)); 443654359Sroberto 4437182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 443854359Sroberto } 443954359Sroberto 444054359Sroberto break; 444154359Sroberto 444254359Sroberto default: 444354359Sroberto break; 444454359Sroberto } 444554359Sroberto } 444654359Sroberto else 444754359Sroberto { 444854359Sroberto msyslog(LOG_DEBUG, "PARSE receiver #%d: gps16x_message: message checksum error: hdr_csum = 0x%x (expected 0x%lx), data_len = %d, data_csum = 0x%x (expected 0x%lx)", 444954359Sroberto CLK_UNIT(parse->peer), 445054359Sroberto header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 445154359Sroberto header.gps_len, 445254359Sroberto header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); 445354359Sroberto } 445454359Sroberto } 445554359Sroberto 445654359Sroberto return; 445754359Sroberto} 445854359Sroberto 445954359Sroberto/*------------------------------------------------------------ 446054359Sroberto * gps16x_poll - query the reciver peridically 446154359Sroberto */ 446254359Srobertostatic void 446354359Srobertogps16x_poll( 446454359Sroberto struct peer *peer 446554359Sroberto ) 446654359Sroberto{ 446754359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 446854359Sroberto 446954359Sroberto static GPS_MSG_HDR sequence[] = 447054359Sroberto { 447154359Sroberto { GPS_SW_REV, 0, 0, 0 }, 447254359Sroberto { GPS_STAT, 0, 0, 0 }, 447354359Sroberto { GPS_UTC, 0, 0, 0 }, 447454359Sroberto { GPS_ASCII_MSG, 0, 0, 0 }, 447554359Sroberto { GPS_ANT_INFO, 0, 0, 0 }, 447654359Sroberto { GPS_CFGH, 0, 0, 0 }, 447754359Sroberto { GPS_POS_XYZ, 0, 0, 0 }, 447854359Sroberto { GPS_POS_LLA, 0, 0, 0 }, 447954359Sroberto { (unsigned short)~0, 0, 0, 0 } 448054359Sroberto }; 448154359Sroberto 448254359Sroberto int rtc; 448354359Sroberto unsigned char cmd_buffer[64]; 448454359Sroberto unsigned char *outp = cmd_buffer; 448554359Sroberto GPS_MSG_HDR *header; 448654359Sroberto 448754359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 448854359Sroberto { 448954359Sroberto parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 449054359Sroberto } 449154359Sroberto 449254359Sroberto if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) 449354359Sroberto parse->localstate = 0; 449454359Sroberto 449554359Sroberto header = sequence + parse->localstate++; 449654359Sroberto 449754359Sroberto *outp++ = SOH; /* start command */ 449854359Sroberto 449954359Sroberto put_mbg_header(&outp, header); 450054359Sroberto outp = cmd_buffer + 1; 450154359Sroberto 450254359Sroberto header->gps_hdr_csum = (short)mbg_csum(outp, 6); 450354359Sroberto put_mbg_header(&outp, header); 450454359Sroberto 450554359Sroberto#ifdef DEBUG 450654359Sroberto if (debug > 2) 450754359Sroberto { 450854359Sroberto char buffer[128]; 450954359Sroberto 451054359Sroberto mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 451154359Sroberto printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 451254359Sroberto CLK_UNIT(parse->peer), 451354359Sroberto parse->localstate - 1, 451454359Sroberto (int)(outp - cmd_buffer), 451554359Sroberto buffer); 451654359Sroberto } 451754359Sroberto#endif 451854359Sroberto 451954359Sroberto rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 452054359Sroberto 452154359Sroberto if (rtc < 0) 452254359Sroberto { 452354359Sroberto ERR(ERR_BADIO) 452454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 452554359Sroberto } 452654359Sroberto else 452754359Sroberto if (rtc != outp - cmd_buffer) 452854359Sroberto { 452954359Sroberto ERR(ERR_BADIO) 453054359Sroberto 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)); 453154359Sroberto } 453254359Sroberto 453354359Sroberto clear_err(parse, ERR_BADIO); 453454359Sroberto return; 453554359Sroberto} 453654359Sroberto 453754359Sroberto/*-------------------------------------------------- 453854359Sroberto * init routine - setup timer 453954359Sroberto */ 454054359Srobertostatic int 454154359Srobertogps16x_poll_init( 454254359Sroberto struct parseunit *parse 454354359Sroberto ) 454454359Sroberto{ 454554359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 454654359Sroberto { 454754359Sroberto parse->peer->action = gps16x_poll; 454854359Sroberto gps16x_poll(parse->peer); 454954359Sroberto } 455054359Sroberto 455154359Sroberto return 0; 455254359Sroberto} 455354359Sroberto 455454359Sroberto#else 455554359Srobertostatic void 455654359Srobertogps16x_message( 455754359Sroberto struct parseunit *parse, 455854359Sroberto parsetime_t *parsetime 455954359Sroberto ) 456054359Sroberto{} 456154359Srobertostatic int 456254359Srobertogps16x_poll_init( 456354359Sroberto struct parseunit *parse 456454359Sroberto ) 456554359Sroberto{ 456654359Sroberto return 1; 456754359Sroberto} 456854359Sroberto#endif /* CLOCK_MEINBERG */ 456954359Sroberto 457054359Sroberto/**=========================================================================== 457154359Sroberto ** clock polling support 457254359Sroberto **/ 457354359Sroberto 457454359Sroberto/*-------------------------------------------------- 457554359Sroberto * direct poll routine 457654359Sroberto */ 457754359Srobertostatic void 457854359Srobertopoll_dpoll( 457954359Sroberto struct parseunit *parse 458054359Sroberto ) 458154359Sroberto{ 458254359Sroberto int rtc; 458354359Sroberto const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 458454359Sroberto int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 458554359Sroberto 458654359Sroberto rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); 458754359Sroberto if (rtc < 0) 458854359Sroberto { 458954359Sroberto ERR(ERR_BADIO) 459054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 459154359Sroberto } 459254359Sroberto else 459354359Sroberto if (rtc != ct) 459454359Sroberto { 459554359Sroberto ERR(ERR_BADIO) 459654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 459754359Sroberto } 459854359Sroberto clear_err(parse, ERR_BADIO); 459954359Sroberto} 460054359Sroberto 460154359Sroberto/*-------------------------------------------------- 460254359Sroberto * periodic poll routine 460354359Sroberto */ 460454359Srobertostatic void 460554359Srobertopoll_poll( 460654359Sroberto struct peer *peer 460754359Sroberto ) 460854359Sroberto{ 460954359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 461054359Sroberto 461154359Sroberto if (parse->parse_type->cl_poll) 461254359Sroberto parse->parse_type->cl_poll(parse); 461354359Sroberto 461454359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 461554359Sroberto { 461654359Sroberto parse->peer->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 461754359Sroberto } 461854359Sroberto} 461954359Sroberto 462054359Sroberto/*-------------------------------------------------- 462154359Sroberto * init routine - setup timer 462254359Sroberto */ 462354359Srobertostatic int 462454359Srobertopoll_init( 462554359Sroberto struct parseunit *parse 462654359Sroberto ) 462754359Sroberto{ 462854359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 462954359Sroberto { 463054359Sroberto parse->peer->action = poll_poll; 463154359Sroberto poll_poll(parse->peer); 463254359Sroberto } 463354359Sroberto 463454359Sroberto return 0; 463554359Sroberto} 463656746Sroberto 463754359Sroberto/**=========================================================================== 463854359Sroberto ** Trimble support 463954359Sroberto **/ 464054359Sroberto 464154359Sroberto/*------------------------------------------------------------- 464254359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init. 464354359Sroberto */ 464454359Srobertostatic int 464554359Srobertotrimbletaip_init( 464654359Sroberto struct parseunit *parse 464754359Sroberto ) 464854359Sroberto{ 464954359Sroberto#ifdef HAVE_TERMIOS 465054359Sroberto struct termios tio; 465154359Sroberto#endif 465254359Sroberto#ifdef HAVE_SYSV_TTYS 465354359Sroberto struct termio tio; 465454359Sroberto#endif 465554359Sroberto /* 465654359Sroberto * configure terminal line for trimble receiver 465754359Sroberto */ 465854359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 465954359Sroberto { 466054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 466154359Sroberto return 0; 466254359Sroberto } 466354359Sroberto else 466454359Sroberto { 466554359Sroberto tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 466654359Sroberto 466754359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 466854359Sroberto { 466954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 467054359Sroberto return 0; 467154359Sroberto } 467254359Sroberto } 467354359Sroberto return poll_init(parse); 467454359Sroberto} 467554359Sroberto 467654359Sroberto/*-------------------------------------------------- 467754359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble 467854359Sroberto */ 467954359Srobertostatic const char *taipinit[] = { 468054359Sroberto ">FPV00000000<", 468154359Sroberto ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 468254359Sroberto ">FTM00020001<", 468354359Sroberto (char *)0 468454359Sroberto}; 468554359Sroberto 468654359Srobertostatic void 468754359Srobertotrimbletaip_event( 468854359Sroberto struct parseunit *parse, 468954359Sroberto int event 469054359Sroberto ) 469154359Sroberto{ 469254359Sroberto switch (event) 469354359Sroberto { 469454359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 469554359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 469654359Sroberto { 469754359Sroberto const char **iv; 469854359Sroberto 469954359Sroberto iv = taipinit; 470054359Sroberto while (*iv) 470154359Sroberto { 470254359Sroberto int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); 470354359Sroberto if (rtc < 0) 470454359Sroberto { 470554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 470654359Sroberto return; 470754359Sroberto } 470854359Sroberto else 470954359Sroberto { 471054359Sroberto if (rtc != strlen(*iv)) 471154359Sroberto { 471254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 471354359Sroberto CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 471454359Sroberto return; 471554359Sroberto } 471654359Sroberto } 471754359Sroberto iv++; 471854359Sroberto } 471954359Sroberto 472054359Sroberto NLOG(NLOG_CLOCKINFO) 472154359Sroberto ERR(ERR_BADIO) 472254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 472354359Sroberto CLK_UNIT(parse->peer)); 472454359Sroberto } 472554359Sroberto break; 472654359Sroberto 472754359Sroberto default: /* ignore */ 472854359Sroberto break; 472954359Sroberto } 473054359Sroberto} 473154359Sroberto 473254359Sroberto/* 473354359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module. 473454359Sroberto * It should support other Trimble receivers which use the Trimble Standard 473554359Sroberto * Interface Protocol (see below). 473654359Sroberto * 473754359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second 473854359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is 473954359Sroberto * coincident with the change of the GPS second. This is the same as 474054359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks 474154359Sroberto * specifically use a feature in the data message as a timing reference, but 474254359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter 474354359Sroberto * on the timing of the messages, so this driver only supports the use 474454359Sroberto * of the PPS pulse for accurate timing. Where it is determined that 474554359Sroberto * the offset is way off, when first starting up ntpd for example, 474654359Sroberto * the timing of the data stream is used until the offset becomes low enough 474756746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used. 474854359Sroberto * 474954359Sroberto * It can use either option for receiving PPS information - the 'ppsclock' 475054359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier 475154359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only 475254359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in 475354359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter 475454359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another 475554359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input, 475654359Sroberto * by whichever method, is handled in ntp_loopfilter.c 475754359Sroberto * 475854359Sroberto * The receiver uses a serial message protocol called Trimble Standard 475954359Sroberto * Interface Protocol (it can support others but this driver only supports 476054359Sroberto * TSIP). Messages in this protocol have the following form: 476154359Sroberto * 476254359Sroberto * <DLE><id> ... <data> ... <DLE><ETX> 476354359Sroberto * 476454359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 476554359Sroberto * on transmission and compressed back to one on reception. Otherwise 476654359Sroberto * the values of data bytes can be anything. The serial interface is RS-422 476754359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 476854359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single, 476954359Sroberto * and double datatypes. Integers are two bytes, sent most significant first. 477054359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent 477154359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point 477254359Sroberto * numbers (8 byte) sent sign & exponent first. 477354359Sroberto * The receiver supports a large set of messages, only a small subset of 477454359Sroberto * which are used here. From driver to receiver the following are used: 477554359Sroberto * 477654359Sroberto * ID Description 477754359Sroberto * 477854359Sroberto * 21 Request current time 477954359Sroberto * 22 Mode Select 478054359Sroberto * 2C Set/Request operating parameters 478154359Sroberto * 2F Request UTC info 478254359Sroberto * 35 Set/Request I/O options 478354359Sroberto 478454359Sroberto * From receiver to driver the following are recognised: 478554359Sroberto * 478654359Sroberto * ID Description 478754359Sroberto * 478854359Sroberto * 41 GPS Time 478954359Sroberto * 44 Satellite selection, PDOP, mode 479054359Sroberto * 46 Receiver health 479154359Sroberto * 4B Machine code/status 479254359Sroberto * 4C Report operating parameters (debug only) 479354359Sroberto * 4F UTC correction data (used to get leap second warnings) 479454359Sroberto * 55 I/O options (debug only) 479554359Sroberto * 479654359Sroberto * All others are accepted but ignored. 479754359Sroberto * 479854359Sroberto */ 479954359Sroberto 480054359Sroberto#define PI 3.1415926535898 /* lots of sig figs */ 480154359Sroberto#define D2R PI/180.0 480254359Sroberto 480354359Sroberto/*------------------------------------------------------------------- 480454359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 480554359Sroberto * interface to the receiver. 480654359Sroberto * 480754359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and 480854359Sroberto * float implementation dependend - these must be converted to portable 480954359Sroberto * versions ! 481054359Sroberto * 481154359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems 481254359Sroberto * with IEEE754 floats as native floats 481354359Sroberto */ 481454359Sroberto 481554359Srobertotypedef struct trimble 481654359Sroberto{ 481754359Sroberto u_long last_msg; /* last message received */ 4818182007Sroberto u_long last_reset; /* last time a reset was issued */ 481954359Sroberto u_char qtracking; /* query tracking status */ 482054359Sroberto u_long ctrack; /* current tracking set */ 482154359Sroberto u_long ltrack; /* last tracking set */ 482254359Sroberto} trimble_t; 482354359Sroberto 482454359Srobertounion uval { 482554359Sroberto u_char bd[8]; 482654359Sroberto int iv; 482754359Sroberto float fv; 482854359Sroberto double dv; 482954359Sroberto}; 483054359Sroberto 483154359Srobertostruct txbuf 483254359Sroberto{ 483354359Sroberto short idx; /* index to first unused byte */ 483454359Sroberto u_char *txt; /* pointer to actual data buffer */ 483554359Sroberto}; 483654359Sroberto 483756746Srobertovoid sendcmd P((struct txbuf *buf, int c)); 483856746Srobertovoid sendbyte P((struct txbuf *buf, int b)); 483956746Srobertovoid sendetx P((struct txbuf *buf, struct parseunit *parse)); 484056746Srobertovoid sendint P((struct txbuf *buf, int a)); 484156746Srobertovoid sendflt P((struct txbuf *buf, double a)); 484256746Sroberto 484354359Srobertovoid 484454359Srobertosendcmd( 484554359Sroberto struct txbuf *buf, 484654359Sroberto int c 484754359Sroberto ) 484854359Sroberto{ 484954359Sroberto buf->txt[0] = DLE; 485054359Sroberto buf->txt[1] = (u_char)c; 485154359Sroberto buf->idx = 2; 485254359Sroberto} 485354359Sroberto 4854182007Srobertovoid sendcmd P((struct txbuf *buf, int c)); 4855182007Srobertovoid sendbyte P((struct txbuf *buf, int b)); 4856182007Srobertovoid sendetx P((struct txbuf *buf, struct parseunit *parse)); 4857182007Srobertovoid sendint P((struct txbuf *buf, int a)); 4858182007Srobertovoid sendflt P((struct txbuf *buf, double a)); 4859182007Sroberto 486054359Srobertovoid 486154359Srobertosendbyte( 486254359Sroberto struct txbuf *buf, 486354359Sroberto int b 486454359Sroberto ) 486554359Sroberto{ 486654359Sroberto if (b == DLE) 486754359Sroberto buf->txt[buf->idx++] = DLE; 486854359Sroberto buf->txt[buf->idx++] = (u_char)b; 486954359Sroberto} 487054359Sroberto 487154359Srobertovoid 487254359Srobertosendetx( 487354359Sroberto struct txbuf *buf, 487454359Sroberto struct parseunit *parse 487554359Sroberto ) 487654359Sroberto{ 487754359Sroberto buf->txt[buf->idx++] = DLE; 487854359Sroberto buf->txt[buf->idx++] = ETX; 487954359Sroberto 488054359Sroberto if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 488154359Sroberto { 488254359Sroberto ERR(ERR_BADIO) 488354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 488454359Sroberto } 488554359Sroberto else 488654359Sroberto { 488754359Sroberto#ifdef DEBUG 488854359Sroberto if (debug > 2) 488954359Sroberto { 489054359Sroberto char buffer[256]; 489154359Sroberto 489254359Sroberto mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 489354359Sroberto printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 489454359Sroberto CLK_UNIT(parse->peer), 489554359Sroberto buf->idx, buffer); 489654359Sroberto } 489754359Sroberto#endif 489854359Sroberto clear_err(parse, ERR_BADIO); 489954359Sroberto } 490054359Sroberto} 490154359Sroberto 490254359Srobertovoid 490354359Srobertosendint( 490454359Sroberto struct txbuf *buf, 490554359Sroberto int a 490654359Sroberto ) 490754359Sroberto{ 490854359Sroberto /* send 16bit int, msbyte first */ 490954359Sroberto sendbyte(buf, (u_char)((a>>8) & 0xff)); 491054359Sroberto sendbyte(buf, (u_char)(a & 0xff)); 491154359Sroberto} 491254359Sroberto 491354359Srobertovoid 491454359Srobertosendflt( 491554359Sroberto struct txbuf *buf, 491654359Sroberto double a 491754359Sroberto ) 491854359Sroberto{ 491954359Sroberto int i; 492054359Sroberto union uval uval; 492154359Sroberto 492254359Sroberto uval.fv = a; 492354359Sroberto#ifdef WORDS_BIGENDIAN 492454359Sroberto for (i=0; i<=3; i++) 492554359Sroberto#else 492654359Sroberto for (i=3; i>=0; i--) 492754359Sroberto#endif 492854359Sroberto sendbyte(buf, uval.bd[i]); 492954359Sroberto} 493054359Sroberto 493154359Sroberto#define TRIM_POS_OPT 0x13 /* output position with high precision */ 493254359Sroberto#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 493354359Sroberto 493454359Sroberto/*-------------------------------------------------- 493554359Sroberto * trimble TSIP setup routine 493654359Sroberto */ 493754359Srobertostatic int 493854359Srobertotrimbletsip_setup( 493954359Sroberto struct parseunit *parse, 494054359Sroberto const char *reason 494156746Sroberto ) 494254359Sroberto{ 494354359Sroberto u_char buffer[256]; 494454359Sroberto struct txbuf buf; 4945182007Sroberto trimble_t *t = parse->localdata; 494654359Sroberto 4947182007Sroberto if (t && t->last_reset && 4948182007Sroberto ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 4949182007Sroberto return 1; /* not yet */ 4950182007Sroberto } 4951182007Sroberto 4952182007Sroberto if (t) 4953182007Sroberto t->last_reset = current_time; 4954182007Sroberto 495554359Sroberto buf.txt = buffer; 495654359Sroberto 495754359Sroberto sendcmd(&buf, CMD_CVERSION); /* request software versions */ 495856746Sroberto sendetx(&buf, parse); 495956746Sroberto 496054359Sroberto sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 496156746Sroberto sendbyte(&buf, 4); /* static */ 496256746Sroberto sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 496356746Sroberto sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 496456746Sroberto sendflt(&buf, 12.0); /* PDOP mask = 12 */ 496556746Sroberto sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 496656746Sroberto sendetx(&buf, parse); 496756746Sroberto 496854359Sroberto sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 4969182007Sroberto sendbyte(&buf, 1); /* time transfer mode */ 497056746Sroberto sendetx(&buf, parse); 497156746Sroberto 497254359Sroberto sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 497356746Sroberto sendetx(&buf, parse); 497456746Sroberto 497554359Sroberto sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 497656746Sroberto sendbyte(&buf, 0x2); /* binary mode */ 497756746Sroberto sendetx(&buf, parse); 497856746Sroberto 497954359Sroberto sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 498054359Sroberto sendbyte(&buf, TRIM_POS_OPT); /* position output */ 498154359Sroberto sendbyte(&buf, 0x00); /* no velocity output */ 498254359Sroberto sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 498354359Sroberto sendbyte(&buf, 0x00); /* no raw measurements */ 498456746Sroberto sendetx(&buf, parse); 498556746Sroberto 498654359Sroberto sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 498754359Sroberto sendetx(&buf, parse); 498854359Sroberto 498954359Sroberto NLOG(NLOG_CLOCKINFO) 499054359Sroberto ERR(ERR_BADIO) 499154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 499254359Sroberto 499354359Sroberto return 0; 499454359Sroberto} 499554359Sroberto 499654359Sroberto/*-------------------------------------------------- 499754359Sroberto * TRIMBLE TSIP check routine 499854359Sroberto */ 499954359Srobertostatic void 500054359Srobertotrimble_check( 500154359Sroberto struct peer *peer 500254359Sroberto ) 500354359Sroberto{ 500454359Sroberto struct parseunit *parse = (struct parseunit *)peer->procptr->unitptr; 500554359Sroberto trimble_t *t = parse->localdata; 500654359Sroberto u_char buffer[256]; 500754359Sroberto struct txbuf buf; 500854359Sroberto buf.txt = buffer; 500954359Sroberto 501054359Sroberto if (t) 501154359Sroberto { 501254359Sroberto if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 501354359Sroberto (void)trimbletsip_setup(parse, "message timeout"); 501454359Sroberto } 5015182007Sroberto 501654359Sroberto poll_poll(parse->peer); /* emit query string and re-arm timer */ 501754359Sroberto 5018182007Sroberto if (t && t->qtracking) 501954359Sroberto { 502054359Sroberto u_long oldsats = t->ltrack & ~t->ctrack; 502154359Sroberto 502254359Sroberto t->qtracking = 0; 502354359Sroberto t->ltrack = t->ctrack; 502454359Sroberto 502554359Sroberto if (oldsats) 502654359Sroberto { 502754359Sroberto int i; 502854359Sroberto 5029182007Sroberto for (i = 0; oldsats; i++) { 503054359Sroberto if (oldsats & (1 << i)) 503154359Sroberto { 503254359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 503354359Sroberto sendbyte(&buf, i+1); /* old sat */ 503454359Sroberto sendetx(&buf, parse); 503554359Sroberto } 5036182007Sroberto oldsats &= ~(1 << i); 5037182007Sroberto } 503854359Sroberto } 503954359Sroberto 504054359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 504154359Sroberto sendbyte(&buf, 0x00); /* current tracking set */ 504254359Sroberto sendetx(&buf, parse); 504354359Sroberto } 504454359Sroberto} 504554359Sroberto 504654359Sroberto/*-------------------------------------------------- 504754359Sroberto * TRIMBLE TSIP end routine 504854359Sroberto */ 504954359Srobertostatic void 505054359Srobertotrimbletsip_end( 505154359Sroberto struct parseunit *parse 505254359Sroberto ) 505354359Sroberto{ trimble_t *t = parse->localdata; 505454359Sroberto 505554359Sroberto if (t) 505654359Sroberto { 505754359Sroberto free(t); 505854359Sroberto parse->localdata = (void *)0; 505954359Sroberto } 506054359Sroberto parse->peer->nextaction = 0; 506154359Sroberto parse->peer->action = (void (*) P((struct peer *)))0; 506254359Sroberto} 506354359Sroberto 506454359Sroberto/*-------------------------------------------------- 506554359Sroberto * TRIMBLE TSIP init routine 506654359Sroberto */ 506754359Srobertostatic int 506854359Srobertotrimbletsip_init( 506954359Sroberto struct parseunit *parse 507054359Sroberto ) 507154359Sroberto{ 507254359Sroberto#if defined(VEOL) || defined(VEOL2) 507354359Sroberto#ifdef HAVE_TERMIOS 507454359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 507554359Sroberto#endif 507654359Sroberto#ifdef HAVE_SYSV_TTYS 507754359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 507854359Sroberto#endif 507954359Sroberto /* 508054359Sroberto * allocate local data area 508154359Sroberto */ 508254359Sroberto if (!parse->localdata) 508354359Sroberto { 508454359Sroberto trimble_t *t; 508554359Sroberto 508654359Sroberto t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 508754359Sroberto 508854359Sroberto if (t) 508954359Sroberto { 509054359Sroberto memset((char *)t, 0, sizeof(trimble_t)); 509154359Sroberto t->last_msg = current_time; 509254359Sroberto } 509354359Sroberto } 509454359Sroberto 509554359Sroberto parse->peer->action = trimble_check; 509654359Sroberto parse->peer->nextaction = current_time; 509754359Sroberto 509854359Sroberto /* 509954359Sroberto * configure terminal line for ICANON mode with VEOL characters 510054359Sroberto */ 510154359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 510254359Sroberto { 510354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 510454359Sroberto return 0; 510554359Sroberto } 510654359Sroberto else 510754359Sroberto { 510854359Sroberto if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 510954359Sroberto { 511054359Sroberto#ifdef VEOL 511154359Sroberto tio.c_cc[VEOL] = ETX; 511254359Sroberto#endif 511354359Sroberto#ifdef VEOL2 511454359Sroberto tio.c_cc[VEOL2] = DLE; 511554359Sroberto#endif 511656746Sroberto } 511754359Sroberto 511854359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 511954359Sroberto { 512054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 512154359Sroberto return 0; 512254359Sroberto } 512354359Sroberto } 512454359Sroberto#endif 512554359Sroberto return trimbletsip_setup(parse, "initial startup"); 512654359Sroberto} 512754359Sroberto 512854359Sroberto/*------------------------------------------------------------ 512954359Sroberto * trimbletsip_event - handle Trimble events 513054359Sroberto * simple evente handler - attempt to re-initialize receiver 513154359Sroberto */ 513254359Srobertostatic void 513354359Srobertotrimbletsip_event( 513454359Sroberto struct parseunit *parse, 513554359Sroberto int event 513654359Sroberto ) 513754359Sroberto{ 513854359Sroberto switch (event) 513954359Sroberto { 514054359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 514154359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 514254359Sroberto (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 514354359Sroberto break; 514454359Sroberto 514554359Sroberto default: /* ignore */ 514654359Sroberto break; 514754359Sroberto } 514854359Sroberto} 514954359Sroberto 515054359Sroberto/* 515154359Sroberto * getflt, getint convert fields in the incoming data into the 515254359Sroberto * appropriate type of item 515354359Sroberto * 515454359Sroberto * CAVEAT: these routines are currently definitely byte order dependent 515554359Sroberto * and assume Representation(float) == IEEE754 515654359Sroberto * These functions MUST be converted to portable versions (especially 515754359Sroberto * converting the float representation into ntp_fp formats in order 515854359Sroberto * to avoid floating point operations at all! 515954359Sroberto */ 516054359Sroberto 516154359Srobertostatic float 516254359Srobertogetflt( 516354359Sroberto u_char *bp 516454359Sroberto ) 516554359Sroberto{ 516654359Sroberto union uval uval; 516754359Sroberto 516854359Sroberto#ifdef WORDS_BIGENDIAN 516954359Sroberto uval.bd[0] = *bp++; 517054359Sroberto uval.bd[1] = *bp++; 517154359Sroberto uval.bd[2] = *bp++; 517254359Sroberto uval.bd[3] = *bp; 517354359Sroberto#else /* ! WORDS_BIGENDIAN */ 517454359Sroberto uval.bd[3] = *bp++; 517554359Sroberto uval.bd[2] = *bp++; 517654359Sroberto uval.bd[1] = *bp++; 517754359Sroberto uval.bd[0] = *bp; 517854359Sroberto#endif /* ! WORDS_BIGENDIAN */ 517954359Sroberto return uval.fv; 518054359Sroberto} 518154359Sroberto 518254359Srobertostatic double 518354359Srobertogetdbl( 518454359Sroberto u_char *bp 518554359Sroberto ) 518654359Sroberto{ 518754359Sroberto union uval uval; 518854359Sroberto 518954359Sroberto#ifdef WORDS_BIGENDIAN 519054359Sroberto uval.bd[0] = *bp++; 519154359Sroberto uval.bd[1] = *bp++; 519254359Sroberto uval.bd[2] = *bp++; 519354359Sroberto uval.bd[3] = *bp++; 519454359Sroberto uval.bd[4] = *bp++; 519554359Sroberto uval.bd[5] = *bp++; 519654359Sroberto uval.bd[6] = *bp++; 519754359Sroberto uval.bd[7] = *bp; 519854359Sroberto#else /* ! WORDS_BIGENDIAN */ 519954359Sroberto uval.bd[7] = *bp++; 520054359Sroberto uval.bd[6] = *bp++; 520154359Sroberto uval.bd[5] = *bp++; 520254359Sroberto uval.bd[4] = *bp++; 520354359Sroberto uval.bd[3] = *bp++; 520454359Sroberto uval.bd[2] = *bp++; 520554359Sroberto uval.bd[1] = *bp++; 520654359Sroberto uval.bd[0] = *bp; 520754359Sroberto#endif /* ! WORDS_BIGENDIAN */ 520854359Sroberto return uval.dv; 520954359Sroberto} 521054359Sroberto 521154359Srobertostatic int 521254359Srobertogetshort( 521354359Sroberto unsigned char *p 521454359Sroberto ) 521554359Sroberto{ 521654359Sroberto return get_msb_short(&p); 521754359Sroberto} 521854359Sroberto 521954359Sroberto/*-------------------------------------------------- 522054359Sroberto * trimbletsip_message - process trimble messages 522154359Sroberto */ 522254359Sroberto#define RTOD (180.0 / 3.1415926535898) 522354359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 522454359Sroberto 522554359Srobertostatic void 522654359Srobertotrimbletsip_message( 522754359Sroberto struct parseunit *parse, 522854359Sroberto parsetime_t *parsetime 522954359Sroberto ) 523054359Sroberto{ 523154359Sroberto unsigned char *buffer = parsetime->parse_msg; 523254359Sroberto unsigned int size = parsetime->parse_msglen; 523354359Sroberto 523454359Sroberto if ((size < 4) || 523554359Sroberto (buffer[0] != DLE) || 523654359Sroberto (buffer[size-1] != ETX) || 523754359Sroberto (buffer[size-2] != DLE)) 523854359Sroberto { 523954359Sroberto#ifdef DEBUG 524054359Sroberto if (debug > 2) { 524154359Sroberto int i; 524254359Sroberto 524354359Sroberto printf("TRIMBLE BAD packet, size %d:\n ", size); 524454359Sroberto for (i = 0; i < size; i++) { 524554359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 524654359Sroberto if (i%16 == 15) printf("\n\t"); 524754359Sroberto } 524854359Sroberto printf("\n"); 524954359Sroberto } 525054359Sroberto#endif 525154359Sroberto return; 525254359Sroberto } 525354359Sroberto else 525454359Sroberto { 525554359Sroberto int var_flag; 525654359Sroberto trimble_t *tr = parse->localdata; 525754359Sroberto unsigned int cmd = buffer[1]; 525854359Sroberto char pbuffer[200]; 525954359Sroberto char *t = pbuffer; 526054359Sroberto cmd_info_t *s; 526154359Sroberto 526254359Sroberto#ifdef DEBUG 526354359Sroberto if (debug > 3) { 526454359Sroberto int i; 526554359Sroberto 526654359Sroberto printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 526754359Sroberto for (i = 0; i < size; i++) { 526854359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 526954359Sroberto if (i%16 == 15) printf("\n\t"); 527054359Sroberto } 527154359Sroberto printf("\n"); 527254359Sroberto } 527354359Sroberto#endif 527454359Sroberto 527554359Sroberto if (tr) 527654359Sroberto tr->last_msg = current_time; 527754359Sroberto 527854359Sroberto s = trimble_convert(cmd, trimble_rcmds); 527954359Sroberto 528054359Sroberto if (s) 528154359Sroberto { 5282182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "%s=\"", s->varname); 528354359Sroberto } 528454359Sroberto else 528554359Sroberto { 5286182007Sroberto DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 528754359Sroberto return; 528854359Sroberto } 528954359Sroberto 529054359Sroberto var_flag = s->varmode; 529154359Sroberto 529254359Sroberto t += strlen(t); 529354359Sroberto 529454359Sroberto switch(cmd) 529554359Sroberto { 529654359Sroberto case CMD_RCURTIME: 5297182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "%f, %d, %f", 5298182007Sroberto getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5299182007Sroberto getflt((unsigned char *)&mb(6))); 530054359Sroberto break; 530154359Sroberto 530254359Sroberto case CMD_RBEST4: 5303182007Sroberto strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t)); 530454359Sroberto t += strlen(t); 530554359Sroberto switch (mb(0) & 0xF) 530654359Sroberto { 530754359Sroberto default: 5308182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7); 530954359Sroberto break; 531054359Sroberto 531154359Sroberto case 1: 5312182007Sroberto strncpy(t, "0D", BUFFER_SIZE(pbuffer, t)); 531354359Sroberto break; 531454359Sroberto 531554359Sroberto case 3: 5316182007Sroberto strncpy(t, "2D", BUFFER_SIZE(pbuffer, t)); 531754359Sroberto break; 531854359Sroberto 531954359Sroberto case 4: 5320182007Sroberto strncpy(t, "3D", BUFFER_SIZE(pbuffer, t)); 532154359Sroberto break; 532254359Sroberto } 532354359Sroberto t += strlen(t); 532454359Sroberto if (mb(0) & 0x10) 5325182007Sroberto strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t)); 532654359Sroberto else 5327182007Sroberto strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t)); 532854359Sroberto t += strlen(t); 532954359Sroberto 5330182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 533154359Sroberto mb(1), mb(2), mb(3), mb(4), 533254359Sroberto getflt((unsigned char *)&mb(5)), 533354359Sroberto getflt((unsigned char *)&mb(9)), 533454359Sroberto getflt((unsigned char *)&mb(13)), 533554359Sroberto getflt((unsigned char *)&mb(17))); 533654359Sroberto 533754359Sroberto break; 533854359Sroberto 533954359Sroberto case CMD_RVERSION: 5340182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "%d.%d (%d/%d/%d)", 534154359Sroberto mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 534254359Sroberto break; 534354359Sroberto 534454359Sroberto case CMD_RRECVHEALTH: 534554359Sroberto { 534654359Sroberto static const char *msgs[] = 534754359Sroberto { 534854359Sroberto "Battery backup failed", 534954359Sroberto "Signal processor error", 535054359Sroberto "Alignment error, channel or chip 1", 535154359Sroberto "Alignment error, channel or chip 2", 535254359Sroberto "Antenna feed line fault", 535354359Sroberto "Excessive ref freq. error", 535454359Sroberto "<BIT 6>", 535554359Sroberto "<BIT 7>" 535654359Sroberto }; 535754359Sroberto 535854359Sroberto int i, bits; 535954359Sroberto 536054359Sroberto switch (mb(0) & 0xFF) 536154359Sroberto { 536254359Sroberto default: 5363182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "illegal value 0x%02x", mb(0) & 0xFF); 536454359Sroberto break; 536554359Sroberto case 0x00: 5366182007Sroberto strncpy(t, "doing position fixes", BUFFER_SIZE(pbuffer, t)); 536754359Sroberto break; 536854359Sroberto case 0x01: 5369182007Sroberto strncpy(t, "no GPS time yet", BUFFER_SIZE(pbuffer, t)); 537054359Sroberto break; 537154359Sroberto case 0x03: 5372182007Sroberto strncpy(t, "PDOP too high", BUFFER_SIZE(pbuffer, t)); 537354359Sroberto break; 537454359Sroberto case 0x08: 5375182007Sroberto strncpy(t, "no usable satellites", BUFFER_SIZE(pbuffer, t)); 537654359Sroberto break; 537754359Sroberto case 0x09: 5378182007Sroberto strncpy(t, "only ONE usable satellite", BUFFER_SIZE(pbuffer, t)); 537954359Sroberto break; 538054359Sroberto case 0x0A: 5381182007Sroberto strncpy(t, "only TWO usable satellites", BUFFER_SIZE(pbuffer, t)); 538254359Sroberto break; 538354359Sroberto case 0x0B: 5384182007Sroberto strncpy(t, "only THREE usable satellites", BUFFER_SIZE(pbuffer, t)); 538554359Sroberto break; 538654359Sroberto case 0x0C: 5387182007Sroberto strncpy(t, "the chosen satellite is unusable", BUFFER_SIZE(pbuffer, t)); 538854359Sroberto break; 538954359Sroberto } 539054359Sroberto 539154359Sroberto t += strlen(t); 539254359Sroberto 539354359Sroberto bits = mb(1) & 0xFF; 539454359Sroberto 539554359Sroberto for (i = 0; i < 8; i++) 539654359Sroberto if (bits & (0x1<<i)) 539754359Sroberto { 5398182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]); 539954359Sroberto t += strlen(t); 540054359Sroberto } 540154359Sroberto } 540254359Sroberto break; 540354359Sroberto 540454359Sroberto case CMD_RMESSAGE: 5405182007Sroberto mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 540654359Sroberto break; 540754359Sroberto 540854359Sroberto case CMD_RMACHSTAT: 540954359Sroberto { 541054359Sroberto static const char *msgs[] = 541154359Sroberto { 541254359Sroberto "Synthesizer Fault", 541354359Sroberto "Battery Powered Time Clock Fault", 541454359Sroberto "A-to-D Converter Fault", 541554359Sroberto "The almanac stored in the receiver is not complete and current", 541654359Sroberto "<BIT 4>", 541754359Sroberto "<BIT 5", 541854359Sroberto "<BIT 6>", 541954359Sroberto "<BIT 7>" 542054359Sroberto }; 542154359Sroberto 542254359Sroberto int i, bits; 542354359Sroberto 5424182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "machine id 0x%02x", mb(0) & 0xFF); 542554359Sroberto t += strlen(t); 542654359Sroberto 542754359Sroberto bits = mb(1) & 0xFF; 542854359Sroberto 542954359Sroberto for (i = 0; i < 8; i++) 543054359Sroberto if (bits & (0x1<<i)) 543154359Sroberto { 5432182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), ", %s", msgs[i]); 543354359Sroberto t += strlen(t); 543454359Sroberto } 543554359Sroberto 5436182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 543754359Sroberto } 543854359Sroberto break; 543954359Sroberto 544054359Sroberto case CMD_ROPERPARAM: 5441182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "%2x %.1f %.1f %.1f %.1f", 544254359Sroberto mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 544354359Sroberto getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 544454359Sroberto break; 544554359Sroberto 544654359Sroberto case CMD_RUTCPARAM: 544754359Sroberto { 544854359Sroberto float t0t = getflt((unsigned char *)&mb(14)); 544954359Sroberto short wnt = getshort((unsigned char *)&mb(18)); 545054359Sroberto short dtls = getshort((unsigned char *)&mb(12)); 545154359Sroberto short wnlsf = getshort((unsigned char *)&mb(20)); 545254359Sroberto short dn = getshort((unsigned char *)&mb(22)); 545354359Sroberto short dtlsf = getshort((unsigned char *)&mb(24)); 545454359Sroberto 545554359Sroberto if ((int)t0t != 0) 545654359Sroberto { 5457182007Sroberto mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 545854359Sroberto } 545954359Sroberto else 546054359Sroberto { 5461182007Sroberto strncpy(t, "<NO UTC DATA>", BUFFER_SIZE(pbuffer, t)); 546254359Sroberto } 546354359Sroberto } 546454359Sroberto break; 546554359Sroberto 546654359Sroberto case CMD_RSAT1BIAS: 5467182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "%.1fm %.2fm/s at %.1fs", 546854359Sroberto getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 546954359Sroberto break; 547054359Sroberto 547154359Sroberto case CMD_RIOOPTIONS: 547254359Sroberto { 5473182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "%02x %02x %02x %02x", 547454359Sroberto mb(0), mb(1), mb(2), mb(3)); 547554359Sroberto if (mb(0) != TRIM_POS_OPT || 547654359Sroberto mb(2) != TRIM_TIME_OPT) 547754359Sroberto { 547854359Sroberto (void)trimbletsip_setup(parse, "bad io options"); 547954359Sroberto } 548054359Sroberto } 548154359Sroberto break; 548254359Sroberto 548354359Sroberto case CMD_RSPOSXYZ: 548454359Sroberto { 548554359Sroberto double x = getflt((unsigned char *)&mb(0)); 548654359Sroberto double y = getflt((unsigned char *)&mb(4)); 548754359Sroberto double z = getflt((unsigned char *)&mb(8)); 548854359Sroberto double f = getflt((unsigned char *)&mb(12)); 548954359Sroberto 549054359Sroberto if (f > 0.0) 5491182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 549254359Sroberto x, y, z, 549354359Sroberto f); 549454359Sroberto else 549554359Sroberto return; 549654359Sroberto } 549754359Sroberto break; 549854359Sroberto 549954359Sroberto case CMD_RSLLAPOS: 550054359Sroberto { 550154359Sroberto double lat = getflt((unsigned char *)&mb(0)); 550254359Sroberto double lng = getflt((unsigned char *)&mb(4)); 550354359Sroberto double f = getflt((unsigned char *)&mb(12)); 550454359Sroberto 550554359Sroberto if (f > 0.0) 5506182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, long %f %c, alt %.2fm", 550754359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 550854359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 550954359Sroberto getflt((unsigned char *)&mb(8))); 551054359Sroberto else 551154359Sroberto return; 551254359Sroberto } 551354359Sroberto break; 551454359Sroberto 551554359Sroberto case CMD_RDOUBLEXYZ: 551654359Sroberto { 551754359Sroberto double x = getdbl((unsigned char *)&mb(0)); 551854359Sroberto double y = getdbl((unsigned char *)&mb(8)); 551954359Sroberto double z = getdbl((unsigned char *)&mb(16)); 5520182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "x= %.1fm, y= %.1fm, z= %.1fm", 552154359Sroberto x, y, z); 552254359Sroberto } 552354359Sroberto break; 552454359Sroberto 552554359Sroberto case CMD_RDOUBLELLA: 552654359Sroberto { 552754359Sroberto double lat = getdbl((unsigned char *)&mb(0)); 552854359Sroberto double lng = getdbl((unsigned char *)&mb(8)); 5529182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "lat %f %c, lon %f %c, alt %.2fm", 553054359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 553154359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 553254359Sroberto getdbl((unsigned char *)&mb(16))); 553354359Sroberto } 553454359Sroberto break; 553554359Sroberto 553654359Sroberto case CMD_RALLINVIEW: 553754359Sroberto { 553854359Sroberto int i, sats; 553954359Sroberto 5540182007Sroberto strncpy(t, "mode: ", BUFFER_SIZE(pbuffer, t)); 554154359Sroberto t += strlen(t); 554254359Sroberto switch (mb(0) & 0x7) 554354359Sroberto { 554454359Sroberto default: 5545182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "0x%x", mb(0) & 0x7); 554654359Sroberto break; 554754359Sroberto 554854359Sroberto case 3: 5549182007Sroberto strncpy(t, "2D", BUFFER_SIZE(pbuffer, t)); 555054359Sroberto break; 555154359Sroberto 555254359Sroberto case 4: 5553182007Sroberto strncpy(t, "3D", BUFFER_SIZE(pbuffer, t)); 555454359Sroberto break; 555554359Sroberto } 555654359Sroberto t += strlen(t); 555754359Sroberto if (mb(0) & 0x8) 5558182007Sroberto strncpy(t, "-MANUAL, ", BUFFER_SIZE(pbuffer, t)); 555954359Sroberto else 5560182007Sroberto strncpy(t, "-AUTO, ", BUFFER_SIZE(pbuffer, t)); 556154359Sroberto t += strlen(t); 556254359Sroberto 556354359Sroberto sats = (mb(0)>>4) & 0xF; 556454359Sroberto 5565182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 556654359Sroberto getflt((unsigned char *)&mb(1)), 556754359Sroberto getflt((unsigned char *)&mb(5)), 556854359Sroberto getflt((unsigned char *)&mb(9)), 556954359Sroberto getflt((unsigned char *)&mb(13)), 557054359Sroberto sats, (sats == 1) ? "" : "s"); 557154359Sroberto t += strlen(t); 557254359Sroberto 557354359Sroberto for (i=0; i < sats; i++) 557454359Sroberto { 5575182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "%s%02d", i ? ", " : "", mb(17+i)); 557654359Sroberto t += strlen(t); 557754359Sroberto if (tr) 557854359Sroberto tr->ctrack |= (1 << (mb(17+i)-1)); 557954359Sroberto } 558054359Sroberto 558154359Sroberto if (tr) 558254359Sroberto { /* mark for tracking status query */ 558354359Sroberto tr->qtracking = 1; 558454359Sroberto } 558554359Sroberto } 558654359Sroberto break; 558754359Sroberto 558854359Sroberto case CMD_RSTATTRACK: 558954359Sroberto { 5590182007Sroberto snprintf(t-2, BUFFER_SIZE(pbuffer, t-2), "[%02d]=\"", mb(0)); /* add index to var name */ 559154359Sroberto t += strlen(t); 559254359Sroberto 559354359Sroberto if (getflt((unsigned char *)&mb(4)) < 0.0) 559454359Sroberto { 5595182007Sroberto strncpy(t, "<NO MEASUREMENTS>", BUFFER_SIZE(pbuffer, t)); 559654359Sroberto var_flag &= ~DEF; 559754359Sroberto } 559854359Sroberto else 559954359Sroberto { 5600182007Sroberto snprintf(t, BUFFER_SIZE(pbuffer, t), "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 560154359Sroberto (mb(1) & 0xFF)>>3, 560254359Sroberto mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 560354359Sroberto mb(3), 560454359Sroberto getflt((unsigned char *)&mb(4)), 560554359Sroberto getflt((unsigned char *)&mb(12)) * RTOD, 560654359Sroberto getflt((unsigned char *)&mb(16)) * RTOD); 560754359Sroberto t += strlen(t); 560854359Sroberto if (mb(20)) 560954359Sroberto { 561054359Sroberto var_flag &= ~DEF; 5611182007Sroberto strncpy(t, ", OLD", BUFFER_SIZE(pbuffer, t)); 561254359Sroberto } 561354359Sroberto t += strlen(t); 561454359Sroberto if (mb(22)) 561554359Sroberto { 561654359Sroberto if (mb(22) == 1) 5617182007Sroberto strncpy(t, ", BAD PARITY", BUFFER_SIZE(pbuffer, t)); 561854359Sroberto else 561954359Sroberto if (mb(22) == 2) 5620182007Sroberto strncpy(t, ", BAD EPH HEALTH", BUFFER_SIZE(pbuffer, t)); 562154359Sroberto } 562254359Sroberto t += strlen(t); 562354359Sroberto if (mb(23)) 5624182007Sroberto strncpy(t, ", collecting data", BUFFER_SIZE(pbuffer, t)); 562554359Sroberto } 562654359Sroberto } 562754359Sroberto break; 562854359Sroberto 562954359Sroberto default: 5630182007Sroberto strncpy(t, "<UNDECODED>", BUFFER_SIZE(pbuffer, t)); 563154359Sroberto break; 563254359Sroberto } 5633182007Sroberto t += strlen(t); 5634182007Sroberto 5635182007Sroberto strncpy(t,"\"", BUFFER_SIZE(pbuffer, t)); 563654359Sroberto set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 563754359Sroberto } 563854359Sroberto} 563954359Sroberto 564054359Sroberto 564154359Sroberto/**============================================================ 564254359Sroberto ** RAWDCF support 564354359Sroberto **/ 564454359Sroberto 564554359Sroberto/*-------------------------------------------------- 564656746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers 564756746Sroberto * SET DTR line 564854359Sroberto */ 564954359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 565054359Srobertostatic int 565156746Srobertorawdcf_init_1( 565254359Sroberto struct parseunit *parse 565354359Sroberto ) 565454359Sroberto{ 565582498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 565654359Sroberto /* 565754359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 565854359Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 565954359Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 566054359Sroberto */ 566182498Sroberto int sl232; 566282498Sroberto 566382498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 566482498Sroberto { 566582498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 566682498Sroberto return 0; 566782498Sroberto } 566882498Sroberto 566954359Sroberto#ifdef TIOCM_DTR 567082498Sroberto sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 567154359Sroberto#else 567282498Sroberto sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 567354359Sroberto#endif 567454359Sroberto 567554359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 567654359Sroberto { 567756746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 567854359Sroberto } 567954359Sroberto return 0; 568054359Sroberto} 568154359Sroberto#else 568254359Srobertostatic int 5683132451Srobertorawdcfdtr_init_1( 568454359Sroberto struct parseunit *parse 568554359Sroberto ) 568654359Sroberto{ 568756746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 568854359Sroberto return 0; 568954359Sroberto} 569054359Sroberto#endif /* DTR initialisation type */ 569154359Sroberto 569254359Sroberto/*-------------------------------------------------- 569356746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers 569456746Sroberto * CLR DTR line, SET RTS line 569554359Sroberto */ 569656746Sroberto#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 569754359Srobertostatic int 569856746Srobertorawdcf_init_2( 569954359Sroberto struct parseunit *parse 570054359Sroberto ) 570154359Sroberto{ 570282498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 570354359Sroberto /* 570454359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 570556746Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 570656746Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 570754359Sroberto */ 570882498Sroberto int sl232; 570982498Sroberto 571082498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 571182498Sroberto { 571282498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 571382498Sroberto return 0; 571482498Sroberto } 571582498Sroberto 571654359Sroberto#ifdef TIOCM_RTS 571782498Sroberto sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 571854359Sroberto#else 571982498Sroberto sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 572054359Sroberto#endif 572154359Sroberto 572254359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 572354359Sroberto { 572456746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 572554359Sroberto } 572654359Sroberto return 0; 572754359Sroberto} 572854359Sroberto#else 572954359Srobertostatic int 573056746Srobertorawdcf_init_2( 573154359Sroberto struct parseunit *parse 573254359Sroberto ) 573354359Sroberto{ 573456746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 573554359Sroberto return 0; 573654359Sroberto} 573756746Sroberto#endif /* DTR initialisation type */ 573854359Sroberto 573954359Sroberto#else /* defined(REFCLOCK) && defined(PARSE) */ 574054359Srobertoint refclock_parse_bs; 574154359Sroberto#endif /* defined(REFCLOCK) && defined(PARSE) */ 574254359Sroberto 574354359Sroberto/* 574454359Sroberto * History: 574554359Sroberto * 574654359Sroberto * refclock_parse.c,v 5747182007Sroberto * Revision 4.80 2007/08/11 12:06:29 kardel 5748182007Sroberto * update comments wrt/ to PPS 5749182007Sroberto * 5750182007Sroberto * Revision 4.79 2007/08/11 11:52:23 kardel 5751182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor 5752182007Sroberto * 5753182007Sroberto * Revision 4.78 2006/12/22 20:08:27 kardel 5754182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5755182007Sroberto * 5756182007Sroberto * Revision 4.77 2006/08/05 07:44:49 kardel 5757182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5758182007Sroberto * 5759182007Sroberto * Revision 4.76 2006/06/22 18:40:47 kardel 5760182007Sroberto * clean up signedness (gcc 4) 5761182007Sroberto * 5762182007Sroberto * Revision 4.75 2006/06/22 16:58:10 kardel 5763182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5764182007Sroberto * the PPS offset. Fix sign of offset passed to kernel. 5765182007Sroberto * 5766182007Sroberto * Revision 4.74 2006/06/18 21:18:37 kardel 5767182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref 5768182007Sroberto * 5769182007Sroberto * Revision 4.73 2006/05/26 14:23:46 kardel 5770182007Sroberto * cleanup of copyright info 5771182007Sroberto * 5772182007Sroberto * Revision 4.72 2006/05/26 14:19:43 kardel 5773182007Sroberto * cleanup of ioctl cruft 5774182007Sroberto * 5775182007Sroberto * Revision 4.71 2006/05/26 14:15:57 kardel 5776182007Sroberto * delay adding refclock to async refclock io after all initializations 5777182007Sroberto * 5778182007Sroberto * Revision 4.70 2006/05/25 18:20:50 kardel 5779182007Sroberto * bug #619 5780182007Sroberto * terminate parse io engine after de-registering 5781182007Sroberto * from refclock io engine 5782182007Sroberto * 5783182007Sroberto * Revision 4.69 2006/05/25 17:28:02 kardel 5784182007Sroberto * complete refclock io structure initialization *before* inserting it into the 5785182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619) 5786182007Sroberto * 5787182007Sroberto * Revision 4.68 2006/05/01 17:02:51 kardel 5788182007Sroberto * copy receiver method also for newlwy created receive buffers 5789182007Sroberto * 5790182007Sroberto * Revision 4.67 2006/05/01 14:37:29 kardel 5791182007Sroberto * If an input buffer parses into more than one message do insert the 5792182007Sroberto * parsed message in a new input buffer instead of processing it 5793182007Sroberto * directly. This avoids deed complicated processing in signal 5794182007Sroberto * handling. 5795182007Sroberto * 5796182007Sroberto * Revision 4.66 2006/03/18 00:45:30 kardel 5797182007Sroberto * coverity fixes found in NetBSD coverity scan 5798182007Sroberto * 5799182007Sroberto * Revision 4.65 2006/01/26 06:08:33 kardel 5800182007Sroberto * output errno on PPS setup failure 5801182007Sroberto * 5802182007Sroberto * Revision 4.64 2005/11/09 20:44:47 kardel 5803182007Sroberto * utilize full PPS timestamp resolution from PPS API 5804182007Sroberto * 5805182007Sroberto * Revision 4.63 2005/10/07 22:10:25 kardel 5806182007Sroberto * bounded buffer implementation 5807182007Sroberto * 5808182007Sroberto * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 5809182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 5810182007Sroberto * replace almost all str* and *printf functions be their buffer bounded 5811182007Sroberto * counterparts 5812182007Sroberto * 5813182007Sroberto * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 5814182007Sroberto * limit re-set rate of trimble clocks 5815182007Sroberto * 5816182007Sroberto * Revision 4.62 2005/08/06 17:40:00 kardel 5817182007Sroberto * cleanup size handling wrt/ to buffer boundaries 5818182007Sroberto * 5819182007Sroberto * Revision 4.61 2005/07/27 21:16:19 kardel 5820182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 5821182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of 5822182007Sroberto * the DCF77 clocks. 5823182007Sroberto * 5824182007Sroberto * Revision 4.60 2005/07/17 21:14:44 kardel 5825182007Sroberto * change contents of version string to include the RCS/CVS Id 5826182007Sroberto * 5827182007Sroberto * Revision 4.59 2005/07/06 06:56:38 kardel 5828182007Sroberto * syntax error 5829182007Sroberto * 5830182007Sroberto * Revision 4.58 2005/07/04 13:10:40 kardel 5831182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup 5832182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 5833182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and 5834182007Sroberto * varying structure element sizes 5835182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers 5836182007Sroberto * 5837182007Sroberto * Revision 4.57 2005/06/25 09:25:19 kardel 5838182007Sroberto * sort out log output sequence 5839182007Sroberto * 5840182007Sroberto * Revision 4.56 2005/06/14 21:47:27 kardel 5841182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel) 5842182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 5843182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state 5844182007Sroberto * 5845182007Sroberto * Revision 4.55 2005/06/02 21:28:31 kardel 5846182007Sroberto * clarify trust logic 5847182007Sroberto * 5848182007Sroberto * Revision 4.54 2005/06/02 17:06:49 kardel 5849182007Sroberto * change status reporting to use fixed refclock_report() 5850182007Sroberto * 5851182007Sroberto * Revision 4.53 2005/06/02 16:33:31 kardel 5852182007Sroberto * fix acceptance of clocks unsync clocks right at start 5853182007Sroberto * 5854182007Sroberto * Revision 4.52 2005/05/26 21:55:06 kardel 5855182007Sroberto * cleanup status reporting 5856182007Sroberto * 5857182007Sroberto * Revision 4.51 2005/05/26 19:19:14 kardel 5858182007Sroberto * implement fast refclock startup 5859182007Sroberto * 5860182007Sroberto * Revision 4.50 2005/04/16 20:51:35 kardel 5861182007Sroberto * set pps_enable = 1 when binding a kernel PPS source 5862182007Sroberto * 5863182007Sroberto * Revision 4.49 2005/04/16 17:29:26 kardel 5864182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks 5865182007Sroberto * 5866182007Sroberto * Revision 4.48 2005/04/16 16:22:27 kardel 5867182007Sroberto * bk sync 20050415 ntp-dev 5868182007Sroberto * 5869182007Sroberto * Revision 4.47 2004/11/29 10:42:48 kardel 5870182007Sroberto * bk sync ntp-dev 20041129 5871182007Sroberto * 5872182007Sroberto * Revision 4.46 2004/11/29 10:26:29 kardel 5873182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 5874182007Sroberto * 5875182007Sroberto * Revision 4.45 2004/11/14 20:53:20 kardel 5876182007Sroberto * clear PPS flags after using them 5877182007Sroberto * 5878182007Sroberto * Revision 4.44 2004/11/14 15:29:41 kardel 5879182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style 5880182007Sroberto * 5881182007Sroberto * Revision 4.43 2001/05/26 22:53:16 kardel 5882182007Sroberto * 20010526 reconcilation 5883182007Sroberto * 5884182007Sroberto * Revision 4.42 2000/05/14 15:31:51 kardel 5885182007Sroberto * PPSAPI && RAWDCF modemline support 5886182007Sroberto * 5887182007Sroberto * Revision 4.41 2000/04/09 19:50:45 kardel 5888182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1 5889182007Sroberto * 5890182007Sroberto * Revision 4.40 2000/04/09 15:27:55 kardel 5891182007Sroberto * modem line fiddle in rawdcf_init_2 5892182007Sroberto * 5893182007Sroberto * Revision 4.39 2000/03/18 09:16:55 kardel 5894182007Sroberto * PPSAPI integration 5895182007Sroberto * 5896182007Sroberto * Revision 4.38 2000/03/05 20:25:06 kardel 5897182007Sroberto * support PPSAPI 5898182007Sroberto * 5899182007Sroberto * Revision 4.37 2000/03/05 20:11:14 kardel 5900182007Sroberto * 4.0.99g reconcilation 5901182007Sroberto * 590256746Sroberto * Revision 4.36 1999/11/28 17:18:20 kardel 590356746Sroberto * disabled burst mode 590456746Sroberto * 590556746Sroberto * Revision 4.35 1999/11/28 09:14:14 kardel 590656746Sroberto * RECON_4_0_98F 590756746Sroberto * 590856746Sroberto * Revision 4.34 1999/05/14 06:08:05 kardel 590956746Sroberto * store current_time in a suitable container (u_long) 591056746Sroberto * 591156746Sroberto * Revision 4.33 1999/05/13 21:48:38 kardel 591256746Sroberto * double the no response timeout interval 591356746Sroberto * 591456746Sroberto * Revision 4.32 1999/05/13 20:09:13 kardel 591556746Sroberto * complain only about missing polls after a full poll interval 591656746Sroberto * 591756746Sroberto * Revision 4.31 1999/05/13 19:59:32 kardel 591856746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF 591956746Sroberto * 592056746Sroberto * Revision 4.30 1999/02/28 20:36:43 kardel 592156746Sroberto * fixed printf fmt 592256746Sroberto * 592354359Sroberto * Revision 4.29 1999/02/28 19:58:23 kardel 592454359Sroberto * updated copyright information 592554359Sroberto * 592654359Sroberto * Revision 4.28 1999/02/28 19:01:50 kardel 592754359Sroberto * improved debug out on sent Meinberg messages 592854359Sroberto * 592954359Sroberto * Revision 4.27 1999/02/28 18:05:55 kardel 593054359Sroberto * no linux/ppsclock.h stuff 593154359Sroberto * 593254359Sroberto * Revision 4.26 1999/02/28 15:27:27 kardel 593354359Sroberto * wharton clock integration 593454359Sroberto * 593554359Sroberto * Revision 4.25 1999/02/28 14:04:46 kardel 593654359Sroberto * added missing double quotes to UTC information string 593754359Sroberto * 593854359Sroberto * Revision 4.24 1999/02/28 12:06:50 kardel 593954359Sroberto * (parse_control): using gmprettydate instead of prettydate() 594054359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information 594154359Sroberto * (gps16x_message): changed to use mk_utcinfo() 594254359Sroberto * (trimbletsip_message): changed to use mk_utcinfo() 594354359Sroberto * ignoring position information in unsynchronized mode 594454359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 594554359Sroberto * 594654359Sroberto * Revision 4.23 1999/02/23 19:47:53 kardel 594754359Sroberto * fixed #endifs 594854359Sroberto * (stream_receive): fixed formats 594954359Sroberto * 595054359Sroberto * Revision 4.22 1999/02/22 06:21:02 kardel 595154359Sroberto * use new autoconfig symbols 595254359Sroberto * 595354359Sroberto * Revision 4.21 1999/02/21 12:18:13 kardel 595454359Sroberto * 4.91f reconcilation 595554359Sroberto * 595654359Sroberto * Revision 4.20 1999/02/21 10:53:36 kardel 595754359Sroberto * initial Linux PPSkit version 595854359Sroberto * 595954359Sroberto * Revision 4.19 1999/02/07 09:10:45 kardel 596054359Sroberto * clarify STREAMS mitigation rules in comment 596154359Sroberto * 596254359Sroberto * Revision 4.18 1998/12/20 23:45:34 kardel 596354359Sroberto * fix types and warnings 596454359Sroberto * 596554359Sroberto * Revision 4.17 1998/11/15 21:24:51 kardel 596654359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG 596754359Sroberto * is not defined 596854359Sroberto * 596954359Sroberto * Revision 4.16 1998/11/15 20:28:17 kardel 597054359Sroberto * Release 4.0.73e13 reconcilation 597154359Sroberto * 597254359Sroberto * Revision 4.15 1998/08/22 21:56:08 kardel 597354359Sroberto * fixed IO handling for non-STREAM IO 597454359Sroberto * 597554359Sroberto * Revision 4.14 1998/08/16 19:00:48 kardel 597654359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 597754359Sroberto * made uval a local variable (killed one of the last globals) 597854359Sroberto * (sendetx): added logging of messages when in debug mode 597954359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization 598054359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation 598154359Sroberto * (trimbletsip_message): extended message interpretation 598254359Sroberto * (getdbl): fixed data conversion 598354359Sroberto * 598454359Sroberto * Revision 4.13 1998/08/09 22:29:13 kardel 598554359Sroberto * Trimble TSIP support 598654359Sroberto * 598754359Sroberto * Revision 4.12 1998/07/11 10:05:34 kardel 598854359Sroberto * Release 4.0.73d reconcilation 598954359Sroberto * 599054359Sroberto * Revision 4.11 1998/06/14 21:09:42 kardel 599154359Sroberto * Sun acc cleanup 599254359Sroberto * 599354359Sroberto * Revision 4.10 1998/06/13 12:36:45 kardel 599454359Sroberto * signed/unsigned, name clashes 599554359Sroberto * 599654359Sroberto * Revision 4.9 1998/06/12 15:30:00 kardel 599754359Sroberto * prototype fixes 599854359Sroberto * 599954359Sroberto * Revision 4.8 1998/06/12 11:19:42 kardel 600054359Sroberto * added direct input processing routine for refclocks in 600154359Sroberto * order to avaiod that single character io gobbles up all 600254359Sroberto * receive buffers and drops input data. (Problem started 600354359Sroberto * with fast machines so a character a buffer was possible 600454359Sroberto * one of the few cases where faster machines break existing 600554359Sroberto * allocation algorithms) 600654359Sroberto * 600754359Sroberto * Revision 4.7 1998/06/06 18:35:20 kardel 600854359Sroberto * (parse_start): added BURST mode initialisation 600954359Sroberto * 601054359Sroberto * Revision 4.6 1998/05/27 06:12:46 kardel 601154359Sroberto * RAWDCF_BASEDELAY default added 601254359Sroberto * old comment removed 601354359Sroberto * casts for ioctl() 601454359Sroberto * 601554359Sroberto * Revision 4.5 1998/05/25 22:05:09 kardel 601654359Sroberto * RAWDCF_SETDTR option removed 601754359Sroberto * clock type 14 attempts to set DTR for 601854359Sroberto * power supply of RAWDCF receivers 601954359Sroberto * 602054359Sroberto * Revision 4.4 1998/05/24 16:20:47 kardel 602154359Sroberto * updated comments referencing Meinberg clocks 602254359Sroberto * added RAWDCF clock with DTR set option as type 14 602354359Sroberto * 602454359Sroberto * Revision 4.3 1998/05/24 10:48:33 kardel 602554359Sroberto * calibrated CONRAD RAWDCF default fudge factor 602654359Sroberto * 602754359Sroberto * Revision 4.2 1998/05/24 09:59:35 kardel 602854359Sroberto * corrected version information (ntpq support) 602954359Sroberto * 603054359Sroberto * Revision 4.1 1998/05/24 09:52:31 kardel 603154359Sroberto * use fixed format only (new IO model) 603254359Sroberto * output debug to stdout instead of msyslog() 603354359Sroberto * don't include >"< in ASCII output in order not to confuse 603454359Sroberto * ntpq parsing 603554359Sroberto * 603654359Sroberto * Revision 4.0 1998/04/10 19:52:11 kardel 603754359Sroberto * Start 4.0 release version numbering 603854359Sroberto * 603954359Sroberto * Revision 1.2 1998/04/10 19:28:04 kardel 604054359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 604154359Sroberto * derived from 3.105.1.2 from V3 tree 604254359Sroberto * 604354359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 604454359Sroberto * 604554359Sroberto */ 6046