refclock_parse.c revision 280849
154359Sroberto/* 2280849Scy * /src/NTP/REPOSITORY/ntp4-dev/ntpd/refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 354359Sroberto * 4280849Scy * refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A 554359Sroberto * 6182007Sroberto * generic reference clock driver for several DCF/GPS/MSF/... receivers 754359Sroberto * 8182007Sroberto * PPS notes: 9182007Sroberto * On systems that support PPSAPI (RFC2783) PPSAPI is the 10182007Sroberto * preferred interface. 1154359Sroberto * 12182007Sroberto * Optionally make use of a STREAMS module for input processing where 13182007Sroberto * available and configured. This STREAMS module reduces the time 14182007Sroberto * stamp latency for serial and PPS events. 15182007Sroberto * Currently the STREAMS module is only available for Suns running 16182007Sroberto * SunOS 4.x and SunOS5.x. 1754359Sroberto * 18280849Scy * Copyright (c) 1995-2009 by Frank Kardel <kardel <AT> ntp.org> 19280849Scy * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany 2054359Sroberto * 21182007Sroberto * Redistribution and use in source and binary forms, with or without 22182007Sroberto * modification, are permitted provided that the following conditions 23182007Sroberto * are met: 24182007Sroberto * 1. Redistributions of source code must retain the above copyright 25182007Sroberto * notice, this list of conditions and the following disclaimer. 26182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright 27182007Sroberto * notice, this list of conditions and the following disclaimer in the 28182007Sroberto * documentation and/or other materials provided with the distribution. 29182007Sroberto * 3. Neither the name of the author nor the names of its contributors 30182007Sroberto * may be used to endorse or promote products derived from this software 31182007Sroberto * without specific prior written permission. 3254359Sroberto * 33182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 34182007Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35182007Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36182007Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 37182007Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38182007Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39182007Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40182007Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41182007Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42182007Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43182007Sroberto * SUCH DAMAGE. 4454359Sroberto * 4554359Sroberto */ 4654359Sroberto 4754359Sroberto#ifdef HAVE_CONFIG_H 48182007Sroberto# include "config.h" 4954359Sroberto#endif 5054359Sroberto 51280849Scy#include "ntp_types.h" 52280849Scy 5354359Sroberto#if defined(REFCLOCK) && defined(CLOCK_PARSE) 5454359Sroberto 5554359Sroberto/* 5654359Sroberto * This driver currently provides the support for 5754359Sroberto * - Meinberg receiver DCF77 PZF 535 (TCXO version) (DCF) 5854359Sroberto * - Meinberg receiver DCF77 PZF 535 (OCXO version) (DCF) 5954359Sroberto * - Meinberg receiver DCF77 PZF 509 (DCF) 6054359Sroberto * - Meinberg receiver DCF77 AM receivers (e.g. C51) (DCF) 6154359Sroberto * - IGEL CLOCK (DCF) 6254359Sroberto * - ELV DCF7000 (DCF) 6354359Sroberto * - Schmid clock (DCF) 6454359Sroberto * - Conrad DCF77 receiver module (DCF) 6554359Sroberto * - FAU DCF77 NTP receiver (TimeBrick) (DCF) 66182007Sroberto * - WHARTON 400A Series clock (DCF) 6754359Sroberto * 6854359Sroberto * - Meinberg GPS166/GPS167 (GPS) 6954359Sroberto * - Trimble (TSIP and TAIP protocol) (GPS) 7054359Sroberto * 7154359Sroberto * - RCC8000 MSF Receiver (MSF) 7254359Sroberto * - VARITEXT clock (MSF) 7354359Sroberto */ 7454359Sroberto 7554359Sroberto/* 7654359Sroberto * Meinberg receivers are usually connected via a 7754359Sroberto * 9600 baud serial line 7854359Sroberto * 7954359Sroberto * The Meinberg GPS receivers also have a special NTP time stamp 8054359Sroberto * format. The firmware release is Uni-Erlangen. 8154359Sroberto * 8254359Sroberto * Meinberg generic receiver setup: 8354359Sroberto * output time code every second 8454359Sroberto * Baud rate 9600 7E2S 8554359Sroberto * 8654359Sroberto * Meinberg GPS16x setup: 8754359Sroberto * output time code every second 8854359Sroberto * Baudrate 19200 8N1 8954359Sroberto * 9054359Sroberto * This software supports the standard data formats used 9154359Sroberto * in Meinberg receivers. 9254359Sroberto * 9354359Sroberto * Special software versions are only sensible for the 9454359Sroberto * GPS 16x family of receivers. 9554359Sroberto * 9654359Sroberto * Meinberg can be reached via: http://www.meinberg.de/ 9754359Sroberto */ 9854359Sroberto 9954359Sroberto#include "ntpd.h" 10054359Sroberto#include "ntp_refclock.h" 101280849Scy#include "timevalops.h" /* includes <sys/time.h> */ 10254359Sroberto#include "ntp_control.h" 103182007Sroberto#include "ntp_string.h" 10454359Sroberto 10554359Sroberto#include <stdio.h> 10654359Sroberto#include <ctype.h> 10754359Sroberto#ifndef TM_IN_SYS_TIME 10854359Sroberto# include <time.h> 10954359Sroberto#endif 11054359Sroberto 111182007Sroberto#ifdef HAVE_UNISTD_H 112182007Sroberto# include <unistd.h> 113182007Sroberto#endif 114182007Sroberto 11554359Sroberto#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS) 11654359Sroberto# include "Bletch: Define one of {STREAM,HAVE_SYSV_TTYS,HAVE_TERMIOS}" 11754359Sroberto#endif 11854359Sroberto 11954359Sroberto#ifdef STREAM 12054359Sroberto# include <sys/stream.h> 12154359Sroberto# include <sys/stropts.h> 12254359Sroberto#endif 12354359Sroberto 12454359Sroberto#ifdef HAVE_TERMIOS 125280849Scy# include <termios.h> 12654359Sroberto# define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 12754359Sroberto# define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 12854359Sroberto# undef HAVE_SYSV_TTYS 12954359Sroberto#endif 13054359Sroberto 13154359Sroberto#ifdef HAVE_SYSV_TTYS 13254359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) 13354359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) 13454359Sroberto#endif 13554359Sroberto 13654359Sroberto#ifdef HAVE_BSD_TTYS 13754359Sroberto/* #error CURRENTLY NO BSD TTY SUPPORT */ 13854359Sroberto# include "Bletch: BSD TTY not currently supported" 13954359Sroberto#endif 14054359Sroberto 14154359Sroberto#ifdef HAVE_SYS_IOCTL_H 14254359Sroberto# include <sys/ioctl.h> 14354359Sroberto#endif 14454359Sroberto 145182007Sroberto#ifdef HAVE_PPSAPI 146182007Sroberto# include "ppsapi_timepps.h" 147280849Scy# include "refclock_atom.h" 148182007Sroberto#endif 149182007Sroberto 15054359Sroberto#ifdef PPS 151182007Sroberto# ifdef HAVE_SYS_PPSCLOCK_H 152182007Sroberto# include <sys/ppsclock.h> 153182007Sroberto# endif 154182007Sroberto# ifdef HAVE_TIO_SERIAL_STUFF 155182007Sroberto# include <linux/serial.h> 156182007Sroberto# endif 15754359Sroberto#endif 158182007Sroberto 159182007Sroberto#define BUFFER_SIZE(_BUF, _PTR) ((_BUF) + sizeof(_BUF) - (_PTR)) 160182007Sroberto#define BUFFER_SIZES(_BUF, _PTR, _SZ) ((_BUF) + (_SZ) - (_PTR)) 161182007Sroberto 162182007Sroberto/* 163182007Sroberto * document type of PPS interfacing - copy of ifdef mechanism in local_input() 164182007Sroberto */ 165182007Sroberto#undef PPS_METHOD 166182007Sroberto 167182007Sroberto#ifdef HAVE_PPSAPI 168182007Sroberto#define PPS_METHOD "PPS API" 169182007Sroberto#else 170182007Sroberto#ifdef TIOCDCDTIMESTAMP 171182007Sroberto#define PPS_METHOD "TIOCDCDTIMESTAMP" 172182007Sroberto#else /* TIOCDCDTIMESTAMP */ 173182007Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 174182007Sroberto#ifdef HAVE_CIOGETEV 175182007Sroberto#define PPS_METHOD "CIOGETEV" 17654359Sroberto#endif 177182007Sroberto#ifdef HAVE_TIOCGPPSEV 178182007Sroberto#define PPS_METHOD "TIOCGPPSEV" 17954359Sroberto#endif 180182007Sroberto#endif 181182007Sroberto#endif /* TIOCDCDTIMESTAMP */ 182182007Sroberto#endif /* HAVE_PPSAPI */ 18354359Sroberto 18454359Sroberto#include "ntp_io.h" 18554359Sroberto#include "ntp_stdlib.h" 18654359Sroberto 18754359Sroberto#include "parse.h" 18854359Sroberto#include "mbg_gps166.h" 18954359Sroberto#include "trimble.h" 19054359Sroberto#include "binio.h" 19154359Sroberto#include "ascii.h" 19254359Sroberto#include "ieee754io.h" 193182007Sroberto#include "recvbuff.h" 19454359Sroberto 195280849Scystatic char rcsid[] = "refclock_parse.c,v 4.81 2009/05/01 10:15:29 kardel RELEASE_20090105_A+POWERUPTRUST"; 19654359Sroberto 19754359Sroberto/**=========================================================================== 19854359Sroberto ** external interface to ntp mechanism 19954359Sroberto **/ 20054359Sroberto 201280849Scystatic int parse_start (int, struct peer *); 202280849Scystatic void parse_shutdown (int, struct peer *); 203280849Scystatic void parse_poll (int, struct peer *); 204280849Scystatic void parse_control (int, const struct refclockstat *, struct refclockstat *, struct peer *); 20554359Sroberto 20654359Srobertostruct refclock refclock_parse = { 20754359Sroberto parse_start, 20854359Sroberto parse_shutdown, 20954359Sroberto parse_poll, 21054359Sroberto parse_control, 211182007Sroberto noentry, 212182007Sroberto noentry, 21354359Sroberto NOFLAGS 21454359Sroberto}; 21554359Sroberto 21654359Sroberto/* 21754359Sroberto * Definitions 21854359Sroberto */ 21954359Sroberto#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */ 22054359Sroberto#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */ 221182007Sroberto#define PARSEPPSDEVICE "/dev/refclockpps-%d" /* optional pps device to open %d is unit number */ 22254359Sroberto 22354359Sroberto#undef ABS 22454359Sroberto#define ABS(_X_) (((_X_) < 0) ? -(_X_) : (_X_)) 22554359Sroberto 226182007Sroberto#define PARSE_HARDPPS_DISABLE 0 227182007Sroberto#define PARSE_HARDPPS_ENABLE 1 228182007Sroberto 22954359Sroberto/**=========================================================================== 23054359Sroberto ** function vector for dynamically binding io handling mechanism 23154359Sroberto **/ 23254359Sroberto 23354359Srobertostruct parseunit; /* to keep inquiring minds happy */ 23454359Sroberto 23554359Srobertotypedef struct bind 23654359Sroberto{ 23754359Sroberto const char *bd_description; /* name of type of binding */ 238280849Scy int (*bd_init) (struct parseunit *); /* initialize */ 239280849Scy void (*bd_end) (struct parseunit *); /* end */ 240280849Scy int (*bd_setcs) (struct parseunit *, parsectl_t *); /* set character size */ 241280849Scy int (*bd_disable) (struct parseunit *); /* disable */ 242280849Scy int (*bd_enable) (struct parseunit *); /* enable */ 243280849Scy int (*bd_getfmt) (struct parseunit *, parsectl_t *); /* get format */ 244280849Scy int (*bd_setfmt) (struct parseunit *, parsectl_t *); /* setfmt */ 245280849Scy int (*bd_timecode) (struct parseunit *, parsectl_t *); /* get time code */ 246280849Scy void (*bd_receive) (struct recvbuf *); /* receive operation */ 247280849Scy int (*bd_io_input) (struct recvbuf *); /* input operation */ 24854359Sroberto} bind_t; 24954359Sroberto 25054359Sroberto#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_) 25154359Sroberto#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_) 25254359Sroberto#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_) 25354359Sroberto#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_) 25454359Sroberto#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_) 25554359Sroberto#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_) 25654359Sroberto#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_) 25754359Sroberto 25854359Sroberto/* 259280849Scy * special handling flags 26054359Sroberto */ 261280849Scy#define PARSE_F_PPSONSECOND 0x00000001 /* PPS pulses are on second */ 262280849Scy#define PARSE_F_POWERUPTRUST 0x00000100 /* POWERUP state ist trusted for */ 263280849Scy /* trusttime after SYNC was seen */ 26454359Sroberto/**=========================================================================== 26554359Sroberto ** error message regression handling 26654359Sroberto ** 26754359Sroberto ** there are quite a few errors that can occur in rapid succession such as 26854359Sroberto ** noisy input data or no data at all. in order to reduce the amount of 26954359Sroberto ** syslog messages in such case, we are using a backoff algorithm. We limit 27054359Sroberto ** the number of error messages of a certain class to 1 per time unit. if a 27154359Sroberto ** configurable number of messages is displayed that way, we move on to the 27254359Sroberto ** next time unit / count for that class. a count of messages that have been 27354359Sroberto ** suppressed is held and displayed whenever a corresponding message is 27454359Sroberto ** displayed. the time units for a message class will also be displayed. 27554359Sroberto ** whenever an error condition clears we reset the error message state, 27654359Sroberto ** thus we would still generate much output on pathological conditions 27754359Sroberto ** where the system oscillates between OK and NOT OK states. coping 27854359Sroberto ** with that condition is currently considered too complicated. 27954359Sroberto **/ 28054359Sroberto 28154359Sroberto#define ERR_ALL (unsigned)~0 /* "all" errors */ 28254359Sroberto#define ERR_BADDATA (unsigned)0 /* unusable input data/conversion errors */ 28354359Sroberto#define ERR_NODATA (unsigned)1 /* no input data */ 28454359Sroberto#define ERR_BADIO (unsigned)2 /* read/write/select errors */ 28554359Sroberto#define ERR_BADSTATUS (unsigned)3 /* unsync states */ 28654359Sroberto#define ERR_BADEVENT (unsigned)4 /* non nominal events */ 28754359Sroberto#define ERR_INTERNAL (unsigned)5 /* internal error */ 28854359Sroberto#define ERR_CNT (unsigned)(ERR_INTERNAL+1) 28954359Sroberto 29054359Sroberto#define ERR(_X_) if (list_err(parse, (_X_))) 29154359Sroberto 29254359Srobertostruct errorregression 29354359Sroberto{ 29454359Sroberto u_long err_count; /* number of repititions per class */ 29554359Sroberto u_long err_delay; /* minimum delay between messages */ 29654359Sroberto}; 29754359Sroberto 29854359Srobertostatic struct errorregression 29954359Srobertoerr_baddata[] = /* error messages for bad input data */ 30054359Sroberto{ 30154359Sroberto { 1, 0 }, /* output first message immediately */ 30254359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 30354359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 30454359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 30554359Sroberto}; 30654359Sroberto 30754359Srobertostatic struct errorregression 30854359Srobertoerr_nodata[] = /* error messages for missing input data */ 30954359Sroberto{ 31054359Sroberto { 1, 0 }, /* output first message immediately */ 31154359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 31254359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 31354359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 31454359Sroberto}; 31554359Sroberto 31654359Srobertostatic struct errorregression 31754359Srobertoerr_badstatus[] = /* unsynchronized state messages */ 31854359Sroberto{ 31954359Sroberto { 1, 0 }, /* output first message immediately */ 32054359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 32154359Sroberto { 3, 3600 }, /* output next 3 messages in hour intervals */ 32254359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 32354359Sroberto}; 32454359Sroberto 32554359Srobertostatic struct errorregression 32654359Srobertoerr_badio[] = /* io failures (bad reads, selects, ...) */ 32754359Sroberto{ 32854359Sroberto { 1, 0 }, /* output first message immediately */ 32954359Sroberto { 5, 60 }, /* output next five messages in 60 second intervals */ 33054359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 33154359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 33254359Sroberto}; 33354359Sroberto 33454359Srobertostatic struct errorregression 33554359Srobertoerr_badevent[] = /* non nominal events */ 33654359Sroberto{ 33754359Sroberto { 20, 0 }, /* output first message immediately */ 33854359Sroberto { 6, 60 }, /* output next five messages in 60 second intervals */ 33954359Sroberto { 5, 3600 }, /* output next 3 messages in hour intervals */ 34054359Sroberto { 0, 12*3600 } /* repeat messages only every 12 hours */ 34154359Sroberto}; 34254359Sroberto 34354359Srobertostatic struct errorregression 34454359Srobertoerr_internal[] = /* really bad things - basically coding/OS errors */ 34554359Sroberto{ 34654359Sroberto { 0, 0 }, /* output all messages immediately */ 34754359Sroberto}; 34854359Sroberto 34954359Srobertostatic struct errorregression * 35054359Srobertoerr_tbl[] = 35154359Sroberto{ 35254359Sroberto err_baddata, 35354359Sroberto err_nodata, 35454359Sroberto err_badio, 35554359Sroberto err_badstatus, 35654359Sroberto err_badevent, 35754359Sroberto err_internal 35854359Sroberto}; 35954359Sroberto 36054359Srobertostruct errorinfo 36154359Sroberto{ 36254359Sroberto u_long err_started; /* begin time (ntp) of error condition */ 36354359Sroberto u_long err_last; /* last time (ntp) error occurred */ 36454359Sroberto u_long err_cnt; /* number of error repititions */ 36554359Sroberto u_long err_suppressed; /* number of suppressed messages */ 36654359Sroberto struct errorregression *err_stage; /* current error stage */ 36754359Sroberto}; 36854359Sroberto 36954359Sroberto/**=========================================================================== 37054359Sroberto ** refclock instance data 37154359Sroberto **/ 37254359Sroberto 37354359Srobertostruct parseunit 37454359Sroberto{ 37554359Sroberto /* 37654359Sroberto * NTP management 37754359Sroberto */ 37854359Sroberto struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */ 37954359Sroberto struct refclockproc *generic; /* backlink to refclockproc structure */ 38054359Sroberto 38154359Sroberto /* 38254359Sroberto * PARSE io 38354359Sroberto */ 38454359Sroberto bind_t *binding; /* io handling binding */ 38554359Sroberto 38654359Sroberto /* 38754359Sroberto * parse state 38854359Sroberto */ 38954359Sroberto parse_t parseio; /* io handling structure (user level parsing) */ 39054359Sroberto 39154359Sroberto /* 39254359Sroberto * type specific parameters 39354359Sroberto */ 39454359Sroberto struct parse_clockinfo *parse_type; /* link to clock description */ 39554359Sroberto 39654359Sroberto /* 39754359Sroberto * clock state handling/reporting 39854359Sroberto */ 39954359Sroberto u_char flags; /* flags (leap_control) */ 40054359Sroberto u_long lastchange; /* time (ntp) when last state change accured */ 40154359Sroberto u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */ 40256746Sroberto u_long pollneeddata; /* current_time(!=0) for receive sample expected in PPS mode */ 40354359Sroberto u_short lastformat; /* last format used */ 40454359Sroberto u_long lastsync; /* time (ntp) when clock was last seen fully synchronized */ 405182007Sroberto u_long maxunsync; /* max time in seconds a receiver is trusted after loosing synchronisation */ 406182007Sroberto double ppsphaseadjust; /* phase adjustment of PPS time stamp */ 407182007Sroberto u_long lastmissed; /* time (ntp) when poll didn't get data (powerup heuristic) */ 40854359Sroberto u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */ 409182007Sroberto int ppsfd; /* fd to ise for PPS io */ 410182007Sroberto#ifdef HAVE_PPSAPI 411182007Sroberto int hardppsstate; /* current hard pps state */ 412280849Scy struct refclock_atom atom; /* PPSAPI structure */ 413182007Sroberto#endif 414182007Sroberto parsetime_t timedata; /* last (parse module) data */ 41554359Sroberto void *localdata; /* optional local, receiver-specific data */ 41654359Sroberto unsigned long localstate; /* private local state */ 41754359Sroberto struct errorinfo errors[ERR_CNT]; /* error state table for suppressing excessive error messages */ 41854359Sroberto struct ctl_var *kv; /* additional pseudo variables */ 41954359Sroberto u_long laststatistic; /* time when staticstics where output */ 42054359Sroberto}; 42154359Sroberto 42254359Sroberto 42354359Sroberto/**=========================================================================== 42454359Sroberto ** Clockinfo section all parameter for specific clock types 42554359Sroberto ** includes NTP parameters, TTY parameters and IO handling parameters 42654359Sroberto **/ 42754359Sroberto 428280849Scystatic void poll_dpoll (struct parseunit *); 429280849Scystatic void poll_poll (struct peer *); 430280849Scystatic int poll_init (struct parseunit *); 43154359Sroberto 43254359Srobertotypedef struct poll_info 43354359Sroberto{ 43454359Sroberto u_long rate; /* poll rate - once every "rate" seconds - 0 off */ 43554359Sroberto const char *string; /* string to send for polling */ 43654359Sroberto u_long count; /* number of characters in string */ 43754359Sroberto} poll_info_t; 43854359Sroberto 43954359Sroberto#define NO_CL_FLAGS 0 44054359Sroberto#define NO_POLL 0 44154359Sroberto#define NO_INIT 0 44254359Sroberto#define NO_END 0 44354359Sroberto#define NO_EVENT 0 444182007Sroberto#define NO_LCLDATA 0 44554359Sroberto#define NO_MESSAGE 0 44654359Sroberto#define NO_PPSDELAY 0 44754359Sroberto 44854359Sroberto#define DCF_ID "DCF" /* generic DCF */ 44954359Sroberto#define DCF_A_ID "DCFa" /* AM demodulation */ 45054359Sroberto#define DCF_P_ID "DCFp" /* psuedo random phase shift */ 45154359Sroberto#define GPS_ID "GPS" /* GPS receiver */ 45254359Sroberto 45354359Sroberto#define NOCLOCK_ROOTDELAY 0.0 45454359Sroberto#define NOCLOCK_BASEDELAY 0.0 45554359Sroberto#define NOCLOCK_DESCRIPTION 0 45654359Sroberto#define NOCLOCK_MAXUNSYNC 0 45754359Sroberto#define NOCLOCK_CFLAG 0 45854359Sroberto#define NOCLOCK_IFLAG 0 45954359Sroberto#define NOCLOCK_OFLAG 0 46054359Sroberto#define NOCLOCK_LFLAG 0 46154359Sroberto#define NOCLOCK_ID "TILT" 46254359Sroberto#define NOCLOCK_POLL NO_POLL 46354359Sroberto#define NOCLOCK_INIT NO_INIT 46454359Sroberto#define NOCLOCK_END NO_END 465182007Sroberto#define NOCLOCK_DATA NO_LCLDATA 46654359Sroberto#define NOCLOCK_FORMAT "" 46754359Sroberto#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC 46854359Sroberto#define NOCLOCK_SAMPLES 0 46954359Sroberto#define NOCLOCK_KEEP 0 47054359Sroberto 47154359Sroberto#define DCF_TYPE CTL_SST_TS_LF 47254359Sroberto#define GPS_TYPE CTL_SST_TS_UHF 47354359Sroberto 47454359Sroberto/* 47554359Sroberto * receiver specific constants 47654359Sroberto */ 47754359Sroberto#define MBG_SPEED (B9600) 478182007Sroberto#define MBG_CFLAG (CS7|PARENB|CREAD|CLOCAL|HUPCL|CSTOPB) 47954359Sroberto#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP) 48054359Sroberto#define MBG_OFLAG 0 48154359Sroberto#define MBG_LFLAG 0 48254359Sroberto#define MBG_FLAGS PARSE_F_PPSONSECOND 48354359Sroberto 48454359Sroberto/* 48554359Sroberto * Meinberg DCF77 receivers 48654359Sroberto */ 48754359Sroberto#define DCFUA31_ROOTDELAY 0.0 /* 0 */ 48854359Sroberto#define DCFUA31_BASEDELAY 0.010 /* 10.7421875ms: 10 ms (+/- 3 ms) */ 48954359Sroberto#define DCFUA31_DESCRIPTION "Meinberg DCF77 C51 or compatible" 49054359Sroberto#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */ 49154359Sroberto#define DCFUA31_SPEED MBG_SPEED 49254359Sroberto#define DCFUA31_CFLAG MBG_CFLAG 49354359Sroberto#define DCFUA31_IFLAG MBG_IFLAG 49454359Sroberto#define DCFUA31_OFLAG MBG_OFLAG 49554359Sroberto#define DCFUA31_LFLAG MBG_LFLAG 49654359Sroberto#define DCFUA31_SAMPLES 5 49754359Sroberto#define DCFUA31_KEEP 3 49854359Sroberto#define DCFUA31_FORMAT "Meinberg Standard" 49954359Sroberto 50054359Sroberto/* 50154359Sroberto * Meinberg DCF PZF535/TCXO (FM/PZF) receiver 50254359Sroberto */ 50354359Sroberto#define DCFPZF535_ROOTDELAY 0.0 50454359Sroberto#define DCFPZF535_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 50554359Sroberto#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/509 / TCXO" 50654359Sroberto#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours 50754359Sroberto * @ 5e-8df/f we have accumulated 50854359Sroberto * at most 2.16 ms (thus we move to 50954359Sroberto * NTP synchronisation */ 51054359Sroberto#define DCFPZF535_SPEED MBG_SPEED 51154359Sroberto#define DCFPZF535_CFLAG MBG_CFLAG 51254359Sroberto#define DCFPZF535_IFLAG MBG_IFLAG 51354359Sroberto#define DCFPZF535_OFLAG MBG_OFLAG 51454359Sroberto#define DCFPZF535_LFLAG MBG_LFLAG 51554359Sroberto#define DCFPZF535_SAMPLES 5 51654359Sroberto#define DCFPZF535_KEEP 3 51754359Sroberto#define DCFPZF535_FORMAT "Meinberg Standard" 51854359Sroberto 51954359Sroberto/* 52054359Sroberto * Meinberg DCF PZF535/OCXO receiver 52154359Sroberto */ 52254359Sroberto#define DCFPZF535OCXO_ROOTDELAY 0.0 52354359Sroberto#define DCFPZF535OCXO_BASEDELAY 0.001968 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 52454359Sroberto#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/509 / OCXO" 52554359Sroberto#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 52654359Sroberto * @ 5e-9df/f we have accumulated 52754359Sroberto * at most an error of 1.73 ms 52854359Sroberto * (thus we move to NTP synchronisation) */ 52954359Sroberto#define DCFPZF535OCXO_SPEED MBG_SPEED 53054359Sroberto#define DCFPZF535OCXO_CFLAG MBG_CFLAG 53154359Sroberto#define DCFPZF535OCXO_IFLAG MBG_IFLAG 53254359Sroberto#define DCFPZF535OCXO_OFLAG MBG_OFLAG 53354359Sroberto#define DCFPZF535OCXO_LFLAG MBG_LFLAG 53454359Sroberto#define DCFPZF535OCXO_SAMPLES 5 53554359Sroberto#define DCFPZF535OCXO_KEEP 3 53654359Sroberto#define DCFPZF535OCXO_FORMAT "Meinberg Standard" 53754359Sroberto 53854359Sroberto/* 53954359Sroberto * Meinberg GPS16X receiver 54054359Sroberto */ 541280849Scystatic void gps16x_message (struct parseunit *, parsetime_t *); 542280849Scystatic int gps16x_poll_init (struct parseunit *); 54354359Sroberto 54454359Sroberto#define GPS16X_ROOTDELAY 0.0 /* nothing here */ 54554359Sroberto#define GPS16X_BASEDELAY 0.001968 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */ 54654359Sroberto#define GPS16X_DESCRIPTION "Meinberg GPS16x receiver" 54754359Sroberto#define GPS16X_MAXUNSYNC 60*60*96 /* only trust clock for 4 days 54854359Sroberto * @ 5e-9df/f we have accumulated 54954359Sroberto * at most an error of 1.73 ms 55054359Sroberto * (thus we move to NTP synchronisation) */ 55154359Sroberto#define GPS16X_SPEED B19200 55254359Sroberto#define GPS16X_CFLAG (CS8|CREAD|CLOCAL|HUPCL) 55354359Sroberto#define GPS16X_IFLAG (IGNBRK|IGNPAR) 55454359Sroberto#define GPS16X_OFLAG MBG_OFLAG 55554359Sroberto#define GPS16X_LFLAG MBG_LFLAG 55654359Sroberto#define GPS16X_POLLRATE 6 55754359Sroberto#define GPS16X_POLLCMD "" 55854359Sroberto#define GPS16X_CMDSIZE 0 55954359Sroberto 56054359Srobertostatic poll_info_t gps16x_pollinfo = { GPS16X_POLLRATE, GPS16X_POLLCMD, GPS16X_CMDSIZE }; 56154359Sroberto 56254359Sroberto#define GPS16X_INIT gps16x_poll_init 56354359Sroberto#define GPS16X_POLL 0 56454359Sroberto#define GPS16X_END 0 56554359Sroberto#define GPS16X_DATA ((void *)(&gps16x_pollinfo)) 56654359Sroberto#define GPS16X_MESSAGE gps16x_message 56754359Sroberto#define GPS16X_ID GPS_ID 56854359Sroberto#define GPS16X_FORMAT "Meinberg GPS Extended" 56954359Sroberto#define GPS16X_SAMPLES 5 57054359Sroberto#define GPS16X_KEEP 3 57154359Sroberto 57254359Sroberto/* 57354359Sroberto * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit) 57454359Sroberto * 57554359Sroberto * This is really not the hottest clock - but before you have nothing ... 57654359Sroberto */ 57754359Sroberto#define DCF7000_ROOTDELAY 0.0 /* 0 */ 57854359Sroberto#define DCF7000_BASEDELAY 0.405 /* slow blow */ 57954359Sroberto#define DCF7000_DESCRIPTION "ELV DCF7000" 58054359Sroberto#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */ 58154359Sroberto#define DCF7000_SPEED (B9600) 58254359Sroberto#define DCF7000_CFLAG (CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL) 58354359Sroberto#define DCF7000_IFLAG (IGNBRK) 58454359Sroberto#define DCF7000_OFLAG 0 58554359Sroberto#define DCF7000_LFLAG 0 58654359Sroberto#define DCF7000_SAMPLES 5 58754359Sroberto#define DCF7000_KEEP 3 58854359Sroberto#define DCF7000_FORMAT "ELV DCF7000" 58954359Sroberto 59054359Sroberto/* 59154359Sroberto * Schmid DCF Receiver Kit 59254359Sroberto * 59354359Sroberto * When the WSDCF clock is operating optimally we want the primary clock 59454359Sroberto * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer 59554359Sroberto * structure is set to 290 ms and we compute delays which are at least 59654359Sroberto * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format 59754359Sroberto */ 59854359Sroberto#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */ 59954359Sroberto#define WS_POLLCMD "\163" 60054359Sroberto#define WS_CMDSIZE 1 60154359Sroberto 60254359Srobertostatic poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE }; 60354359Sroberto 60454359Sroberto#define WSDCF_INIT poll_init 60554359Sroberto#define WSDCF_POLL poll_dpoll 60654359Sroberto#define WSDCF_END 0 60754359Sroberto#define WSDCF_DATA ((void *)(&wsdcf_pollinfo)) 60854359Sroberto#define WSDCF_ROOTDELAY 0.0 /* 0 */ 60954359Sroberto#define WSDCF_BASEDELAY 0.010 /* ~ 10ms */ 61054359Sroberto#define WSDCF_DESCRIPTION "WS/DCF Receiver" 61154359Sroberto#define WSDCF_FORMAT "Schmid" 61254359Sroberto#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */ 61354359Sroberto#define WSDCF_SPEED (B1200) 61454359Sroberto#define WSDCF_CFLAG (CS8|CREAD|CLOCAL) 61554359Sroberto#define WSDCF_IFLAG 0 61654359Sroberto#define WSDCF_OFLAG 0 61754359Sroberto#define WSDCF_LFLAG 0 61854359Sroberto#define WSDCF_SAMPLES 5 61954359Sroberto#define WSDCF_KEEP 3 62054359Sroberto 62154359Sroberto/* 62254359Sroberto * RAW DCF77 - input of DCF marks via RS232 - many variants 62354359Sroberto */ 62454359Sroberto#define RAWDCF_FLAGS 0 62554359Sroberto#define RAWDCF_ROOTDELAY 0.0 /* 0 */ 62654359Sroberto#define RAWDCF_BASEDELAY 0.258 62754359Sroberto#define RAWDCF_FORMAT "RAW DCF77 Timecode" 62854359Sroberto#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */ 62954359Sroberto#define RAWDCF_SPEED (B50) 63054359Sroberto#ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined(SYS_IRIX5) */ 63154359Sroberto/* somehow doesn't grok PARENB & IGNPAR (mj) */ 63254359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL) 63354359Sroberto#else 63454359Sroberto# define RAWDCF_CFLAG (CS8|CREAD|CLOCAL|PARENB) 63554359Sroberto#endif 63654359Sroberto#ifdef RAWDCF_NO_IGNPAR /* Was: defined(SYS_LINUX) && defined(CLOCK_RAWDCF) */ 63754359Sroberto# define RAWDCF_IFLAG 0 63854359Sroberto#else 63954359Sroberto# define RAWDCF_IFLAG (IGNPAR) 64054359Sroberto#endif 64154359Sroberto#define RAWDCF_OFLAG 0 64254359Sroberto#define RAWDCF_LFLAG 0 64354359Sroberto#define RAWDCF_SAMPLES 20 64454359Sroberto#define RAWDCF_KEEP 12 64554359Sroberto#define RAWDCF_INIT 0 64654359Sroberto 64754359Sroberto/* 64854359Sroberto * RAW DCF variants 64954359Sroberto */ 65054359Sroberto/* 65154359Sroberto * Conrad receiver 65254359Sroberto * 65354359Sroberto * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad 65454359Sroberto * (~40DM - roughly $30 ) followed by a level converter for RS232 65554359Sroberto */ 65654359Sroberto#define CONRAD_BASEDELAY 0.292 /* Conrad receiver @ 50 Baud on a Sun */ 65754359Sroberto#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)" 65854359Sroberto 659182007Sroberto/* Gude Analog- und Digitalsystem GmbH 'Expert mouseCLOCK USB v2.0' */ 660182007Sroberto#define GUDE_EMC_USB_V20_SPEED (B4800) 661182007Sroberto#define GUDE_EMC_USB_V20_BASEDELAY 0.425 /* USB serial<->USB converter FTDI232R */ 662182007Sroberto#define GUDE_EMC_USB_V20_DESCRIPTION "RAW DCF77 CODE (Expert mouseCLOCK USB v2.0)" 663182007Sroberto 66454359Sroberto/* 66554359Sroberto * TimeBrick receiver 66654359Sroberto */ 66754359Sroberto#define TIMEBRICK_BASEDELAY 0.210 /* TimeBrick @ 50 Baud on a Sun */ 66854359Sroberto#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)" 66954359Sroberto 67054359Sroberto/* 67154359Sroberto * IGEL:clock receiver 67254359Sroberto */ 67354359Sroberto#define IGELCLOCK_BASEDELAY 0.258 /* IGEL:clock receiver */ 67454359Sroberto#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)" 67554359Sroberto#define IGELCLOCK_SPEED (B1200) 67654359Sroberto#define IGELCLOCK_CFLAG (CS8|CREAD|HUPCL|CLOCAL) 67754359Sroberto 67854359Sroberto/* 67954359Sroberto * RAWDCF receivers that need to be powered from DTR 68054359Sroberto * (like Expert mouse clock) 68154359Sroberto */ 682280849Scystatic int rawdcf_init_1 (struct parseunit *); 68356746Sroberto#define RAWDCFDTRSET_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR)" 684280849Scy#define RAWDCFDTRSET75_DESCRIPTION "RAW DCF77 CODE (DTR SET/RTS CLR @ 75 baud)" 68556746Sroberto#define RAWDCFDTRSET_INIT rawdcf_init_1 68654359Sroberto 68754359Sroberto/* 68856746Sroberto * RAWDCF receivers that need to be powered from 68956746Sroberto * DTR CLR and RTS SET 69054359Sroberto */ 691280849Scystatic int rawdcf_init_2 (struct parseunit *); 69256746Sroberto#define RAWDCFDTRCLRRTSSET_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET)" 693280849Scy#define RAWDCFDTRCLRRTSSET75_DESCRIPTION "RAW DCF77 CODE (DTR CLR/RTS SET @ 75 baud)" 69456746Sroberto#define RAWDCFDTRCLRRTSSET_INIT rawdcf_init_2 69554359Sroberto 69654359Sroberto/* 69754359Sroberto * Trimble GPS receivers (TAIP and TSIP protocols) 69854359Sroberto */ 69954359Sroberto#ifndef TRIM_POLLRATE 70054359Sroberto#define TRIM_POLLRATE 0 /* only true direct polling */ 70154359Sroberto#endif 70254359Sroberto 70354359Sroberto#define TRIM_TAIPPOLLCMD ">SRM;FR_FLAG=F;EC_FLAG=F<>QTM<" 70454359Sroberto#define TRIM_TAIPCMDSIZE (sizeof(TRIM_TAIPPOLLCMD)-1) 70554359Sroberto 70654359Srobertostatic poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE }; 707280849Scystatic int trimbletaip_init (struct parseunit *); 708280849Scystatic void trimbletaip_event (struct parseunit *, int); 70954359Sroberto 71054359Sroberto/* query time & UTC correction data */ 71154359Srobertostatic char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX }; 71254359Sroberto 71354359Srobertostatic poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) }; 714280849Scystatic int trimbletsip_init (struct parseunit *); 715280849Scystatic void trimbletsip_end (struct parseunit *); 716280849Scystatic void trimbletsip_message (struct parseunit *, parsetime_t *); 717280849Scystatic void trimbletsip_event (struct parseunit *, int); 71854359Sroberto 71954359Sroberto#define TRIMBLETSIP_IDLE_TIME (300) /* 5 minutes silence at most */ 720182007Sroberto#define TRIMBLE_RESET_HOLDOFF TRIMBLETSIP_IDLE_TIME 72154359Sroberto 72254359Sroberto#define TRIMBLETAIP_SPEED (B4800) 72354359Sroberto#define TRIMBLETAIP_CFLAG (CS8|CREAD|CLOCAL) 72454359Sroberto#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON) 72554359Sroberto#define TRIMBLETAIP_OFLAG (OPOST|ONLCR) 72654359Sroberto#define TRIMBLETAIP_LFLAG (0) 72754359Sroberto 72854359Sroberto#define TRIMBLETSIP_SPEED (B9600) 72954359Sroberto#define TRIMBLETSIP_CFLAG (CS8|CLOCAL|CREAD|PARENB|PARODD) 73054359Sroberto#define TRIMBLETSIP_IFLAG (IGNBRK) 73154359Sroberto#define TRIMBLETSIP_OFLAG (0) 73254359Sroberto#define TRIMBLETSIP_LFLAG (ICANON) 73354359Sroberto 73454359Sroberto#define TRIMBLETSIP_SAMPLES 5 73554359Sroberto#define TRIMBLETSIP_KEEP 3 73654359Sroberto#define TRIMBLETAIP_SAMPLES 5 73754359Sroberto#define TRIMBLETAIP_KEEP 3 73854359Sroberto 73954359Sroberto#define TRIMBLETAIP_FLAGS (PARSE_F_PPSONSECOND) 74054359Sroberto#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS) 74154359Sroberto 74254359Sroberto#define TRIMBLETAIP_POLL poll_dpoll 74354359Sroberto#define TRIMBLETSIP_POLL poll_dpoll 74454359Sroberto 74554359Sroberto#define TRIMBLETAIP_INIT trimbletaip_init 74654359Sroberto#define TRIMBLETSIP_INIT trimbletsip_init 74754359Sroberto 74854359Sroberto#define TRIMBLETAIP_EVENT trimbletaip_event 74954359Sroberto 75054359Sroberto#define TRIMBLETSIP_EVENT trimbletsip_event 75154359Sroberto#define TRIMBLETSIP_MESSAGE trimbletsip_message 75254359Sroberto 75354359Sroberto#define TRIMBLETAIP_END 0 75454359Sroberto#define TRIMBLETSIP_END trimbletsip_end 75554359Sroberto 75654359Sroberto#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo)) 75754359Sroberto#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo)) 75854359Sroberto 75954359Sroberto#define TRIMBLETAIP_ID GPS_ID 76054359Sroberto#define TRIMBLETSIP_ID GPS_ID 76154359Sroberto 76254359Sroberto#define TRIMBLETAIP_FORMAT "Trimble TAIP" 76354359Sroberto#define TRIMBLETSIP_FORMAT "Trimble TSIP" 76454359Sroberto 76554359Sroberto#define TRIMBLETAIP_ROOTDELAY 0x0 76654359Sroberto#define TRIMBLETSIP_ROOTDELAY 0x0 76754359Sroberto 76854359Sroberto#define TRIMBLETAIP_BASEDELAY 0.0 76954359Sroberto#define TRIMBLETSIP_BASEDELAY 0.020 /* GPS time message latency */ 77054359Sroberto 77154359Sroberto#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver" 77254359Sroberto#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver" 77354359Sroberto 77454359Sroberto#define TRIMBLETAIP_MAXUNSYNC 0 77554359Sroberto#define TRIMBLETSIP_MAXUNSYNC 0 77654359Sroberto 77754359Sroberto#define TRIMBLETAIP_EOL '<' 77854359Sroberto 77954359Sroberto/* 78054359Sroberto * RadioCode Clocks RCC 800 receiver 78154359Sroberto */ 78254359Sroberto#define RCC_POLLRATE 0 /* only true direct polling */ 78354359Sroberto#define RCC_POLLCMD "\r" 78454359Sroberto#define RCC_CMDSIZE 1 78554359Sroberto 78654359Srobertostatic poll_info_t rcc8000_pollinfo = { RCC_POLLRATE, RCC_POLLCMD, RCC_CMDSIZE }; 78754359Sroberto#define RCC8000_FLAGS 0 78854359Sroberto#define RCC8000_POLL poll_dpoll 78954359Sroberto#define RCC8000_INIT poll_init 79054359Sroberto#define RCC8000_END 0 79154359Sroberto#define RCC8000_DATA ((void *)(&rcc8000_pollinfo)) 79254359Sroberto#define RCC8000_ROOTDELAY 0.0 79354359Sroberto#define RCC8000_BASEDELAY 0.0 79454359Sroberto#define RCC8000_ID "MSF" 79554359Sroberto#define RCC8000_DESCRIPTION "RCC 8000 MSF Receiver" 79654359Sroberto#define RCC8000_FORMAT "Radiocode RCC8000" 79754359Sroberto#define RCC8000_MAXUNSYNC (60*60) /* should be ok for an hour */ 79854359Sroberto#define RCC8000_SPEED (B2400) 79954359Sroberto#define RCC8000_CFLAG (CS8|CREAD|CLOCAL) 80054359Sroberto#define RCC8000_IFLAG (IGNBRK|IGNPAR) 80154359Sroberto#define RCC8000_OFLAG 0 80254359Sroberto#define RCC8000_LFLAG 0 80354359Sroberto#define RCC8000_SAMPLES 5 80454359Sroberto#define RCC8000_KEEP 3 80554359Sroberto 80654359Sroberto/* 80754359Sroberto * Hopf Radio clock 6021 Format 80854359Sroberto * 80954359Sroberto */ 81054359Sroberto#define HOPF6021_ROOTDELAY 0.0 81154359Sroberto#define HOPF6021_BASEDELAY 0.0 81254359Sroberto#define HOPF6021_DESCRIPTION "HOPF 6021" 81354359Sroberto#define HOPF6021_FORMAT "hopf Funkuhr 6021" 81454359Sroberto#define HOPF6021_MAXUNSYNC (60*60) /* should be ok for an hour */ 81554359Sroberto#define HOPF6021_SPEED (B9600) 81654359Sroberto#define HOPF6021_CFLAG (CS8|CREAD|CLOCAL) 81754359Sroberto#define HOPF6021_IFLAG (IGNBRK|ISTRIP) 81854359Sroberto#define HOPF6021_OFLAG 0 81954359Sroberto#define HOPF6021_LFLAG 0 82054359Sroberto#define HOPF6021_FLAGS 0 82154359Sroberto#define HOPF6021_SAMPLES 5 82254359Sroberto#define HOPF6021_KEEP 3 82354359Sroberto 82454359Sroberto/* 82554359Sroberto * Diem's Computime Radio Clock Receiver 82654359Sroberto */ 82754359Sroberto#define COMPUTIME_FLAGS 0 82854359Sroberto#define COMPUTIME_ROOTDELAY 0.0 82954359Sroberto#define COMPUTIME_BASEDELAY 0.0 83054359Sroberto#define COMPUTIME_ID DCF_ID 83154359Sroberto#define COMPUTIME_DESCRIPTION "Diem's Computime receiver" 83254359Sroberto#define COMPUTIME_FORMAT "Diem's Computime Radio Clock" 83354359Sroberto#define COMPUTIME_TYPE DCF_TYPE 83454359Sroberto#define COMPUTIME_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 83554359Sroberto#define COMPUTIME_SPEED (B9600) 83654359Sroberto#define COMPUTIME_CFLAG (CSTOPB|CS7|CREAD|CLOCAL) 83754359Sroberto#define COMPUTIME_IFLAG (IGNBRK|IGNPAR|ISTRIP) 83854359Sroberto#define COMPUTIME_OFLAG 0 83954359Sroberto#define COMPUTIME_LFLAG 0 84054359Sroberto#define COMPUTIME_SAMPLES 5 84154359Sroberto#define COMPUTIME_KEEP 3 84254359Sroberto 84354359Sroberto/* 84454359Sroberto * Varitext Radio Clock Receiver 84554359Sroberto */ 84654359Sroberto#define VARITEXT_FLAGS 0 84754359Sroberto#define VARITEXT_ROOTDELAY 0.0 84854359Sroberto#define VARITEXT_BASEDELAY 0.0 84954359Sroberto#define VARITEXT_ID "MSF" 85054359Sroberto#define VARITEXT_DESCRIPTION "Varitext receiver" 85154359Sroberto#define VARITEXT_FORMAT "Varitext Radio Clock" 85254359Sroberto#define VARITEXT_TYPE DCF_TYPE 85354359Sroberto#define VARITEXT_MAXUNSYNC (60*60) /* only trust clock for 1 hour */ 85454359Sroberto#define VARITEXT_SPEED (B9600) 85554359Sroberto#define VARITEXT_CFLAG (CS7|CREAD|CLOCAL|PARENB|PARODD) 85654359Sroberto#define VARITEXT_IFLAG (IGNPAR|IGNBRK|INPCK) /*|ISTRIP)*/ 85754359Sroberto#define VARITEXT_OFLAG 0 85854359Sroberto#define VARITEXT_LFLAG 0 85954359Sroberto#define VARITEXT_SAMPLES 32 86054359Sroberto#define VARITEXT_KEEP 20 86154359Sroberto 862280849Scy/* 863280849Scy * SEL240x Satellite Sychronized Clock 864280849Scy */ 865280849Scy#define SEL240X_POLLRATE 0 /* only true direct polling */ 866280849Scy#define SEL240X_POLLCMD "BUB8" 867280849Scy#define SEL240X_CMDSIZE 4 868280849Scy 869280849Scystatic poll_info_t sel240x_pollinfo = { SEL240X_POLLRATE, 870280849Scy SEL240X_POLLCMD, 871280849Scy SEL240X_CMDSIZE }; 872280849Scy#define SEL240X_FLAGS (PARSE_F_PPSONSECOND) 873280849Scy#define SEL240X_POLL poll_dpoll 874280849Scy#define SEL240X_INIT poll_init 875280849Scy#define SEL240X_END 0 876280849Scy#define SEL240X_DATA ((void *)(&sel240x_pollinfo)) 877280849Scy#define SEL240X_ROOTDELAY 0.0 878280849Scy#define SEL240X_BASEDELAY 0.0 879280849Scy#define SEL240X_ID GPS_ID 880280849Scy#define SEL240X_DESCRIPTION "SEL240x Satellite Synchronized Clock" 881280849Scy#define SEL240X_FORMAT "SEL B8" 882280849Scy#define SEL240X_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours */ 883280849Scy#define SEL240X_SPEED (B9600) 884280849Scy#define SEL240X_CFLAG (CS8|CREAD|CLOCAL) 885280849Scy#define SEL240X_IFLAG (IGNBRK|IGNPAR) 886280849Scy#define SEL240X_OFLAG (0) 887280849Scy#define SEL240X_LFLAG (0) 888280849Scy#define SEL240X_SAMPLES 5 889280849Scy#define SEL240X_KEEP 3 890280849Scy 89154359Srobertostatic struct parse_clockinfo 89254359Sroberto{ 893280849Scy u_long cl_flags; /* operation flags (PPS interpretation, trust handling) */ 894280849Scy void (*cl_poll) (struct parseunit *); /* active poll routine */ 895280849Scy int (*cl_init) (struct parseunit *); /* active poll init routine */ 896280849Scy void (*cl_event) (struct parseunit *, int); /* special event handling (e.g. reset clock) */ 897280849Scy void (*cl_end) (struct parseunit *); /* active poll end routine */ 898280849Scy void (*cl_message) (struct parseunit *, parsetime_t *); /* process a lower layer message */ 89954359Sroberto void *cl_data; /* local data area for "poll" mechanism */ 90054359Sroberto double cl_rootdelay; /* rootdelay */ 90154359Sroberto double cl_basedelay; /* current offset by which the RS232 90254359Sroberto time code is delayed from the actual time */ 90354359Sroberto const char *cl_id; /* ID code */ 90454359Sroberto const char *cl_description; /* device name */ 90554359Sroberto const char *cl_format; /* fixed format */ 90654359Sroberto u_char cl_type; /* clock type (ntp control) */ 907132451Sroberto u_long cl_maxunsync; /* time to trust oscillator after losing synch */ 90854359Sroberto u_long cl_speed; /* terminal input & output baudrate */ 90954359Sroberto u_long cl_cflag; /* terminal control flags */ 91054359Sroberto u_long cl_iflag; /* terminal input flags */ 91154359Sroberto u_long cl_oflag; /* terminal output flags */ 91254359Sroberto u_long cl_lflag; /* terminal local flags */ 91354359Sroberto u_long cl_samples; /* samples for median filter */ 91454359Sroberto u_long cl_keep; /* samples for median filter to keep */ 91554359Sroberto} parse_clockinfo[] = 91654359Sroberto{ 91754359Sroberto { /* mode 0 */ 91854359Sroberto MBG_FLAGS, 91954359Sroberto NO_POLL, 92054359Sroberto NO_INIT, 92154359Sroberto NO_EVENT, 92254359Sroberto NO_END, 92354359Sroberto NO_MESSAGE, 924182007Sroberto NO_LCLDATA, 92554359Sroberto DCFPZF535_ROOTDELAY, 92654359Sroberto DCFPZF535_BASEDELAY, 92754359Sroberto DCF_P_ID, 92854359Sroberto DCFPZF535_DESCRIPTION, 92954359Sroberto DCFPZF535_FORMAT, 93054359Sroberto DCF_TYPE, 93154359Sroberto DCFPZF535_MAXUNSYNC, 93254359Sroberto DCFPZF535_SPEED, 93354359Sroberto DCFPZF535_CFLAG, 93454359Sroberto DCFPZF535_IFLAG, 93554359Sroberto DCFPZF535_OFLAG, 93654359Sroberto DCFPZF535_LFLAG, 93754359Sroberto DCFPZF535_SAMPLES, 93854359Sroberto DCFPZF535_KEEP 93954359Sroberto }, 94054359Sroberto { /* mode 1 */ 94154359Sroberto MBG_FLAGS, 94254359Sroberto NO_POLL, 94354359Sroberto NO_INIT, 94454359Sroberto NO_EVENT, 94554359Sroberto NO_END, 94654359Sroberto NO_MESSAGE, 947182007Sroberto NO_LCLDATA, 94854359Sroberto DCFPZF535OCXO_ROOTDELAY, 94954359Sroberto DCFPZF535OCXO_BASEDELAY, 95054359Sroberto DCF_P_ID, 95154359Sroberto DCFPZF535OCXO_DESCRIPTION, 95254359Sroberto DCFPZF535OCXO_FORMAT, 95354359Sroberto DCF_TYPE, 95454359Sroberto DCFPZF535OCXO_MAXUNSYNC, 95554359Sroberto DCFPZF535OCXO_SPEED, 95654359Sroberto DCFPZF535OCXO_CFLAG, 95754359Sroberto DCFPZF535OCXO_IFLAG, 95854359Sroberto DCFPZF535OCXO_OFLAG, 95954359Sroberto DCFPZF535OCXO_LFLAG, 96054359Sroberto DCFPZF535OCXO_SAMPLES, 96154359Sroberto DCFPZF535OCXO_KEEP 96254359Sroberto }, 96354359Sroberto { /* mode 2 */ 96454359Sroberto MBG_FLAGS, 96554359Sroberto NO_POLL, 96654359Sroberto NO_INIT, 96754359Sroberto NO_EVENT, 96854359Sroberto NO_END, 96954359Sroberto NO_MESSAGE, 970182007Sroberto NO_LCLDATA, 97154359Sroberto DCFUA31_ROOTDELAY, 97254359Sroberto DCFUA31_BASEDELAY, 97354359Sroberto DCF_A_ID, 97454359Sroberto DCFUA31_DESCRIPTION, 97554359Sroberto DCFUA31_FORMAT, 97654359Sroberto DCF_TYPE, 97754359Sroberto DCFUA31_MAXUNSYNC, 97854359Sroberto DCFUA31_SPEED, 97954359Sroberto DCFUA31_CFLAG, 98054359Sroberto DCFUA31_IFLAG, 98154359Sroberto DCFUA31_OFLAG, 98254359Sroberto DCFUA31_LFLAG, 98354359Sroberto DCFUA31_SAMPLES, 98454359Sroberto DCFUA31_KEEP 98554359Sroberto }, 98654359Sroberto { /* mode 3 */ 98754359Sroberto MBG_FLAGS, 98854359Sroberto NO_POLL, 98954359Sroberto NO_INIT, 99054359Sroberto NO_EVENT, 99154359Sroberto NO_END, 99254359Sroberto NO_MESSAGE, 993182007Sroberto NO_LCLDATA, 99454359Sroberto DCF7000_ROOTDELAY, 99554359Sroberto DCF7000_BASEDELAY, 99654359Sroberto DCF_A_ID, 99754359Sroberto DCF7000_DESCRIPTION, 99854359Sroberto DCF7000_FORMAT, 99954359Sroberto DCF_TYPE, 100054359Sroberto DCF7000_MAXUNSYNC, 100154359Sroberto DCF7000_SPEED, 100254359Sroberto DCF7000_CFLAG, 100354359Sroberto DCF7000_IFLAG, 100454359Sroberto DCF7000_OFLAG, 100554359Sroberto DCF7000_LFLAG, 100654359Sroberto DCF7000_SAMPLES, 100754359Sroberto DCF7000_KEEP 100854359Sroberto }, 100954359Sroberto { /* mode 4 */ 101054359Sroberto NO_CL_FLAGS, 101154359Sroberto WSDCF_POLL, 101254359Sroberto WSDCF_INIT, 101354359Sroberto NO_EVENT, 101454359Sroberto WSDCF_END, 101554359Sroberto NO_MESSAGE, 101654359Sroberto WSDCF_DATA, 101754359Sroberto WSDCF_ROOTDELAY, 101854359Sroberto WSDCF_BASEDELAY, 101954359Sroberto DCF_A_ID, 102054359Sroberto WSDCF_DESCRIPTION, 102154359Sroberto WSDCF_FORMAT, 102254359Sroberto DCF_TYPE, 102354359Sroberto WSDCF_MAXUNSYNC, 102454359Sroberto WSDCF_SPEED, 102554359Sroberto WSDCF_CFLAG, 102654359Sroberto WSDCF_IFLAG, 102754359Sroberto WSDCF_OFLAG, 102854359Sroberto WSDCF_LFLAG, 102954359Sroberto WSDCF_SAMPLES, 103054359Sroberto WSDCF_KEEP 103154359Sroberto }, 103254359Sroberto { /* mode 5 */ 103354359Sroberto RAWDCF_FLAGS, 103454359Sroberto NO_POLL, 103554359Sroberto RAWDCF_INIT, 103654359Sroberto NO_EVENT, 103754359Sroberto NO_END, 103854359Sroberto NO_MESSAGE, 1039182007Sroberto NO_LCLDATA, 104054359Sroberto RAWDCF_ROOTDELAY, 104154359Sroberto CONRAD_BASEDELAY, 104254359Sroberto DCF_A_ID, 104354359Sroberto CONRAD_DESCRIPTION, 104454359Sroberto RAWDCF_FORMAT, 104554359Sroberto DCF_TYPE, 104654359Sroberto RAWDCF_MAXUNSYNC, 104754359Sroberto RAWDCF_SPEED, 104854359Sroberto RAWDCF_CFLAG, 104954359Sroberto RAWDCF_IFLAG, 105054359Sroberto RAWDCF_OFLAG, 105154359Sroberto RAWDCF_LFLAG, 105254359Sroberto RAWDCF_SAMPLES, 105354359Sroberto RAWDCF_KEEP 105454359Sroberto }, 105554359Sroberto { /* mode 6 */ 105654359Sroberto RAWDCF_FLAGS, 105754359Sroberto NO_POLL, 105854359Sroberto RAWDCF_INIT, 105954359Sroberto NO_EVENT, 106054359Sroberto NO_END, 106154359Sroberto NO_MESSAGE, 1062182007Sroberto NO_LCLDATA, 106354359Sroberto RAWDCF_ROOTDELAY, 106454359Sroberto TIMEBRICK_BASEDELAY, 106554359Sroberto DCF_A_ID, 106654359Sroberto TIMEBRICK_DESCRIPTION, 106754359Sroberto RAWDCF_FORMAT, 106854359Sroberto DCF_TYPE, 106954359Sroberto RAWDCF_MAXUNSYNC, 107054359Sroberto RAWDCF_SPEED, 107154359Sroberto RAWDCF_CFLAG, 107254359Sroberto RAWDCF_IFLAG, 107354359Sroberto RAWDCF_OFLAG, 107454359Sroberto RAWDCF_LFLAG, 107554359Sroberto RAWDCF_SAMPLES, 107654359Sroberto RAWDCF_KEEP 107754359Sroberto }, 107854359Sroberto { /* mode 7 */ 107954359Sroberto MBG_FLAGS, 108054359Sroberto GPS16X_POLL, 108154359Sroberto GPS16X_INIT, 108254359Sroberto NO_EVENT, 108354359Sroberto GPS16X_END, 108454359Sroberto GPS16X_MESSAGE, 108554359Sroberto GPS16X_DATA, 108654359Sroberto GPS16X_ROOTDELAY, 108754359Sroberto GPS16X_BASEDELAY, 108854359Sroberto GPS16X_ID, 108954359Sroberto GPS16X_DESCRIPTION, 109054359Sroberto GPS16X_FORMAT, 109154359Sroberto GPS_TYPE, 109254359Sroberto GPS16X_MAXUNSYNC, 109354359Sroberto GPS16X_SPEED, 109454359Sroberto GPS16X_CFLAG, 109554359Sroberto GPS16X_IFLAG, 109654359Sroberto GPS16X_OFLAG, 109754359Sroberto GPS16X_LFLAG, 109854359Sroberto GPS16X_SAMPLES, 109954359Sroberto GPS16X_KEEP 110054359Sroberto }, 110154359Sroberto { /* mode 8 */ 110254359Sroberto RAWDCF_FLAGS, 110354359Sroberto NO_POLL, 110454359Sroberto NO_INIT, 110554359Sroberto NO_EVENT, 110654359Sroberto NO_END, 110754359Sroberto NO_MESSAGE, 1108182007Sroberto NO_LCLDATA, 110954359Sroberto RAWDCF_ROOTDELAY, 111054359Sroberto IGELCLOCK_BASEDELAY, 111154359Sroberto DCF_A_ID, 111254359Sroberto IGELCLOCK_DESCRIPTION, 111354359Sroberto RAWDCF_FORMAT, 111454359Sroberto DCF_TYPE, 111554359Sroberto RAWDCF_MAXUNSYNC, 111654359Sroberto IGELCLOCK_SPEED, 111754359Sroberto IGELCLOCK_CFLAG, 111854359Sroberto RAWDCF_IFLAG, 111954359Sroberto RAWDCF_OFLAG, 112054359Sroberto RAWDCF_LFLAG, 112154359Sroberto RAWDCF_SAMPLES, 112254359Sroberto RAWDCF_KEEP 112354359Sroberto }, 112454359Sroberto { /* mode 9 */ 112554359Sroberto TRIMBLETAIP_FLAGS, 112654359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 112754359Sroberto NO_POLL, 112854359Sroberto#else 112954359Sroberto TRIMBLETAIP_POLL, 113054359Sroberto#endif 113154359Sroberto TRIMBLETAIP_INIT, 113254359Sroberto TRIMBLETAIP_EVENT, 113354359Sroberto TRIMBLETAIP_END, 113454359Sroberto NO_MESSAGE, 113554359Sroberto TRIMBLETAIP_DATA, 113654359Sroberto TRIMBLETAIP_ROOTDELAY, 113754359Sroberto TRIMBLETAIP_BASEDELAY, 113854359Sroberto TRIMBLETAIP_ID, 113954359Sroberto TRIMBLETAIP_DESCRIPTION, 114054359Sroberto TRIMBLETAIP_FORMAT, 114154359Sroberto GPS_TYPE, 114254359Sroberto TRIMBLETAIP_MAXUNSYNC, 114354359Sroberto TRIMBLETAIP_SPEED, 114454359Sroberto TRIMBLETAIP_CFLAG, 114554359Sroberto TRIMBLETAIP_IFLAG, 114654359Sroberto TRIMBLETAIP_OFLAG, 114754359Sroberto TRIMBLETAIP_LFLAG, 114854359Sroberto TRIMBLETAIP_SAMPLES, 114954359Sroberto TRIMBLETAIP_KEEP 115054359Sroberto }, 115154359Sroberto { /* mode 10 */ 115254359Sroberto TRIMBLETSIP_FLAGS, 115354359Sroberto#if TRIM_POLLRATE /* DHD940515: Allow user config */ 115454359Sroberto NO_POLL, 115554359Sroberto#else 115654359Sroberto TRIMBLETSIP_POLL, 115754359Sroberto#endif 115854359Sroberto TRIMBLETSIP_INIT, 115954359Sroberto TRIMBLETSIP_EVENT, 116054359Sroberto TRIMBLETSIP_END, 116154359Sroberto TRIMBLETSIP_MESSAGE, 116254359Sroberto TRIMBLETSIP_DATA, 116354359Sroberto TRIMBLETSIP_ROOTDELAY, 116454359Sroberto TRIMBLETSIP_BASEDELAY, 116554359Sroberto TRIMBLETSIP_ID, 116654359Sroberto TRIMBLETSIP_DESCRIPTION, 116754359Sroberto TRIMBLETSIP_FORMAT, 116854359Sroberto GPS_TYPE, 116954359Sroberto TRIMBLETSIP_MAXUNSYNC, 117054359Sroberto TRIMBLETSIP_SPEED, 117154359Sroberto TRIMBLETSIP_CFLAG, 117254359Sroberto TRIMBLETSIP_IFLAG, 117354359Sroberto TRIMBLETSIP_OFLAG, 117454359Sroberto TRIMBLETSIP_LFLAG, 117554359Sroberto TRIMBLETSIP_SAMPLES, 117654359Sroberto TRIMBLETSIP_KEEP 117754359Sroberto }, 117854359Sroberto { /* mode 11 */ 117954359Sroberto NO_CL_FLAGS, 118054359Sroberto RCC8000_POLL, 118154359Sroberto RCC8000_INIT, 118254359Sroberto NO_EVENT, 118354359Sroberto RCC8000_END, 118454359Sroberto NO_MESSAGE, 118554359Sroberto RCC8000_DATA, 118654359Sroberto RCC8000_ROOTDELAY, 118754359Sroberto RCC8000_BASEDELAY, 118854359Sroberto RCC8000_ID, 118954359Sroberto RCC8000_DESCRIPTION, 119054359Sroberto RCC8000_FORMAT, 119154359Sroberto DCF_TYPE, 119254359Sroberto RCC8000_MAXUNSYNC, 119354359Sroberto RCC8000_SPEED, 119454359Sroberto RCC8000_CFLAG, 119554359Sroberto RCC8000_IFLAG, 119654359Sroberto RCC8000_OFLAG, 119754359Sroberto RCC8000_LFLAG, 119854359Sroberto RCC8000_SAMPLES, 119954359Sroberto RCC8000_KEEP 120054359Sroberto }, 120154359Sroberto { /* mode 12 */ 120254359Sroberto HOPF6021_FLAGS, 120354359Sroberto NO_POLL, 120454359Sroberto NO_INIT, 120554359Sroberto NO_EVENT, 120654359Sroberto NO_END, 120754359Sroberto NO_MESSAGE, 1208182007Sroberto NO_LCLDATA, 120954359Sroberto HOPF6021_ROOTDELAY, 121054359Sroberto HOPF6021_BASEDELAY, 121154359Sroberto DCF_ID, 121254359Sroberto HOPF6021_DESCRIPTION, 121354359Sroberto HOPF6021_FORMAT, 121454359Sroberto DCF_TYPE, 121554359Sroberto HOPF6021_MAXUNSYNC, 121654359Sroberto HOPF6021_SPEED, 121754359Sroberto HOPF6021_CFLAG, 121854359Sroberto HOPF6021_IFLAG, 121954359Sroberto HOPF6021_OFLAG, 122054359Sroberto HOPF6021_LFLAG, 122154359Sroberto HOPF6021_SAMPLES, 122254359Sroberto HOPF6021_KEEP 122354359Sroberto }, 122454359Sroberto { /* mode 13 */ 122554359Sroberto COMPUTIME_FLAGS, 122654359Sroberto NO_POLL, 122754359Sroberto NO_INIT, 122854359Sroberto NO_EVENT, 122954359Sroberto NO_END, 123054359Sroberto NO_MESSAGE, 1231182007Sroberto NO_LCLDATA, 123254359Sroberto COMPUTIME_ROOTDELAY, 123354359Sroberto COMPUTIME_BASEDELAY, 123454359Sroberto COMPUTIME_ID, 123554359Sroberto COMPUTIME_DESCRIPTION, 123654359Sroberto COMPUTIME_FORMAT, 123754359Sroberto COMPUTIME_TYPE, 123854359Sroberto COMPUTIME_MAXUNSYNC, 123954359Sroberto COMPUTIME_SPEED, 124054359Sroberto COMPUTIME_CFLAG, 124154359Sroberto COMPUTIME_IFLAG, 124254359Sroberto COMPUTIME_OFLAG, 124354359Sroberto COMPUTIME_LFLAG, 124454359Sroberto COMPUTIME_SAMPLES, 124554359Sroberto COMPUTIME_KEEP 124654359Sroberto }, 124754359Sroberto { /* mode 14 */ 124854359Sroberto RAWDCF_FLAGS, 124954359Sroberto NO_POLL, 125056746Sroberto RAWDCFDTRSET_INIT, 125154359Sroberto NO_EVENT, 125254359Sroberto NO_END, 125354359Sroberto NO_MESSAGE, 1254182007Sroberto NO_LCLDATA, 125554359Sroberto RAWDCF_ROOTDELAY, 125654359Sroberto RAWDCF_BASEDELAY, 125754359Sroberto DCF_A_ID, 125856746Sroberto RAWDCFDTRSET_DESCRIPTION, 125954359Sroberto RAWDCF_FORMAT, 126054359Sroberto DCF_TYPE, 126154359Sroberto RAWDCF_MAXUNSYNC, 126254359Sroberto RAWDCF_SPEED, 126354359Sroberto RAWDCF_CFLAG, 126454359Sroberto RAWDCF_IFLAG, 126554359Sroberto RAWDCF_OFLAG, 126654359Sroberto RAWDCF_LFLAG, 126754359Sroberto RAWDCF_SAMPLES, 126854359Sroberto RAWDCF_KEEP 126954359Sroberto }, 127054359Sroberto { /* mode 15 */ 127156746Sroberto 0, /* operation flags (io modes) */ 127282498Sroberto NO_POLL, /* active poll routine */ 127382498Sroberto NO_INIT, /* active poll init routine */ 127456746Sroberto NO_EVENT, /* special event handling (e.g. reset clock) */ 127556746Sroberto NO_END, /* active poll end routine */ 127656746Sroberto NO_MESSAGE, /* process a lower layer message */ 1277182007Sroberto NO_LCLDATA, /* local data area for "poll" mechanism */ 127856746Sroberto 0, /* rootdelay */ 127982498Sroberto 11.0 /* bits */ / 9600, /* current offset by which the RS232 128056746Sroberto time code is delayed from the actual time */ 128156746Sroberto DCF_ID, /* ID code */ 128256746Sroberto "WHARTON 400A Series clock", /* device name */ 128382498Sroberto "WHARTON 400A Series clock Output Format 1", /* fixed format */ 128456746Sroberto /* Must match a format-name in a libparse/clk_xxx.c file */ 128556746Sroberto DCF_TYPE, /* clock type (ntp control) */ 1286132451Sroberto (1*60*60), /* time to trust oscillator after losing synch */ 128756746Sroberto B9600, /* terminal input & output baudrate */ 128856746Sroberto (CS8|CREAD|PARENB|CLOCAL|HUPCL),/* terminal control flags */ 128956746Sroberto 0, /* terminal input flags */ 129056746Sroberto 0, /* terminal output flags */ 129156746Sroberto 0, /* terminal local flags */ 129256746Sroberto 5, /* samples for median filter */ 129356746Sroberto 3, /* samples for median filter to keep */ 129454359Sroberto }, 129556746Sroberto { /* mode 16 - RAWDCF RTS set, DTR clr */ 129656746Sroberto RAWDCF_FLAGS, 129756746Sroberto NO_POLL, 129856746Sroberto RAWDCFDTRCLRRTSSET_INIT, 129956746Sroberto NO_EVENT, 130056746Sroberto NO_END, 130156746Sroberto NO_MESSAGE, 1302182007Sroberto NO_LCLDATA, 130356746Sroberto RAWDCF_ROOTDELAY, 130456746Sroberto RAWDCF_BASEDELAY, 130556746Sroberto DCF_A_ID, 130656746Sroberto RAWDCFDTRCLRRTSSET_DESCRIPTION, 130756746Sroberto RAWDCF_FORMAT, 130856746Sroberto DCF_TYPE, 130956746Sroberto RAWDCF_MAXUNSYNC, 131056746Sroberto RAWDCF_SPEED, 131156746Sroberto RAWDCF_CFLAG, 131256746Sroberto RAWDCF_IFLAG, 131356746Sroberto RAWDCF_OFLAG, 131456746Sroberto RAWDCF_LFLAG, 131556746Sroberto RAWDCF_SAMPLES, 131656746Sroberto RAWDCF_KEEP 131756746Sroberto }, 131856746Sroberto { /* mode 17 */ 131954359Sroberto VARITEXT_FLAGS, 132054359Sroberto NO_POLL, 132154359Sroberto NO_INIT, 132254359Sroberto NO_EVENT, 132354359Sroberto NO_END, 132454359Sroberto NO_MESSAGE, 1325182007Sroberto NO_LCLDATA, 132654359Sroberto VARITEXT_ROOTDELAY, 132754359Sroberto VARITEXT_BASEDELAY, 132854359Sroberto VARITEXT_ID, 132954359Sroberto VARITEXT_DESCRIPTION, 133054359Sroberto VARITEXT_FORMAT, 133154359Sroberto VARITEXT_TYPE, 133254359Sroberto VARITEXT_MAXUNSYNC, 133354359Sroberto VARITEXT_SPEED, 133454359Sroberto VARITEXT_CFLAG, 133554359Sroberto VARITEXT_IFLAG, 133654359Sroberto VARITEXT_OFLAG, 133754359Sroberto VARITEXT_LFLAG, 133854359Sroberto VARITEXT_SAMPLES, 133954359Sroberto VARITEXT_KEEP 1340182007Sroberto }, 1341182007Sroberto { /* mode 18 */ 1342182007Sroberto MBG_FLAGS, 1343182007Sroberto NO_POLL, 1344182007Sroberto NO_INIT, 1345182007Sroberto NO_EVENT, 1346182007Sroberto GPS16X_END, 1347182007Sroberto GPS16X_MESSAGE, 1348182007Sroberto GPS16X_DATA, 1349182007Sroberto GPS16X_ROOTDELAY, 1350182007Sroberto GPS16X_BASEDELAY, 1351182007Sroberto GPS16X_ID, 1352182007Sroberto GPS16X_DESCRIPTION, 1353182007Sroberto GPS16X_FORMAT, 1354182007Sroberto GPS_TYPE, 1355182007Sroberto GPS16X_MAXUNSYNC, 1356182007Sroberto GPS16X_SPEED, 1357182007Sroberto GPS16X_CFLAG, 1358182007Sroberto GPS16X_IFLAG, 1359182007Sroberto GPS16X_OFLAG, 1360182007Sroberto GPS16X_LFLAG, 1361182007Sroberto GPS16X_SAMPLES, 1362182007Sroberto GPS16X_KEEP 1363182007Sroberto }, 1364182007Sroberto { /* mode 19 */ 1365182007Sroberto RAWDCF_FLAGS, 1366182007Sroberto NO_POLL, 1367182007Sroberto RAWDCF_INIT, 1368182007Sroberto NO_EVENT, 1369182007Sroberto NO_END, 1370182007Sroberto NO_MESSAGE, 1371182007Sroberto NO_LCLDATA, 1372182007Sroberto RAWDCF_ROOTDELAY, 1373182007Sroberto GUDE_EMC_USB_V20_BASEDELAY, 1374182007Sroberto DCF_A_ID, 1375182007Sroberto GUDE_EMC_USB_V20_DESCRIPTION, 1376182007Sroberto RAWDCF_FORMAT, 1377182007Sroberto DCF_TYPE, 1378182007Sroberto RAWDCF_MAXUNSYNC, 1379182007Sroberto GUDE_EMC_USB_V20_SPEED, 1380182007Sroberto RAWDCF_CFLAG, 1381182007Sroberto RAWDCF_IFLAG, 1382182007Sroberto RAWDCF_OFLAG, 1383182007Sroberto RAWDCF_LFLAG, 1384182007Sroberto RAWDCF_SAMPLES, 1385182007Sroberto RAWDCF_KEEP 1386182007Sroberto }, 1387280849Scy { /* mode 20, like mode 14 but driven by 75 baud */ 1388280849Scy RAWDCF_FLAGS, 1389280849Scy NO_POLL, 1390280849Scy RAWDCFDTRSET_INIT, 1391280849Scy NO_EVENT, 1392280849Scy NO_END, 1393280849Scy NO_MESSAGE, 1394280849Scy NO_LCLDATA, 1395280849Scy RAWDCF_ROOTDELAY, 1396280849Scy RAWDCF_BASEDELAY, 1397280849Scy DCF_A_ID, 1398280849Scy RAWDCFDTRSET75_DESCRIPTION, 1399280849Scy RAWDCF_FORMAT, 1400280849Scy DCF_TYPE, 1401280849Scy RAWDCF_MAXUNSYNC, 1402280849Scy B75, 1403280849Scy RAWDCF_CFLAG, 1404280849Scy RAWDCF_IFLAG, 1405280849Scy RAWDCF_OFLAG, 1406280849Scy RAWDCF_LFLAG, 1407280849Scy RAWDCF_SAMPLES, 1408280849Scy RAWDCF_KEEP 1409280849Scy }, 1410280849Scy { /* mode 21, like mode 16 but driven by 75 baud 1411280849Scy - RAWDCF RTS set, DTR clr */ 1412280849Scy RAWDCF_FLAGS, 1413280849Scy NO_POLL, 1414280849Scy RAWDCFDTRCLRRTSSET_INIT, 1415280849Scy NO_EVENT, 1416280849Scy NO_END, 1417280849Scy NO_MESSAGE, 1418280849Scy NO_LCLDATA, 1419280849Scy RAWDCF_ROOTDELAY, 1420280849Scy RAWDCF_BASEDELAY, 1421280849Scy DCF_A_ID, 1422280849Scy RAWDCFDTRCLRRTSSET75_DESCRIPTION, 1423280849Scy RAWDCF_FORMAT, 1424280849Scy DCF_TYPE, 1425280849Scy RAWDCF_MAXUNSYNC, 1426280849Scy B75, 1427280849Scy RAWDCF_CFLAG, 1428280849Scy RAWDCF_IFLAG, 1429280849Scy RAWDCF_OFLAG, 1430280849Scy RAWDCF_LFLAG, 1431280849Scy RAWDCF_SAMPLES, 1432280849Scy RAWDCF_KEEP 1433280849Scy }, 1434280849Scy { /* mode 22 - like 2 with POWERUP trust */ 1435280849Scy MBG_FLAGS | PARSE_F_POWERUPTRUST, 1436280849Scy NO_POLL, 1437280849Scy NO_INIT, 1438280849Scy NO_EVENT, 1439280849Scy NO_END, 1440280849Scy NO_MESSAGE, 1441280849Scy NO_LCLDATA, 1442280849Scy DCFUA31_ROOTDELAY, 1443280849Scy DCFUA31_BASEDELAY, 1444280849Scy DCF_A_ID, 1445280849Scy DCFUA31_DESCRIPTION, 1446280849Scy DCFUA31_FORMAT, 1447280849Scy DCF_TYPE, 1448280849Scy DCFUA31_MAXUNSYNC, 1449280849Scy DCFUA31_SPEED, 1450280849Scy DCFUA31_CFLAG, 1451280849Scy DCFUA31_IFLAG, 1452280849Scy DCFUA31_OFLAG, 1453280849Scy DCFUA31_LFLAG, 1454280849Scy DCFUA31_SAMPLES, 1455280849Scy DCFUA31_KEEP 1456280849Scy }, 1457280849Scy { /* mode 23 - like 7 with POWERUP trust */ 1458280849Scy MBG_FLAGS | PARSE_F_POWERUPTRUST, 1459280849Scy GPS16X_POLL, 1460280849Scy GPS16X_INIT, 1461280849Scy NO_EVENT, 1462280849Scy GPS16X_END, 1463280849Scy GPS16X_MESSAGE, 1464280849Scy GPS16X_DATA, 1465280849Scy GPS16X_ROOTDELAY, 1466280849Scy GPS16X_BASEDELAY, 1467280849Scy GPS16X_ID, 1468280849Scy GPS16X_DESCRIPTION, 1469280849Scy GPS16X_FORMAT, 1470280849Scy GPS_TYPE, 1471280849Scy GPS16X_MAXUNSYNC, 1472280849Scy GPS16X_SPEED, 1473280849Scy GPS16X_CFLAG, 1474280849Scy GPS16X_IFLAG, 1475280849Scy GPS16X_OFLAG, 1476280849Scy GPS16X_LFLAG, 1477280849Scy GPS16X_SAMPLES, 1478280849Scy GPS16X_KEEP 1479280849Scy }, 1480280849Scy { /* mode 24 */ 1481280849Scy SEL240X_FLAGS, 1482280849Scy SEL240X_POLL, 1483280849Scy SEL240X_INIT, 1484280849Scy NO_EVENT, 1485280849Scy SEL240X_END, 1486280849Scy NO_MESSAGE, 1487280849Scy SEL240X_DATA, 1488280849Scy SEL240X_ROOTDELAY, 1489280849Scy SEL240X_BASEDELAY, 1490280849Scy SEL240X_ID, 1491280849Scy SEL240X_DESCRIPTION, 1492280849Scy SEL240X_FORMAT, 1493280849Scy GPS_TYPE, 1494280849Scy SEL240X_MAXUNSYNC, 1495280849Scy SEL240X_SPEED, 1496280849Scy SEL240X_CFLAG, 1497280849Scy SEL240X_IFLAG, 1498280849Scy SEL240X_OFLAG, 1499280849Scy SEL240X_LFLAG, 1500280849Scy SEL240X_SAMPLES, 1501280849Scy SEL240X_KEEP 1502280849Scy }, 150354359Sroberto}; 150454359Sroberto 150554359Srobertostatic int ncltypes = sizeof(parse_clockinfo) / sizeof(struct parse_clockinfo); 150654359Sroberto 1507132451Sroberto#define CLK_REALTYPE(x) ((int)(((x)->ttl) & 0x7F)) 150854359Sroberto#define CLK_TYPE(x) ((CLK_REALTYPE(x) >= ncltypes) ? ~0 : CLK_REALTYPE(x)) 150954359Sroberto#define CLK_UNIT(x) ((int)REFCLOCKUNIT(&(x)->srcadr)) 1510132451Sroberto#define CLK_PPS(x) (((x)->ttl) & 0x80) 151154359Sroberto 151254359Sroberto/* 151354359Sroberto * Other constant stuff 151454359Sroberto */ 151554359Sroberto#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */ 151654359Sroberto 151754359Sroberto#define PARSESTATISTICS (60*60) /* output state statistics every hour */ 151854359Sroberto 151954359Srobertostatic int notice = 0; 152054359Sroberto 152154359Sroberto#define PARSE_STATETIME(parse, i) ((parse->generic->currentstatus == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i]) 152254359Sroberto 1523280849Scystatic void parse_event (struct parseunit *, int); 1524280849Scystatic void parse_process (struct parseunit *, parsetime_t *); 1525280849Scystatic void clear_err (struct parseunit *, u_long); 1526280849Scystatic int list_err (struct parseunit *, u_long); 1527280849Scystatic char * l_mktime (u_long); 152854359Sroberto 152954359Sroberto/**=========================================================================== 153054359Sroberto ** implementation error message regression module 153154359Sroberto **/ 153254359Srobertostatic void 153354359Srobertoclear_err( 153454359Sroberto struct parseunit *parse, 153554359Sroberto u_long lstate 153654359Sroberto ) 153754359Sroberto{ 153854359Sroberto if (lstate == ERR_ALL) 153954359Sroberto { 1540280849Scy size_t i; 154154359Sroberto 154254359Sroberto for (i = 0; i < ERR_CNT; i++) 154354359Sroberto { 154454359Sroberto parse->errors[i].err_stage = err_tbl[i]; 154554359Sroberto parse->errors[i].err_cnt = 0; 154654359Sroberto parse->errors[i].err_last = 0; 154754359Sroberto parse->errors[i].err_started = 0; 154854359Sroberto parse->errors[i].err_suppressed = 0; 154954359Sroberto } 155054359Sroberto } 155154359Sroberto else 155254359Sroberto { 155354359Sroberto parse->errors[lstate].err_stage = err_tbl[lstate]; 155454359Sroberto parse->errors[lstate].err_cnt = 0; 155554359Sroberto parse->errors[lstate].err_last = 0; 155654359Sroberto parse->errors[lstate].err_started = 0; 155754359Sroberto parse->errors[lstate].err_suppressed = 0; 155854359Sroberto } 155954359Sroberto} 156054359Sroberto 156154359Srobertostatic int 156254359Srobertolist_err( 156354359Sroberto struct parseunit *parse, 156454359Sroberto u_long lstate 156554359Sroberto ) 156654359Sroberto{ 156754359Sroberto int do_it; 156854359Sroberto struct errorinfo *err = &parse->errors[lstate]; 156954359Sroberto 157054359Sroberto if (err->err_started == 0) 157154359Sroberto { 157254359Sroberto err->err_started = current_time; 157354359Sroberto } 157454359Sroberto 157554359Sroberto do_it = (current_time - err->err_last) >= err->err_stage->err_delay; 157654359Sroberto 157754359Sroberto if (do_it) 157854359Sroberto err->err_cnt++; 157954359Sroberto 158054359Sroberto if (err->err_stage->err_count && 158154359Sroberto (err->err_cnt >= err->err_stage->err_count)) 158254359Sroberto { 158354359Sroberto err->err_stage++; 158454359Sroberto err->err_cnt = 0; 158554359Sroberto } 158654359Sroberto 158754359Sroberto if (!err->err_cnt && do_it) 158854359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: interval for following error message class is at least %s", 158954359Sroberto CLK_UNIT(parse->peer), l_mktime(err->err_stage->err_delay)); 159054359Sroberto 159154359Sroberto if (!do_it) 159254359Sroberto err->err_suppressed++; 159354359Sroberto else 159454359Sroberto err->err_last = current_time; 159554359Sroberto 159654359Sroberto if (do_it && err->err_suppressed) 159754359Sroberto { 159854359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %ld message%s suppressed, error condition class persists for %s", 159954359Sroberto CLK_UNIT(parse->peer), err->err_suppressed, (err->err_suppressed == 1) ? " was" : "s where", 160054359Sroberto l_mktime(current_time - err->err_started)); 160154359Sroberto err->err_suppressed = 0; 160254359Sroberto } 160354359Sroberto 160454359Sroberto return do_it; 160554359Sroberto} 160654359Sroberto 160754359Sroberto/*-------------------------------------------------- 160854359Sroberto * mkreadable - make a printable ascii string (without 160954359Sroberto * embedded quotes so that the ntpq protocol isn't 161054359Sroberto * fooled 161154359Sroberto */ 161254359Sroberto#ifndef isprint 161354359Sroberto#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F)) 161454359Sroberto#endif 161554359Sroberto 161654359Srobertostatic char * 161754359Srobertomkreadable( 161854359Sroberto char *buffer, 161954359Sroberto long blen, 162054359Sroberto const char *src, 162154359Sroberto u_long srclen, 162254359Sroberto int hex 162354359Sroberto ) 162454359Sroberto{ 1625280849Scy static const char ellipsis[] = "..."; 162654359Sroberto char *b = buffer; 1627280849Scy char *endb = NULL; 162854359Sroberto 162954359Sroberto if (blen < 4) 1630280849Scy return NULL; /* don't bother with mini buffers */ 163154359Sroberto 1632280849Scy endb = buffer + blen - sizeof(ellipsis); 163354359Sroberto 163454359Sroberto blen--; /* account for '\0' */ 163554359Sroberto 163654359Sroberto while (blen && srclen--) 163754359Sroberto { 163854359Sroberto if (!hex && /* no binary only */ 163954359Sroberto (*src != '\\') && /* no plain \ */ 164054359Sroberto (*src != '"') && /* no " */ 1641280849Scy isprint((unsigned char)*src)) /* only printables */ 164254359Sroberto { /* they are easy... */ 164354359Sroberto *buffer++ = *src++; 164454359Sroberto blen--; 164554359Sroberto } 164654359Sroberto else 164754359Sroberto { 164854359Sroberto if (blen < 4) 164954359Sroberto { 165054359Sroberto while (blen--) 165154359Sroberto { 165254359Sroberto *buffer++ = '.'; 165354359Sroberto } 165454359Sroberto *buffer = '\0'; 165554359Sroberto return b; 165654359Sroberto } 165754359Sroberto else 165854359Sroberto { 165954359Sroberto if (*src == '\\') 166054359Sroberto { 1661280849Scy memcpy(buffer, "\\\\", 2); 166254359Sroberto buffer += 2; 166354359Sroberto blen -= 2; 166454359Sroberto src++; 166554359Sroberto } 166654359Sroberto else 166754359Sroberto { 1668280849Scy snprintf(buffer, blen, "\\x%02x", *src++); 166954359Sroberto blen -= 4; 167054359Sroberto buffer += 4; 167154359Sroberto } 167254359Sroberto } 167354359Sroberto } 167454359Sroberto if (srclen && !blen && endb) /* overflow - set last chars to ... */ 1675280849Scy memcpy(endb, ellipsis, sizeof(ellipsis)); 167654359Sroberto } 167754359Sroberto 167854359Sroberto *buffer = '\0'; 167954359Sroberto return b; 168054359Sroberto} 168154359Sroberto 168254359Sroberto 168354359Sroberto/*-------------------------------------------------- 168454359Sroberto * mkascii - make a printable ascii string 168554359Sroberto * assumes (unless defined better) 7-bit ASCII 168654359Sroberto */ 168754359Srobertostatic char * 168854359Srobertomkascii( 168954359Sroberto char *buffer, 169054359Sroberto long blen, 169154359Sroberto const char *src, 169254359Sroberto u_long srclen 169354359Sroberto ) 169454359Sroberto{ 169554359Sroberto return mkreadable(buffer, blen, src, srclen, 0); 169654359Sroberto} 169754359Sroberto 169854359Sroberto/**=========================================================================== 169954359Sroberto ** implementation of i/o handling methods 170054359Sroberto ** (all STREAM, partial STREAM, user level) 170154359Sroberto **/ 170254359Sroberto 170354359Sroberto/* 170454359Sroberto * define possible io handling methods 170554359Sroberto */ 170654359Sroberto#ifdef STREAM 1707280849Scystatic int ppsclock_init (struct parseunit *); 1708280849Scystatic int stream_init (struct parseunit *); 1709280849Scystatic void stream_end (struct parseunit *); 1710280849Scystatic int stream_enable (struct parseunit *); 1711280849Scystatic int stream_disable (struct parseunit *); 1712280849Scystatic int stream_setcs (struct parseunit *, parsectl_t *); 1713280849Scystatic int stream_getfmt (struct parseunit *, parsectl_t *); 1714280849Scystatic int stream_setfmt (struct parseunit *, parsectl_t *); 1715280849Scystatic int stream_timecode (struct parseunit *, parsectl_t *); 1716280849Scystatic void stream_receive (struct recvbuf *); 171754359Sroberto#endif 171854359Sroberto 1719280849Scystatic int local_init (struct parseunit *); 1720280849Scystatic void local_end (struct parseunit *); 1721280849Scystatic int local_nop (struct parseunit *); 1722280849Scystatic int local_setcs (struct parseunit *, parsectl_t *); 1723280849Scystatic int local_getfmt (struct parseunit *, parsectl_t *); 1724280849Scystatic int local_setfmt (struct parseunit *, parsectl_t *); 1725280849Scystatic int local_timecode (struct parseunit *, parsectl_t *); 1726280849Scystatic void local_receive (struct recvbuf *); 1727280849Scystatic int local_input (struct recvbuf *); 172854359Sroberto 172954359Srobertostatic bind_t io_bindings[] = 173054359Sroberto{ 173154359Sroberto#ifdef STREAM 173254359Sroberto { 173354359Sroberto "parse STREAM", 173454359Sroberto stream_init, 173554359Sroberto stream_end, 173654359Sroberto stream_setcs, 173754359Sroberto stream_disable, 173854359Sroberto stream_enable, 173954359Sroberto stream_getfmt, 174054359Sroberto stream_setfmt, 174154359Sroberto stream_timecode, 174254359Sroberto stream_receive, 174354359Sroberto 0, 174454359Sroberto }, 174554359Sroberto { 174654359Sroberto "ppsclock STREAM", 174754359Sroberto ppsclock_init, 174854359Sroberto local_end, 174954359Sroberto local_setcs, 175054359Sroberto local_nop, 175154359Sroberto local_nop, 175254359Sroberto local_getfmt, 175354359Sroberto local_setfmt, 175454359Sroberto local_timecode, 175554359Sroberto local_receive, 175654359Sroberto local_input, 175754359Sroberto }, 175854359Sroberto#endif 175954359Sroberto { 176054359Sroberto "normal", 176154359Sroberto local_init, 176254359Sroberto local_end, 176354359Sroberto local_setcs, 176454359Sroberto local_nop, 176554359Sroberto local_nop, 176654359Sroberto local_getfmt, 176754359Sroberto local_setfmt, 176854359Sroberto local_timecode, 176954359Sroberto local_receive, 177054359Sroberto local_input, 177154359Sroberto }, 177254359Sroberto { 177354359Sroberto (char *)0, 1774280849Scy NULL, 1775280849Scy NULL, 1776280849Scy NULL, 1777280849Scy NULL, 1778280849Scy NULL, 1779280849Scy NULL, 1780280849Scy NULL, 1781280849Scy NULL, 1782280849Scy NULL, 1783280849Scy NULL, 178454359Sroberto } 178554359Sroberto}; 178654359Sroberto 178754359Sroberto#ifdef STREAM 178854359Sroberto 178954359Sroberto/*-------------------------------------------------- 179054359Sroberto * ppsclock STREAM init 179154359Sroberto */ 179254359Srobertostatic int 179354359Srobertoppsclock_init( 179454359Sroberto struct parseunit *parse 179554359Sroberto ) 179654359Sroberto{ 179754359Sroberto static char m1[] = "ppsclocd"; 179854359Sroberto static char m2[] = "ppsclock"; 179954359Sroberto 180054359Sroberto /* 180154359Sroberto * now push the parse streams module 180254359Sroberto * it will ensure exclusive access to the device 180354359Sroberto */ 1804182007Sroberto if (ioctl(parse->ppsfd, I_PUSH, (caddr_t)m1) == -1 && 1805182007Sroberto ioctl(parse->ppsfd, I_PUSH, (caddr_t)m2) == -1) 180654359Sroberto { 180754359Sroberto if (errno != EINVAL) 180856746Sroberto { 180956746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m", 181056746Sroberto CLK_UNIT(parse->peer)); 181154359Sroberto } 181254359Sroberto return 0; 181354359Sroberto } 181454359Sroberto if (!local_init(parse)) 181554359Sroberto { 1816182007Sroberto (void)ioctl(parse->ppsfd, I_POP, (caddr_t)0); 181754359Sroberto return 0; 181854359Sroberto } 181954359Sroberto 182054359Sroberto parse->flags |= PARSE_PPSCLOCK; 182154359Sroberto return 1; 182254359Sroberto} 182354359Sroberto 182454359Sroberto/*-------------------------------------------------- 182554359Sroberto * parse STREAM init 182654359Sroberto */ 182754359Srobertostatic int 182854359Srobertostream_init( 182954359Sroberto struct parseunit *parse 183054359Sroberto ) 183154359Sroberto{ 183254359Sroberto static char m1[] = "parse"; 183354359Sroberto /* 183454359Sroberto * now push the parse streams module 183554359Sroberto * to test whether it is there (neat interface 8-( ) 183654359Sroberto */ 183754359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 183854359Sroberto { 183954359Sroberto if (errno != EINVAL) /* accept non-existence */ 184056746Sroberto { 184156746Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 184254359Sroberto } 184354359Sroberto return 0; 184454359Sroberto } 184554359Sroberto else 184654359Sroberto { 184754359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 184854359Sroberto /* empty loop */; 184954359Sroberto 185054359Sroberto /* 185154359Sroberto * now push it a second time after we have removed all 185254359Sroberto * module garbage 185354359Sroberto */ 185454359Sroberto if (ioctl(parse->generic->io.fd, I_PUSH, (caddr_t)m1) == -1) 185554359Sroberto { 185654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CLK_UNIT(parse->peer)); 185754359Sroberto return 0; 185854359Sroberto } 185954359Sroberto else 186054359Sroberto { 186154359Sroberto return 1; 186254359Sroberto } 186354359Sroberto } 186454359Sroberto} 186554359Sroberto 186654359Sroberto/*-------------------------------------------------- 186754359Sroberto * parse STREAM end 186854359Sroberto */ 186954359Srobertostatic void 187054359Srobertostream_end( 187154359Sroberto struct parseunit *parse 187254359Sroberto ) 187354359Sroberto{ 187454359Sroberto while(ioctl(parse->generic->io.fd, I_POP, (caddr_t)0) == 0) 187554359Sroberto /* empty loop */; 187654359Sroberto} 187754359Sroberto 187854359Sroberto/*-------------------------------------------------- 187954359Sroberto * STREAM setcs 188054359Sroberto */ 188154359Srobertostatic int 188254359Srobertostream_setcs( 188354359Sroberto struct parseunit *parse, 188454359Sroberto parsectl_t *tcl 188554359Sroberto ) 188654359Sroberto{ 188754359Sroberto struct strioctl strioc; 188854359Sroberto 188954359Sroberto strioc.ic_cmd = PARSEIOC_SETCS; 189054359Sroberto strioc.ic_timout = 0; 189154359Sroberto strioc.ic_dp = (char *)tcl; 189254359Sroberto strioc.ic_len = sizeof (*tcl); 189354359Sroberto 189454359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 189554359Sroberto { 189654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CLK_UNIT(parse->peer)); 189754359Sroberto return 0; 189854359Sroberto } 189954359Sroberto return 1; 190054359Sroberto} 190154359Sroberto 190254359Sroberto/*-------------------------------------------------- 190354359Sroberto * STREAM enable 190454359Sroberto */ 190554359Srobertostatic int 190654359Srobertostream_enable( 190754359Sroberto struct parseunit *parse 190854359Sroberto ) 190954359Sroberto{ 191054359Sroberto struct strioctl strioc; 191154359Sroberto 191254359Sroberto strioc.ic_cmd = PARSEIOC_ENABLE; 191354359Sroberto strioc.ic_timout = 0; 191454359Sroberto strioc.ic_dp = (char *)0; 191554359Sroberto strioc.ic_len = 0; 191654359Sroberto 191754359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 191854359Sroberto { 191954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CLK_UNIT(parse->peer)); 192054359Sroberto return 0; 192154359Sroberto } 192254359Sroberto parse->generic->io.clock_recv = stream_receive; /* ok - parse input in kernel */ 192354359Sroberto return 1; 192454359Sroberto} 192554359Sroberto 192654359Sroberto/*-------------------------------------------------- 192754359Sroberto * STREAM disable 192854359Sroberto */ 192954359Srobertostatic int 193054359Srobertostream_disable( 193154359Sroberto struct parseunit *parse 193254359Sroberto ) 193354359Sroberto{ 193454359Sroberto struct strioctl strioc; 193554359Sroberto 193654359Sroberto strioc.ic_cmd = PARSEIOC_DISABLE; 193754359Sroberto strioc.ic_timout = 0; 193854359Sroberto strioc.ic_dp = (char *)0; 193954359Sroberto strioc.ic_len = 0; 194054359Sroberto 194154359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 194254359Sroberto { 194354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CLK_UNIT(parse->peer)); 194454359Sroberto return 0; 194554359Sroberto } 194654359Sroberto parse->generic->io.clock_recv = local_receive; /* ok - parse input in daemon */ 194754359Sroberto return 1; 194854359Sroberto} 194954359Sroberto 195054359Sroberto/*-------------------------------------------------- 195154359Sroberto * STREAM getfmt 195254359Sroberto */ 195354359Srobertostatic int 195454359Srobertostream_getfmt( 195554359Sroberto struct parseunit *parse, 195654359Sroberto parsectl_t *tcl 195754359Sroberto ) 195854359Sroberto{ 195954359Sroberto struct strioctl strioc; 196054359Sroberto 196154359Sroberto strioc.ic_cmd = PARSEIOC_GETFMT; 196254359Sroberto strioc.ic_timout = 0; 196354359Sroberto strioc.ic_dp = (char *)tcl; 196454359Sroberto strioc.ic_len = sizeof (*tcl); 196554359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 196654359Sroberto { 196754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CLK_UNIT(parse->peer)); 196854359Sroberto return 0; 196954359Sroberto } 197054359Sroberto return 1; 197154359Sroberto} 197254359Sroberto 197354359Sroberto/*-------------------------------------------------- 197454359Sroberto * STREAM setfmt 197554359Sroberto */ 197654359Srobertostatic int 197754359Srobertostream_setfmt( 197854359Sroberto struct parseunit *parse, 197954359Sroberto parsectl_t *tcl 198054359Sroberto ) 198154359Sroberto{ 198254359Sroberto struct strioctl strioc; 198354359Sroberto 198454359Sroberto strioc.ic_cmd = PARSEIOC_SETFMT; 198554359Sroberto strioc.ic_timout = 0; 198654359Sroberto strioc.ic_dp = (char *)tcl; 198754359Sroberto strioc.ic_len = sizeof (*tcl); 198854359Sroberto 198954359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 199054359Sroberto { 199154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CLK_UNIT(parse->peer)); 199254359Sroberto return 0; 199354359Sroberto } 199454359Sroberto return 1; 199554359Sroberto} 199654359Sroberto 199754359Sroberto 199854359Sroberto/*-------------------------------------------------- 199954359Sroberto * STREAM timecode 200054359Sroberto */ 200154359Srobertostatic int 200254359Srobertostream_timecode( 200354359Sroberto struct parseunit *parse, 200454359Sroberto parsectl_t *tcl 200554359Sroberto ) 200654359Sroberto{ 200754359Sroberto struct strioctl strioc; 200854359Sroberto 200954359Sroberto strioc.ic_cmd = PARSEIOC_TIMECODE; 201054359Sroberto strioc.ic_timout = 0; 201154359Sroberto strioc.ic_dp = (char *)tcl; 201254359Sroberto strioc.ic_len = sizeof (*tcl); 201354359Sroberto 201454359Sroberto if (ioctl(parse->generic->io.fd, I_STR, (caddr_t)&strioc) == -1) 201554359Sroberto { 201654359Sroberto ERR(ERR_INTERNAL) 201754359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: stream_timecode: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CLK_UNIT(parse->peer)); 201854359Sroberto return 0; 201954359Sroberto } 202054359Sroberto clear_err(parse, ERR_INTERNAL); 202154359Sroberto return 1; 202254359Sroberto} 202354359Sroberto 202454359Sroberto/*-------------------------------------------------- 202554359Sroberto * STREAM receive 202654359Sroberto */ 202754359Srobertostatic void 202854359Srobertostream_receive( 202954359Sroberto struct recvbuf *rbufp 203054359Sroberto ) 203154359Sroberto{ 2032280849Scy struct parseunit * parse; 203354359Sroberto parsetime_t parsetime; 203454359Sroberto 2035280849Scy parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 203654359Sroberto if (!parse->peer) 203754359Sroberto return; 203854359Sroberto 203954359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 204054359Sroberto { 204154359Sroberto ERR(ERR_BADIO) 204254359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: stream_receive: bad size (got %d expected %d)", 204354359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 204454359Sroberto parse_event(parse, CEVNT_BADREPLY); 204554359Sroberto return; 204654359Sroberto } 204754359Sroberto clear_err(parse, ERR_BADIO); 204854359Sroberto 204954359Sroberto memmove((caddr_t)&parsetime, 205054359Sroberto (caddr_t)rbufp->recv_buffer, 205154359Sroberto sizeof(parsetime_t)); 205254359Sroberto 205354359Sroberto#ifdef DEBUG 205454359Sroberto if (debug > 3) 205554359Sroberto { 205654359Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time %lx.%08lx, stime %lx.%08lx, ptime %lx.%08lx\n", 205754359Sroberto CLK_UNIT(parse->peer), 205854359Sroberto (unsigned int)parsetime.parse_status, 205954359Sroberto (unsigned int)parsetime.parse_state, 2060182007Sroberto (unsigned long)parsetime.parse_time.tv.tv_sec, 2061182007Sroberto (unsigned long)parsetime.parse_time.tv.tv_usec, 2062182007Sroberto (unsigned long)parsetime.parse_stime.tv.tv_sec, 2063182007Sroberto (unsigned long)parsetime.parse_stime.tv.tv_usec, 2064182007Sroberto (unsigned long)parsetime.parse_ptime.tv.tv_sec, 2065182007Sroberto (unsigned long)parsetime.parse_ptime.tv.tv_usec); 206654359Sroberto } 206754359Sroberto#endif 206854359Sroberto 206954359Sroberto /* 207054359Sroberto * switch time stamp world - be sure to normalize small usec field 207154359Sroberto * errors. 207254359Sroberto */ 207354359Sroberto 2074280849Scy parsetime.parse_stime.fp = tval_stamp_to_lfp(parsetime.parse_stime.tv); 207554359Sroberto 207654359Sroberto if (PARSE_TIMECODE(parsetime.parse_state)) 207754359Sroberto { 2078280849Scy parsetime.parse_time.fp = tval_stamp_to_lfp(parsetime.parse_time.tv); 207954359Sroberto } 208054359Sroberto 208154359Sroberto if (PARSE_PPS(parsetime.parse_state)) 2082280849Scy { 2083280849Scy parsetime.parse_ptime.fp = tval_stamp_to_lfp(parsetime.parse_ptime.tv); 2084280849Scy } 208554359Sroberto 208654359Sroberto parse_process(parse, &parsetime); 208754359Sroberto} 208854359Sroberto#endif 208954359Sroberto 209054359Sroberto/*-------------------------------------------------- 209154359Sroberto * local init 209254359Sroberto */ 209354359Srobertostatic int 209454359Srobertolocal_init( 209554359Sroberto struct parseunit *parse 209654359Sroberto ) 209754359Sroberto{ 209854359Sroberto return parse_ioinit(&parse->parseio); 209954359Sroberto} 210054359Sroberto 210154359Sroberto/*-------------------------------------------------- 210254359Sroberto * local end 210354359Sroberto */ 210454359Srobertostatic void 210554359Srobertolocal_end( 210654359Sroberto struct parseunit *parse 210754359Sroberto ) 210854359Sroberto{ 210954359Sroberto parse_ioend(&parse->parseio); 211054359Sroberto} 211154359Sroberto 211254359Sroberto 211354359Sroberto/*-------------------------------------------------- 211454359Sroberto * local nop 211554359Sroberto */ 211654359Srobertostatic int 211754359Srobertolocal_nop( 211854359Sroberto struct parseunit *parse 211954359Sroberto ) 212054359Sroberto{ 212154359Sroberto return 1; 212254359Sroberto} 212354359Sroberto 212454359Sroberto/*-------------------------------------------------- 212554359Sroberto * local setcs 212654359Sroberto */ 212754359Srobertostatic int 212854359Srobertolocal_setcs( 212954359Sroberto struct parseunit *parse, 213054359Sroberto parsectl_t *tcl 213154359Sroberto ) 213254359Sroberto{ 213354359Sroberto return parse_setcs(tcl, &parse->parseio); 213454359Sroberto} 213554359Sroberto 213654359Sroberto/*-------------------------------------------------- 213754359Sroberto * local getfmt 213854359Sroberto */ 213954359Srobertostatic int 214054359Srobertolocal_getfmt( 214154359Sroberto struct parseunit *parse, 214254359Sroberto parsectl_t *tcl 214354359Sroberto ) 214454359Sroberto{ 214554359Sroberto return parse_getfmt(tcl, &parse->parseio); 214654359Sroberto} 214754359Sroberto 214854359Sroberto/*-------------------------------------------------- 214954359Sroberto * local setfmt 215054359Sroberto */ 215154359Srobertostatic int 215254359Srobertolocal_setfmt( 215354359Sroberto struct parseunit *parse, 215454359Sroberto parsectl_t *tcl 215554359Sroberto ) 215654359Sroberto{ 215754359Sroberto return parse_setfmt(tcl, &parse->parseio); 215854359Sroberto} 215954359Sroberto 216054359Sroberto/*-------------------------------------------------- 216154359Sroberto * local timecode 216254359Sroberto */ 216354359Srobertostatic int 216454359Srobertolocal_timecode( 216554359Sroberto struct parseunit *parse, 216654359Sroberto parsectl_t *tcl 216754359Sroberto ) 216854359Sroberto{ 216954359Sroberto return parse_timecode(tcl, &parse->parseio); 217054359Sroberto} 217154359Sroberto 217254359Sroberto 217354359Sroberto/*-------------------------------------------------- 217454359Sroberto * local input 217554359Sroberto */ 217654359Srobertostatic int 217754359Srobertolocal_input( 217854359Sroberto struct recvbuf *rbufp 217954359Sroberto ) 218054359Sroberto{ 2181280849Scy struct parseunit * parse; 2182280849Scy 218354359Sroberto int count; 218454359Sroberto unsigned char *s; 218554359Sroberto timestamp_t ts; 218654359Sroberto 2187280849Scy parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 218854359Sroberto if (!parse->peer) 218954359Sroberto return 0; 219054359Sroberto 219154359Sroberto /* 219254359Sroberto * eat all characters, parsing then and feeding complete samples 219354359Sroberto */ 219454359Sroberto count = rbufp->recv_length; 219554359Sroberto s = (unsigned char *)rbufp->recv_buffer; 219654359Sroberto ts.fp = rbufp->recv_time; 219754359Sroberto 219854359Sroberto while (count--) 219954359Sroberto { 220054359Sroberto if (parse_ioread(&parse->parseio, (unsigned int)(*s++), &ts)) 220154359Sroberto { 2202182007Sroberto struct recvbuf *buf; 220354359Sroberto 220454359Sroberto /* 220554359Sroberto * got something good to eat 220654359Sroberto */ 220754359Sroberto if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state)) 220854359Sroberto { 2209182007Sroberto#ifdef HAVE_PPSAPI 2210182007Sroberto if (parse->flags & PARSE_PPSCLOCK) 2211182007Sroberto { 2212182007Sroberto struct timespec pps_timeout; 2213182007Sroberto pps_info_t pps_info; 2214182007Sroberto 2215182007Sroberto pps_timeout.tv_sec = 0; 2216182007Sroberto pps_timeout.tv_nsec = 0; 2217182007Sroberto 2218280849Scy if (time_pps_fetch(parse->atom.handle, PPS_TSFMT_TSPEC, &pps_info, 2219182007Sroberto &pps_timeout) == 0) 2220182007Sroberto { 2221182007Sroberto if (pps_info.assert_sequence + pps_info.clear_sequence != parse->ppsserial) 2222182007Sroberto { 2223182007Sroberto double dtemp; 2224182007Sroberto 2225182007Sroberto struct timespec pts; 2226182007Sroberto /* 2227182007Sroberto * add PPS time stamp if available via ppsclock module 2228182007Sroberto * and not supplied already. 2229182007Sroberto */ 2230182007Sroberto if (parse->flags & PARSE_CLEAR) 2231182007Sroberto pts = pps_info.clear_timestamp; 2232182007Sroberto else 2233182007Sroberto pts = pps_info.assert_timestamp; 2234182007Sroberto 2235182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui = pts.tv_sec + JAN_1970; 2236182007Sroberto 2237182007Sroberto dtemp = pts.tv_nsec / 1e9; 2238182007Sroberto if (dtemp < 0.) { 2239182007Sroberto dtemp += 1; 2240182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui--; 2241182007Sroberto } 2242182007Sroberto if (dtemp > 1.) { 2243182007Sroberto dtemp -= 1; 2244182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_ui++; 2245182007Sroberto } 2246182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp.l_uf = dtemp * FRAC; 2247182007Sroberto 2248182007Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2249182007Sroberto#ifdef DEBUG 2250182007Sroberto if (debug > 3) 2251182007Sroberto { 2252182007Sroberto printf( 2253182007Sroberto "parse: local_receive: fd %d PPSAPI seq %ld - PPS %s\n", 2254182007Sroberto rbufp->fd, 2255182007Sroberto (long)pps_info.assert_sequence + (long)pps_info.clear_sequence, 2256182007Sroberto lfptoa(&parse->parseio.parse_dtime.parse_ptime.fp, 6)); 2257182007Sroberto } 2258182007Sroberto#endif 2259182007Sroberto } 2260182007Sroberto#ifdef DEBUG 2261182007Sroberto else 2262182007Sroberto { 2263182007Sroberto if (debug > 3) 2264182007Sroberto { 2265182007Sroberto printf( 2266182007Sroberto "parse: local_receive: fd %d PPSAPI seq assert %ld, seq clear %ld - NO PPS event\n", 2267182007Sroberto rbufp->fd, 2268182007Sroberto (long)pps_info.assert_sequence, (long)pps_info.clear_sequence); 2269182007Sroberto } 2270182007Sroberto } 2271182007Sroberto#endif 2272182007Sroberto parse->ppsserial = pps_info.assert_sequence + pps_info.clear_sequence; 2273182007Sroberto } 2274182007Sroberto#ifdef DEBUG 2275182007Sroberto else 2276182007Sroberto { 2277182007Sroberto if (debug > 3) 2278182007Sroberto { 2279182007Sroberto printf( 2280182007Sroberto "parse: local_receive: fd %d PPSAPI time_pps_fetch errno = %d\n", 2281182007Sroberto rbufp->fd, 2282182007Sroberto errno); 2283182007Sroberto } 2284182007Sroberto } 2285182007Sroberto#endif 2286182007Sroberto } 2287182007Sroberto#else 228854359Sroberto#ifdef TIOCDCDTIMESTAMP 228954359Sroberto struct timeval dcd_time; 229054359Sroberto 2291182007Sroberto if (ioctl(parse->ppsfd, TIOCDCDTIMESTAMP, &dcd_time) != -1) 229254359Sroberto { 229354359Sroberto l_fp tstmp; 229454359Sroberto 229554359Sroberto TVTOTS(&dcd_time, &tstmp); 229654359Sroberto tstmp.l_ui += JAN_1970; 229754359Sroberto L_SUB(&ts.fp, &tstmp); 229854359Sroberto if (ts.fp.l_ui == 0) 229954359Sroberto { 230054359Sroberto#ifdef DEBUG 230154359Sroberto if (debug) 230254359Sroberto { 230354359Sroberto printf( 230454359Sroberto "parse: local_receive: fd %d DCDTIMESTAMP %s\n", 2305182007Sroberto parse->ppsfd, 230654359Sroberto lfptoa(&tstmp, 6)); 230754359Sroberto printf(" sigio %s\n", 230854359Sroberto lfptoa(&ts.fp, 6)); 230954359Sroberto } 231054359Sroberto#endif 231154359Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tstmp; 231254359Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 231354359Sroberto } 231454359Sroberto } 231554359Sroberto#else /* TIOCDCDTIMESTAMP */ 231654359Sroberto#if defined(HAVE_STRUCT_PPSCLOCKEV) && (defined(HAVE_CIOGETEV) || defined(HAVE_TIOCGPPSEV)) 231754359Sroberto if (parse->flags & PARSE_PPSCLOCK) 2318182007Sroberto { 2319182007Sroberto l_fp tts; 2320182007Sroberto struct ppsclockev ev; 232154359Sroberto 232254359Sroberto#ifdef HAVE_CIOGETEV 2323182007Sroberto if (ioctl(parse->ppsfd, CIOGETEV, (caddr_t)&ev) == 0) 232454359Sroberto#endif 232554359Sroberto#ifdef HAVE_TIOCGPPSEV 2326182007Sroberto if (ioctl(parse->ppsfd, TIOCGPPSEV, (caddr_t)&ev) == 0) 232754359Sroberto#endif 232854359Sroberto { 2329182007Sroberto if (ev.serial != parse->ppsserial) 2330182007Sroberto { 2331182007Sroberto /* 2332182007Sroberto * add PPS time stamp if available via ppsclock module 2333182007Sroberto * and not supplied already. 2334182007Sroberto */ 2335182007Sroberto if (!buftvtots((const char *)&ev.tv, &tts)) 233654359Sroberto { 2337182007Sroberto ERR(ERR_BADDATA) 2338182007Sroberto msyslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)"); 233954359Sroberto } 2340182007Sroberto else 2341182007Sroberto { 2342182007Sroberto parse->parseio.parse_dtime.parse_ptime.fp = tts; 2343182007Sroberto parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 2344182007Sroberto } 2345182007Sroberto } 2346182007Sroberto parse->ppsserial = ev.serial; 234754359Sroberto } 2348182007Sroberto } 234954359Sroberto#endif 235054359Sroberto#endif /* TIOCDCDTIMESTAMP */ 2351182007Sroberto#endif /* !HAVE_PPSAPI */ 235254359Sroberto } 235354359Sroberto if (count) 235454359Sroberto { /* simulate receive */ 2355182007Sroberto buf = get_free_recv_buffer(); 2356182007Sroberto if (buf != NULL) { 2357182007Sroberto memmove((caddr_t)buf->recv_buffer, 2358182007Sroberto (caddr_t)&parse->parseio.parse_dtime, 2359182007Sroberto sizeof(parsetime_t)); 2360182007Sroberto buf->recv_length = sizeof(parsetime_t); 2361182007Sroberto buf->recv_time = rbufp->recv_time; 2362280849Scy#ifndef HAVE_IO_COMPLETION_PORT 2363182007Sroberto buf->srcadr = rbufp->srcadr; 2364280849Scy#endif 2365182007Sroberto buf->dstadr = rbufp->dstadr; 2366182007Sroberto buf->receiver = rbufp->receiver; 2367182007Sroberto buf->fd = rbufp->fd; 2368182007Sroberto buf->X_from_where = rbufp->X_from_where; 2369280849Scy parse->generic->io.recvcount++; 2370280849Scy packets_received++; 2371182007Sroberto add_full_recv_buffer(buf); 2372280849Scy#ifdef HAVE_IO_COMPLETION_PORT 2373280849Scy SetEvent(WaitableIoEventHandle); 2374280849Scy#endif 2375182007Sroberto } 237654359Sroberto parse_iodone(&parse->parseio); 237754359Sroberto } 237854359Sroberto else 237954359Sroberto { 238056746Sroberto memmove((caddr_t)rbufp->recv_buffer, 238156746Sroberto (caddr_t)&parse->parseio.parse_dtime, 238256746Sroberto sizeof(parsetime_t)); 238356746Sroberto parse_iodone(&parse->parseio); 238454359Sroberto rbufp->recv_length = sizeof(parsetime_t); 238554359Sroberto return 1; /* got something & in place return */ 238654359Sroberto } 238754359Sroberto } 238854359Sroberto } 238954359Sroberto return 0; /* nothing to pass up */ 239054359Sroberto} 239154359Sroberto 239254359Sroberto/*-------------------------------------------------- 239354359Sroberto * local receive 239454359Sroberto */ 239554359Srobertostatic void 239654359Srobertolocal_receive( 239754359Sroberto struct recvbuf *rbufp 239854359Sroberto ) 239954359Sroberto{ 2400280849Scy struct parseunit * parse; 240154359Sroberto parsetime_t parsetime; 240254359Sroberto 2403280849Scy parse = (struct parseunit *)rbufp->recv_peer->procptr->unitptr; 240454359Sroberto if (!parse->peer) 240554359Sroberto return; 240654359Sroberto 240754359Sroberto if (rbufp->recv_length != sizeof(parsetime_t)) 240854359Sroberto { 240954359Sroberto ERR(ERR_BADIO) 241054359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: local_receive: bad size (got %d expected %d)", 241154359Sroberto CLK_UNIT(parse->peer), rbufp->recv_length, (int)sizeof(parsetime_t)); 241254359Sroberto parse_event(parse, CEVNT_BADREPLY); 241354359Sroberto return; 241454359Sroberto } 241554359Sroberto clear_err(parse, ERR_BADIO); 241654359Sroberto 241754359Sroberto memmove((caddr_t)&parsetime, 241854359Sroberto (caddr_t)rbufp->recv_buffer, 241954359Sroberto sizeof(parsetime_t)); 242054359Sroberto 242154359Sroberto#ifdef DEBUG 242254359Sroberto if (debug > 3) 242354359Sroberto { 2424182007Sroberto printf("PARSE receiver #%d: status %06x, state %08x, time(fp) %lx.%08lx, stime(fp) %lx.%08lx, ptime(fp) %lx.%08lx\n", 242554359Sroberto CLK_UNIT(parse->peer), 242654359Sroberto (unsigned int)parsetime.parse_status, 242754359Sroberto (unsigned int)parsetime.parse_state, 2428182007Sroberto (unsigned long)parsetime.parse_time.fp.l_ui, 2429182007Sroberto (unsigned long)parsetime.parse_time.fp.l_uf, 2430182007Sroberto (unsigned long)parsetime.parse_stime.fp.l_ui, 2431182007Sroberto (unsigned long)parsetime.parse_stime.fp.l_uf, 2432182007Sroberto (unsigned long)parsetime.parse_ptime.fp.l_ui, 2433182007Sroberto (unsigned long)parsetime.parse_ptime.fp.l_uf); 243454359Sroberto } 243554359Sroberto#endif 243654359Sroberto 243754359Sroberto parse_process(parse, &parsetime); 243854359Sroberto} 243954359Sroberto 244054359Sroberto/*-------------------------------------------------- 244154359Sroberto * init_iobinding - find and initialize lower layers 244254359Sroberto */ 244354359Srobertostatic bind_t * 244454359Srobertoinit_iobinding( 244554359Sroberto struct parseunit *parse 244654359Sroberto ) 244754359Sroberto{ 244854359Sroberto bind_t *b = io_bindings; 244954359Sroberto 245054359Sroberto while (b->bd_description != (char *)0) 245154359Sroberto { 245254359Sroberto if ((*b->bd_init)(parse)) 245354359Sroberto { 245454359Sroberto return b; 245554359Sroberto } 245654359Sroberto b++; 245754359Sroberto } 245854359Sroberto return (bind_t *)0; 245954359Sroberto} 246054359Sroberto 246154359Sroberto/**=========================================================================== 246254359Sroberto ** support routines 246354359Sroberto **/ 246454359Sroberto 2465280849Scystatic NTP_PRINTF(4, 5) char * 2466280849Scyap(char *buffer, size_t len, char *pos, const char *fmt, ...) 2467280849Scy{ 2468280849Scy va_list va; 2469280849Scy int l; 2470280849Scy size_t rem = len - (pos - buffer); 2471280849Scy 2472280849Scy if (rem == 0) 2473280849Scy return pos; 2474280849Scy 2475280849Scy va_start(va, fmt); 2476280849Scy l = vsnprintf(pos, rem, fmt, va); 2477280849Scy va_end(va); 2478280849Scy 2479280849Scy if (l != -1) { 2480280849Scy rem--; 2481280849Scy if (rem >= (size_t)l) 2482280849Scy pos += l; 2483280849Scy else 2484280849Scy pos += rem; 2485280849Scy } 2486280849Scy 2487280849Scy return pos; 2488280849Scy} 2489280849Scy 249054359Sroberto/*-------------------------------------------------- 249154359Sroberto * convert a flag field to a string 249254359Sroberto */ 249354359Srobertostatic char * 249454359Srobertoparsestate( 249554359Sroberto u_long lstate, 2496182007Sroberto char *buffer, 2497182007Sroberto int size 249854359Sroberto ) 249954359Sroberto{ 250054359Sroberto static struct bits 250154359Sroberto { 250254359Sroberto u_long bit; 250354359Sroberto const char *name; 250454359Sroberto } flagstrings[] = 250554359Sroberto { 250656746Sroberto { PARSEB_ANNOUNCE, "DST SWITCH WARNING" }, 250756746Sroberto { PARSEB_POWERUP, "NOT SYNCHRONIZED" }, 250856746Sroberto { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" }, 250956746Sroberto { PARSEB_DST, "DST" }, 251056746Sroberto { PARSEB_UTC, "UTC DISPLAY" }, 251156746Sroberto { PARSEB_LEAPADD, "LEAP ADD WARNING" }, 251256746Sroberto { PARSEB_LEAPDEL, "LEAP DELETE WARNING" }, 251354359Sroberto { PARSEB_LEAPSECOND, "LEAP SECOND" }, 251456746Sroberto { PARSEB_ALTERNATE, "ALTERNATE ANTENNA" }, 251556746Sroberto { PARSEB_TIMECODE, "TIME CODE" }, 251656746Sroberto { PARSEB_PPS, "PPS" }, 251756746Sroberto { PARSEB_POSITION, "POSITION" }, 2518280849Scy { 0, NULL } 251954359Sroberto }; 252054359Sroberto 252154359Sroberto static struct sbits 252254359Sroberto { 252354359Sroberto u_long bit; 252454359Sroberto const char *name; 252554359Sroberto } sflagstrings[] = 252654359Sroberto { 252754359Sroberto { PARSEB_S_LEAP, "LEAP INDICATION" }, 252854359Sroberto { PARSEB_S_PPS, "PPS SIGNAL" }, 252954359Sroberto { PARSEB_S_ANTENNA, "ANTENNA" }, 253054359Sroberto { PARSEB_S_POSITION, "POSITION" }, 2531280849Scy { 0, NULL } 253254359Sroberto }; 253354359Sroberto int i; 2534182007Sroberto char *s, *t; 253554359Sroberto 253654359Sroberto *buffer = '\0'; 2537182007Sroberto s = t = buffer; 253854359Sroberto 253954359Sroberto i = 0; 254054359Sroberto while (flagstrings[i].bit) 254154359Sroberto { 254254359Sroberto if (flagstrings[i].bit & lstate) 254354359Sroberto { 2544182007Sroberto if (s != t) 2545280849Scy t = ap(buffer, size, t, "; "); 2546280849Scy t = ap(buffer, size, t, "%s", flagstrings[i].name); 254754359Sroberto } 254854359Sroberto i++; 254954359Sroberto } 255054359Sroberto 255154359Sroberto if (lstate & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION)) 255254359Sroberto { 2553182007Sroberto if (s != t) 2554280849Scy t = ap(buffer, size, t, "; "); 255554359Sroberto 2556280849Scy t = ap(buffer, size, t, "("); 255754359Sroberto 2558280849Scy s = t; 255954359Sroberto 256054359Sroberto i = 0; 256154359Sroberto while (sflagstrings[i].bit) 256254359Sroberto { 256354359Sroberto if (sflagstrings[i].bit & lstate) 256454359Sroberto { 256554359Sroberto if (t != s) 256654359Sroberto { 2567280849Scy t = ap(buffer, size, t, "; "); 256854359Sroberto } 256954359Sroberto 2570280849Scy t = ap(buffer, size, t, "%s", 2571280849Scy sflagstrings[i].name); 257254359Sroberto } 257354359Sroberto i++; 257454359Sroberto } 2575280849Scy t = ap(buffer, size, t, ")"); 257654359Sroberto } 257754359Sroberto return buffer; 257854359Sroberto} 257954359Sroberto 258054359Sroberto/*-------------------------------------------------- 258154359Sroberto * convert a status flag field to a string 258254359Sroberto */ 258354359Srobertostatic char * 258454359Srobertoparsestatus( 258554359Sroberto u_long lstate, 2586182007Sroberto char *buffer, 2587182007Sroberto int size 258854359Sroberto ) 258954359Sroberto{ 259054359Sroberto static struct bits 259154359Sroberto { 259254359Sroberto u_long bit; 259354359Sroberto const char *name; 259454359Sroberto } flagstrings[] = 259554359Sroberto { 259654359Sroberto { CVT_OK, "CONVERSION SUCCESSFUL" }, 259754359Sroberto { CVT_NONE, "NO CONVERSION" }, 259854359Sroberto { CVT_FAIL, "CONVERSION FAILED" }, 259954359Sroberto { CVT_BADFMT, "ILLEGAL FORMAT" }, 260054359Sroberto { CVT_BADDATE, "DATE ILLEGAL" }, 260154359Sroberto { CVT_BADTIME, "TIME ILLEGAL" }, 260254359Sroberto { CVT_ADDITIONAL, "ADDITIONAL DATA" }, 2603280849Scy { 0, NULL } 260454359Sroberto }; 260554359Sroberto int i; 2606280849Scy char *t; 260754359Sroberto 2608280849Scy t = buffer; 260954359Sroberto *buffer = '\0'; 261054359Sroberto 261154359Sroberto i = 0; 261254359Sroberto while (flagstrings[i].bit) 261354359Sroberto { 261454359Sroberto if (flagstrings[i].bit & lstate) 261554359Sroberto { 2616280849Scy if (t != buffer) 2617280849Scy t = ap(buffer, size, t, "; "); 2618280849Scy t = ap(buffer, size, t, "%s", flagstrings[i].name); 261954359Sroberto } 262054359Sroberto i++; 262154359Sroberto } 262254359Sroberto 262354359Sroberto return buffer; 262454359Sroberto} 262554359Sroberto 262654359Sroberto/*-------------------------------------------------- 262754359Sroberto * convert a clock status flag field to a string 262854359Sroberto */ 262954359Srobertostatic const char * 263054359Srobertoclockstatus( 263154359Sroberto u_long lstate 263254359Sroberto ) 263354359Sroberto{ 263454359Sroberto static char buffer[20]; 263554359Sroberto static struct status 263654359Sroberto { 263754359Sroberto u_long value; 263854359Sroberto const char *name; 263954359Sroberto } flagstrings[] = 264054359Sroberto { 264154359Sroberto { CEVNT_NOMINAL, "NOMINAL" }, 264254359Sroberto { CEVNT_TIMEOUT, "NO RESPONSE" }, 264354359Sroberto { CEVNT_BADREPLY,"BAD FORMAT" }, 264454359Sroberto { CEVNT_FAULT, "FAULT" }, 264554359Sroberto { CEVNT_PROP, "PROPAGATION DELAY" }, 264654359Sroberto { CEVNT_BADDATE, "ILLEGAL DATE" }, 264754359Sroberto { CEVNT_BADTIME, "ILLEGAL TIME" }, 2648280849Scy { (unsigned)~0L, NULL } 264954359Sroberto }; 265054359Sroberto int i; 265154359Sroberto 265254359Sroberto i = 0; 2653280849Scy while (flagstrings[i].value != (u_int)~0) 265454359Sroberto { 265554359Sroberto if (flagstrings[i].value == lstate) 265654359Sroberto { 265754359Sroberto return flagstrings[i].name; 265854359Sroberto } 265954359Sroberto i++; 266054359Sroberto } 266154359Sroberto 2662182007Sroberto snprintf(buffer, sizeof(buffer), "unknown #%ld", (u_long)lstate); 266354359Sroberto 266454359Sroberto return buffer; 266554359Sroberto} 266654359Sroberto 266754359Sroberto 266854359Sroberto/*-------------------------------------------------- 266954359Sroberto * l_mktime - make representation of a relative time 267054359Sroberto */ 267154359Srobertostatic char * 267254359Srobertol_mktime( 267354359Sroberto u_long delta 267454359Sroberto ) 267554359Sroberto{ 267654359Sroberto u_long tmp, m, s; 267754359Sroberto static char buffer[40]; 2678182007Sroberto char *t; 267954359Sroberto 268054359Sroberto buffer[0] = '\0'; 2681280849Scy t = buffer; 268254359Sroberto 268354359Sroberto if ((tmp = delta / (60*60*24)) != 0) 268454359Sroberto { 2685280849Scy t = ap(buffer, sizeof(buffer), t, "%ldd+", (u_long)tmp); 268654359Sroberto delta -= tmp * 60*60*24; 268754359Sroberto } 268854359Sroberto 268954359Sroberto s = delta % 60; 269054359Sroberto delta /= 60; 269154359Sroberto m = delta % 60; 269254359Sroberto delta /= 60; 269354359Sroberto 2694280849Scy t = ap(buffer, sizeof(buffer), t, "%02d:%02d:%02d", 2695280849Scy (int)delta, (int)m, (int)s); 269654359Sroberto 269754359Sroberto return buffer; 269854359Sroberto} 269954359Sroberto 270054359Sroberto 270154359Sroberto/*-------------------------------------------------- 270254359Sroberto * parse_statistics - list summary of clock states 270354359Sroberto */ 270454359Srobertostatic void 270554359Srobertoparse_statistics( 270654359Sroberto struct parseunit *parse 270754359Sroberto ) 270854359Sroberto{ 270954359Sroberto int i; 271054359Sroberto 271154359Sroberto NLOG(NLOG_CLOCKSTATIST) /* conditional if clause for conditional syslog */ 271254359Sroberto { 271354359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: running time: %s", 271454359Sroberto CLK_UNIT(parse->peer), 271554359Sroberto l_mktime(current_time - parse->generic->timestarted)); 271654359Sroberto 271754359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: current status: %s", 271854359Sroberto CLK_UNIT(parse->peer), 271954359Sroberto clockstatus(parse->generic->currentstatus)); 272054359Sroberto 272154359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 272254359Sroberto { 272354359Sroberto u_long s_time; 272454359Sroberto u_long percent, d = current_time - parse->generic->timestarted; 272554359Sroberto 272654359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 272754359Sroberto 272854359Sroberto while (((u_long)(~0) / 10000) < percent) 272954359Sroberto { 273054359Sroberto percent /= 10; 273154359Sroberto d /= 10; 273254359Sroberto } 273354359Sroberto 273454359Sroberto if (d) 273554359Sroberto percent = (percent * 10000) / d; 273654359Sroberto else 273754359Sroberto percent = 10000; 273854359Sroberto 273954359Sroberto if (s_time) 274054359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3ld.%02ld%%)", 274154359Sroberto CLK_UNIT(parse->peer), 274254359Sroberto clockstatus((unsigned int)i), 274354359Sroberto l_mktime(s_time), 274454359Sroberto percent / 100, percent % 100); 274554359Sroberto } 274654359Sroberto } 274754359Sroberto} 274854359Sroberto 274954359Sroberto/*-------------------------------------------------- 275054359Sroberto * cparse_statistics - wrapper for statistics call 275154359Sroberto */ 275254359Srobertostatic void 275354359Srobertocparse_statistics( 2754182007Sroberto struct parseunit *parse 275554359Sroberto ) 275654359Sroberto{ 275754359Sroberto if (parse->laststatistic + PARSESTATISTICS < current_time) 275854359Sroberto parse_statistics(parse); 275954359Sroberto parse->laststatistic = current_time; 276054359Sroberto} 276154359Sroberto 276254359Sroberto/**=========================================================================== 276354359Sroberto ** ntp interface routines 276454359Sroberto **/ 276554359Sroberto 276654359Sroberto/*-------------------------------------------------- 276754359Sroberto * parse_shutdown - shut down a PARSE clock 276854359Sroberto */ 276954359Srobertostatic void 277054359Srobertoparse_shutdown( 277154359Sroberto int unit, 277254359Sroberto struct peer *peer 277354359Sroberto ) 277454359Sroberto{ 2775280849Scy struct parseunit *parse = NULL; 277654359Sroberto 2777182007Sroberto if (peer && peer->procptr) 2778280849Scy parse = peer->procptr->unitptr; 2779182007Sroberto 2780182007Sroberto if (!parse) 278154359Sroberto { 2782182007Sroberto /* nothing to clean up */ 278354359Sroberto return; 278454359Sroberto } 278554359Sroberto 2786280849Scy if (!parse->peer) 2787182007Sroberto { 2788182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: INTERNAL ERROR - unit already inactive - shutdown ignored", unit); 2789182007Sroberto return; 2790182007Sroberto } 2791182007Sroberto 2792182007Sroberto#ifdef HAVE_PPSAPI 2793182007Sroberto if (parse->flags & PARSE_PPSCLOCK) 2794182007Sroberto { 2795280849Scy (void)time_pps_destroy(parse->atom.handle); 2796182007Sroberto } 2797182007Sroberto#endif 2798182007Sroberto if (parse->generic->io.fd != parse->ppsfd && parse->ppsfd != -1) 2799280849Scy (void)closeserial(parse->ppsfd); /* close separate PPS source */ 2800182007Sroberto 280154359Sroberto /* 280254359Sroberto * print statistics a last time and 280354359Sroberto * stop statistics machine 280454359Sroberto */ 280554359Sroberto parse_statistics(parse); 280654359Sroberto 280754359Sroberto if (parse->parse_type->cl_end) 280854359Sroberto { 280954359Sroberto parse->parse_type->cl_end(parse); 281054359Sroberto } 281154359Sroberto 2812182007Sroberto /* 2813182007Sroberto * cleanup before leaving this world 2814182007Sroberto */ 281554359Sroberto if (parse->binding) 281654359Sroberto PARSE_END(parse); 281754359Sroberto 281854359Sroberto /* 281954359Sroberto * Tell the I/O module to turn us off. We're history. 282054359Sroberto */ 282154359Sroberto io_closeclock(&parse->generic->io); 282254359Sroberto 282354359Sroberto free_varlist(parse->kv); 282454359Sroberto 282554359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 282654359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed", 282754359Sroberto CLK_UNIT(parse->peer), parse->parse_type->cl_description); 282854359Sroberto 282954359Sroberto parse->peer = (struct peer *)0; /* unused now */ 2830182007Sroberto peer->procptr->unitptr = (caddr_t)0; 283154359Sroberto free(parse); 283254359Sroberto} 283354359Sroberto 2834182007Sroberto#ifdef HAVE_PPSAPI 2835182007Sroberto/*---------------------------------------- 2836182007Sroberto * set up HARDPPS via PPSAPI 2837182007Sroberto */ 2838182007Srobertostatic void 2839182007Srobertoparse_hardpps( 2840182007Sroberto struct parseunit *parse, 2841182007Sroberto int mode 2842182007Sroberto ) 2843182007Sroberto{ 2844182007Sroberto if (parse->hardppsstate == mode) 2845182007Sroberto return; 2846182007Sroberto 2847182007Sroberto if (CLK_PPS(parse->peer) && (parse->flags & PARSE_PPSKERNEL)) { 2848182007Sroberto int i = 0; 2849182007Sroberto 2850182007Sroberto if (mode == PARSE_HARDPPS_ENABLE) 2851182007Sroberto { 2852182007Sroberto if (parse->flags & PARSE_CLEAR) 2853182007Sroberto i = PPS_CAPTURECLEAR; 2854182007Sroberto else 2855182007Sroberto i = PPS_CAPTUREASSERT; 2856182007Sroberto } 2857182007Sroberto 2858280849Scy if (time_pps_kcbind(parse->atom.handle, PPS_KC_HARDPPS, i, 2859182007Sroberto PPS_TSFMT_TSPEC) < 0) { 2860182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: time_pps_kcbind failed: %m", 2861182007Sroberto CLK_UNIT(parse->peer)); 2862182007Sroberto } else { 2863182007Sroberto NLOG(NLOG_CLOCKINFO) 2864182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: kernel PPS synchronisation %sabled", 2865182007Sroberto CLK_UNIT(parse->peer), (mode == PARSE_HARDPPS_ENABLE) ? "en" : "dis"); 2866182007Sroberto /* 2867182007Sroberto * tell the rest, that we have a kernel PPS source, iff we ever enable HARDPPS 2868182007Sroberto */ 2869182007Sroberto if (mode == PARSE_HARDPPS_ENABLE) 2870280849Scy hardpps_enable = 1; 2871182007Sroberto } 2872182007Sroberto } 2873182007Sroberto 2874182007Sroberto parse->hardppsstate = mode; 2875182007Sroberto} 2876182007Sroberto 2877182007Sroberto/*---------------------------------------- 2878182007Sroberto * set up PPS via PPSAPI 2879182007Sroberto */ 2880182007Srobertostatic int 2881182007Srobertoparse_ppsapi( 2882182007Sroberto struct parseunit *parse 2883182007Sroberto ) 2884182007Sroberto{ 2885280849Scy int cap, mode_ppsoffset; 2886280849Scy const char *cp; 2887182007Sroberto 2888182007Sroberto parse->flags &= ~PARSE_PPSCLOCK; 2889182007Sroberto 2890280849Scy /* 2891280849Scy * collect PPSAPI offset capability - should move into generic handling 2892280849Scy */ 2893280849Scy if (time_pps_getcap(parse->atom.handle, &cap) < 0) { 2894182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_ppsapi: time_pps_getcap failed: %m", 2895182007Sroberto CLK_UNIT(parse->peer)); 2896182007Sroberto 2897182007Sroberto return 0; 2898182007Sroberto } 2899182007Sroberto 2900280849Scy /* 2901280849Scy * initialize generic PPSAPI interface 2902280849Scy * 2903280849Scy * we leave out CLK_FLAG3 as time_pps_kcbind() 2904280849Scy * is handled here for now. Ideally this should also 2905280849Scy * be part of the generic PPSAPI interface 2906280849Scy */ 2907280849Scy if (!refclock_params(parse->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG4), &parse->atom)) 2908182007Sroberto return 0; 2909182007Sroberto 2910182007Sroberto /* nb. only turn things on, if someone else has turned something 2911182007Sroberto * on before we get here, leave it alone! 2912182007Sroberto */ 2913182007Sroberto 2914182007Sroberto if (parse->flags & PARSE_CLEAR) { 2915182007Sroberto cp = "CLEAR"; 2916280849Scy mode_ppsoffset = PPS_OFFSETCLEAR; 2917182007Sroberto } else { 2918182007Sroberto cp = "ASSERT"; 2919280849Scy mode_ppsoffset = PPS_OFFSETASSERT; 2920182007Sroberto } 2921182007Sroberto 2922182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: initializing PPS to %s", 2923182007Sroberto CLK_UNIT(parse->peer), cp); 2924182007Sroberto 2925280849Scy if (!(mode_ppsoffset & cap)) { 2926182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: Cannot set PPS_%sCLEAR, this will increase jitter (PPS API capabilities=0x%x)", 2927182007Sroberto CLK_UNIT(parse->peer), cp, cap); 2928280849Scy mode_ppsoffset = 0; 2929182007Sroberto } else { 2930280849Scy if (mode_ppsoffset == PPS_OFFSETCLEAR) 2931182007Sroberto { 2932280849Scy parse->atom.pps_params.clear_offset.tv_sec = -parse->ppsphaseadjust; 2933280849Scy parse->atom.pps_params.clear_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2934182007Sroberto } 2935182007Sroberto 2936280849Scy if (mode_ppsoffset == PPS_OFFSETASSERT) 2937182007Sroberto { 2938280849Scy parse->atom.pps_params.assert_offset.tv_sec = -parse->ppsphaseadjust; 2939280849Scy parse->atom.pps_params.assert_offset.tv_nsec = -1e9*(parse->ppsphaseadjust - (long)parse->ppsphaseadjust); 2940182007Sroberto } 2941182007Sroberto } 2942182007Sroberto 2943280849Scy parse->atom.pps_params.mode |= mode_ppsoffset; 2944182007Sroberto 2945280849Scy if (time_pps_setparams(parse->atom.handle, &parse->atom.pps_params) < 0) { 2946182007Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: FAILED set PPS parameters: %m", 2947182007Sroberto CLK_UNIT(parse->peer)); 2948182007Sroberto return 0; 2949182007Sroberto } 2950182007Sroberto 2951182007Sroberto parse->flags |= PARSE_PPSCLOCK; 2952182007Sroberto return 1; 2953182007Sroberto} 2954182007Sroberto#else 2955182007Sroberto#define parse_hardpps(_PARSE_, _MODE_) /* empty */ 2956182007Sroberto#endif 2957182007Sroberto 295854359Sroberto/*-------------------------------------------------- 295954359Sroberto * parse_start - open the PARSE devices and initialize data for processing 296054359Sroberto */ 296154359Srobertostatic int 296254359Srobertoparse_start( 296354359Sroberto int sysunit, 296454359Sroberto struct peer *peer 296554359Sroberto ) 296654359Sroberto{ 296754359Sroberto u_int unit; 296854359Sroberto int fd232; 296954359Sroberto#ifdef HAVE_TERMIOS 297054359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 297154359Sroberto#endif 297254359Sroberto#ifdef HAVE_SYSV_TTYS 297354359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 297454359Sroberto#endif 297554359Sroberto struct parseunit * parse; 297654359Sroberto char parsedev[sizeof(PARSEDEVICE)+20]; 2977182007Sroberto char parseppsdev[sizeof(PARSEPPSDEVICE)+20]; 297854359Sroberto parsectl_t tmp_ctl; 297954359Sroberto u_int type; 298054359Sroberto 2981182007Sroberto /* 2982182007Sroberto * get out Copyright information once 2983182007Sroberto */ 2984182007Sroberto if (!notice) 2985182007Sroberto { 2986182007Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 2987280849Scy msyslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-2009, Frank Kardel"); 2988182007Sroberto notice = 1; 2989182007Sroberto } 2990182007Sroberto 299154359Sroberto type = CLK_TYPE(peer); 299254359Sroberto unit = CLK_UNIT(peer); 299354359Sroberto 2994280849Scy if ((type == (u_int)~0) || (parse_clockinfo[type].cl_description == (char *)0)) 299554359Sroberto { 299654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)", 299754359Sroberto unit, CLK_REALTYPE(peer), ncltypes-1); 299854359Sroberto return 0; 299954359Sroberto } 300054359Sroberto 300154359Sroberto /* 300254359Sroberto * Unit okay, attempt to open the device. 300354359Sroberto */ 3004182007Sroberto (void) snprintf(parsedev, sizeof(parsedev), PARSEDEVICE, unit); 3005182007Sroberto (void) snprintf(parseppsdev, sizeof(parsedev), PARSEPPSDEVICE, unit); 300654359Sroberto 300754359Sroberto#ifndef O_NOCTTY 300854359Sroberto#define O_NOCTTY 0 300954359Sroberto#endif 3010280849Scy#ifndef O_NONBLOCK 3011280849Scy#define O_NONBLOCK 0 301254359Sroberto#endif 301354359Sroberto 3014280849Scy fd232 = tty_open(parsedev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3015280849Scy 301654359Sroberto if (fd232 == -1) 301754359Sroberto { 301854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev); 301954359Sroberto return 0; 302054359Sroberto } 302154359Sroberto 3022280849Scy parse = emalloc_zero(sizeof(*parse)); 302354359Sroberto 302454359Sroberto parse->generic = peer->procptr; /* link up */ 302554359Sroberto parse->generic->unitptr = (caddr_t)parse; /* link down */ 302654359Sroberto 302754359Sroberto /* 302854359Sroberto * Set up the structures 302954359Sroberto */ 303054359Sroberto parse->generic->timestarted = current_time; 303154359Sroberto parse->lastchange = current_time; 303254359Sroberto 303354359Sroberto parse->flags = 0; 303454359Sroberto parse->pollneeddata = 0; 303554359Sroberto parse->laststatistic = current_time; 303654359Sroberto parse->lastformat = (unsigned short)~0; /* assume no format known */ 3037182007Sroberto parse->timedata.parse_status = (unsigned short)~0; /* be sure to mark initial status change */ 303854359Sroberto parse->lastmissed = 0; /* assume got everything */ 303954359Sroberto parse->ppsserial = 0; 3040182007Sroberto parse->ppsfd = -1; 304154359Sroberto parse->localdata = (void *)0; 304254359Sroberto parse->localstate = 0; 304354359Sroberto parse->kv = (struct ctl_var *)0; 304454359Sroberto 304554359Sroberto clear_err(parse, ERR_ALL); 304654359Sroberto 304754359Sroberto parse->parse_type = &parse_clockinfo[type]; 304854359Sroberto 3049182007Sroberto parse->maxunsync = parse->parse_type->cl_maxunsync; 3050182007Sroberto 305154359Sroberto parse->generic->fudgetime1 = parse->parse_type->cl_basedelay; 305254359Sroberto 305354359Sroberto parse->generic->fudgetime2 = 0.0; 3054182007Sroberto parse->ppsphaseadjust = parse->generic->fudgetime2; 305554359Sroberto 3056182007Sroberto parse->generic->clockdesc = parse->parse_type->cl_description; 305754359Sroberto 305854359Sroberto peer->rootdelay = parse->parse_type->cl_rootdelay; 305954359Sroberto peer->sstclktype = parse->parse_type->cl_type; 306054359Sroberto peer->precision = sys_precision; 306154359Sroberto 306254359Sroberto peer->stratum = STRATUM_REFCLOCK; 3063182007Sroberto 306454359Sroberto if (peer->stratum <= 1) 306554359Sroberto memmove((char *)&parse->generic->refid, parse->parse_type->cl_id, 4); 306654359Sroberto else 306754359Sroberto parse->generic->refid = htonl(PARSEHSREFID); 306854359Sroberto 306954359Sroberto parse->generic->io.fd = fd232; 307054359Sroberto 307154359Sroberto parse->peer = peer; /* marks it also as busy */ 307254359Sroberto 307354359Sroberto /* 307454359Sroberto * configure terminal line 307554359Sroberto */ 307654359Sroberto if (TTY_GETATTR(fd232, &tio) == -1) 307754359Sroberto { 307854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tio): %m", unit, fd232); 307954359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 308054359Sroberto return 0; 308154359Sroberto } 308254359Sroberto else 308354359Sroberto { 308454359Sroberto#ifndef _PC_VDISABLE 308554359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); 308654359Sroberto#else 308754359Sroberto int disablec; 308854359Sroberto errno = 0; /* pathconf can deliver -1 without changing errno ! */ 308954359Sroberto 309054359Sroberto disablec = fpathconf(parse->generic->io.fd, _PC_VDISABLE); 309154359Sroberto if (disablec == -1 && errno) 309254359Sroberto { 309354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CLK_UNIT(parse->peer)); 309454359Sroberto memset((char *)tio.c_cc, 0, sizeof(tio.c_cc)); /* best guess */ 309554359Sroberto } 309654359Sroberto else 309754359Sroberto if (disablec != -1) 309854359Sroberto memset((char *)tio.c_cc, disablec, sizeof(tio.c_cc)); 309954359Sroberto#endif 310054359Sroberto 310154359Sroberto#if defined (VMIN) || defined(VTIME) 310254359Sroberto if ((parse_clockinfo[type].cl_lflag & ICANON) == 0) 310354359Sroberto { 310454359Sroberto#ifdef VMIN 310554359Sroberto tio.c_cc[VMIN] = 1; 310654359Sroberto#endif 310754359Sroberto#ifdef VTIME 310854359Sroberto tio.c_cc[VTIME] = 0; 310954359Sroberto#endif 311054359Sroberto } 311154359Sroberto#endif 311254359Sroberto 311354359Sroberto tio.c_cflag = parse_clockinfo[type].cl_cflag; 311454359Sroberto tio.c_iflag = parse_clockinfo[type].cl_iflag; 311554359Sroberto tio.c_oflag = parse_clockinfo[type].cl_oflag; 311654359Sroberto tio.c_lflag = parse_clockinfo[type].cl_lflag; 311754359Sroberto 311854359Sroberto 311954359Sroberto#ifdef HAVE_TERMIOS 312054359Sroberto if ((cfsetospeed(&tio, parse_clockinfo[type].cl_speed) == -1) || 312154359Sroberto (cfsetispeed(&tio, parse_clockinfo[type].cl_speed) == -1)) 312254359Sroberto { 312354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcset{i,o}speed(&tio, speed): %m", unit); 312454359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 312554359Sroberto return 0; 312654359Sroberto } 312754359Sroberto#else 312854359Sroberto tio.c_cflag |= parse_clockinfo[type].cl_speed; 312954359Sroberto#endif 313054359Sroberto 3131182007Sroberto /* 3132182007Sroberto * set up pps device 3133182007Sroberto * if the PARSEPPSDEVICE can be opened that will be used 3134182007Sroberto * for PPS else PARSEDEVICE will be used 3135182007Sroberto */ 3136280849Scy parse->ppsfd = tty_open(parseppsdev, O_RDWR | O_NOCTTY | O_NONBLOCK, 0777); 3137182007Sroberto 3138182007Sroberto if (parse->ppsfd == -1) 3139182007Sroberto { 3140182007Sroberto parse->ppsfd = fd232; 3141182007Sroberto } 3142182007Sroberto 3143182007Sroberto/* 3144182007Sroberto * Linux PPS - the old way 3145182007Sroberto */ 314654359Sroberto#if defined(HAVE_TIO_SERIAL_STUFF) /* Linux hack: define PPS interface */ 314754359Sroberto { 3148182007Sroberto struct serial_struct ss; 3149182007Sroberto if (ioctl(parse->ppsfd, TIOCGSERIAL, &ss) < 0 || 3150182007Sroberto ( 315154359Sroberto#ifdef ASYNC_LOW_LATENCY 3152182007Sroberto ss.flags |= ASYNC_LOW_LATENCY, 315354359Sroberto#endif 3154182007Sroberto#ifndef HAVE_PPSAPI 315554359Sroberto#ifdef ASYNC_PPS_CD_NEG 3156182007Sroberto ss.flags |= ASYNC_PPS_CD_NEG, 315754359Sroberto#endif 3158182007Sroberto#endif 3159182007Sroberto ioctl(parse->ppsfd, TIOCSSERIAL, &ss)) < 0) { 3160182007Sroberto msyslog(LOG_NOTICE, "refclock_parse: TIOCSSERIAL fd %d, %m", parse->ppsfd); 3161182007Sroberto msyslog(LOG_NOTICE, 3162182007Sroberto "refclock_parse: optional PPS processing not available"); 3163182007Sroberto } else { 3164182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3165182007Sroberto#ifdef ASYNC_PPS_CD_NEG 3166182007Sroberto NLOG(NLOG_CLOCKINFO) 3167182007Sroberto msyslog(LOG_INFO, 3168182007Sroberto "refclock_parse: PPS detection on"); 3169182007Sroberto#endif 3170182007Sroberto } 317154359Sroberto } 317254359Sroberto#endif 3173182007Sroberto 3174182007Sroberto/* 3175182007Sroberto * SUN the Solaris way 3176182007Sroberto */ 317754359Sroberto#ifdef HAVE_TIOCSPPS /* SUN PPS support */ 317854359Sroberto if (CLK_PPS(parse->peer)) 3179182007Sroberto { 3180182007Sroberto int i = 1; 318154359Sroberto 3182182007Sroberto if (ioctl(parse->ppsfd, TIOCSPPS, (caddr_t)&i) == 0) 3183182007Sroberto { 3184182007Sroberto parse->flags |= PARSE_PPSCLOCK; 3185182007Sroberto } 3186182007Sroberto } 318754359Sroberto#endif 318854359Sroberto 3189182007Sroberto/* 3190182007Sroberto * PPS via PPSAPI 3191182007Sroberto */ 3192182007Sroberto#if defined(HAVE_PPSAPI) 3193182007Sroberto parse->hardppsstate = PARSE_HARDPPS_DISABLE; 3194182007Sroberto if (CLK_PPS(parse->peer)) 3195182007Sroberto { 3196280849Scy if (!refclock_ppsapi(parse->ppsfd, &parse->atom)) 3197182007Sroberto { 3198182007Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: could not set up PPS: %m", CLK_UNIT(parse->peer)); 3199182007Sroberto } 3200182007Sroberto else 3201182007Sroberto { 3202182007Sroberto parse_ppsapi(parse); 3203182007Sroberto } 3204182007Sroberto } 3205182007Sroberto#endif 3206182007Sroberto 320754359Sroberto if (TTY_SETATTR(fd232, &tio) == -1) 320854359Sroberto { 320954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tio): %m", unit, fd232); 321054359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 321154359Sroberto return 0; 321254359Sroberto } 321354359Sroberto } 321454359Sroberto 321554359Sroberto /* 3216182007Sroberto * pick correct input machine 321754359Sroberto */ 3218280849Scy parse->generic->io.srcclock = peer; 321954359Sroberto parse->generic->io.datalen = 0; 322054359Sroberto 322154359Sroberto parse->binding = init_iobinding(parse); 322254359Sroberto 322354359Sroberto if (parse->binding == (bind_t *)0) 322454359Sroberto { 322554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.", CLK_UNIT(parse->peer)); 322654359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 322754359Sroberto return 0; /* well, ok - special initialisation broke */ 3228280849Scy } 322954359Sroberto 3230182007Sroberto parse->generic->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */ 3231182007Sroberto parse->generic->io.io_input = parse->binding->bd_io_input; /* pick correct input routine */ 3232182007Sroberto 323354359Sroberto /* 323454359Sroberto * as we always(?) get 8 bit chars we want to be 323554359Sroberto * sure, that the upper bits are zero for less 323654359Sroberto * than 8 bit I/O - so we pass that information on. 323754359Sroberto * note that there can be only one bit count format 323854359Sroberto * per file descriptor 323954359Sroberto */ 324054359Sroberto 324154359Sroberto switch (tio.c_cflag & CSIZE) 324254359Sroberto { 324354359Sroberto case CS5: 324454359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5; 324554359Sroberto break; 324654359Sroberto 324754359Sroberto case CS6: 324854359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6; 324954359Sroberto break; 325054359Sroberto 325154359Sroberto case CS7: 325254359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7; 325354359Sroberto break; 325454359Sroberto 325554359Sroberto case CS8: 325654359Sroberto tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8; 325754359Sroberto break; 325854359Sroberto } 325954359Sroberto 326054359Sroberto if (!PARSE_SETCS(parse, &tmp_ctl)) 326154359Sroberto { 326254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit); 326354359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 326454359Sroberto return 0; /* well, ok - special initialisation broke */ 326554359Sroberto } 326654359Sroberto 3267280849Scy strlcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format, sizeof(tmp_ctl.parseformat.parse_buffer)); 326854359Sroberto tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer); 326954359Sroberto 327054359Sroberto if (!PARSE_SETFMT(parse, &tmp_ctl)) 327154359Sroberto { 327254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit); 327354359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 327454359Sroberto return 0; /* well, ok - special initialisation broke */ 327554359Sroberto } 327654359Sroberto 327754359Sroberto /* 327854359Sroberto * get rid of all IO accumulated so far 327954359Sroberto */ 328054359Sroberto#ifdef HAVE_TERMIOS 328154359Sroberto (void) tcflush(parse->generic->io.fd, TCIOFLUSH); 328254359Sroberto#else 3283182007Sroberto#if defined(TCFLSH) && defined(TCIOFLUSH) 328454359Sroberto { 328554359Sroberto int flshcmd = TCIOFLUSH; 328654359Sroberto 328754359Sroberto (void) ioctl(parse->generic->io.fd, TCFLSH, (caddr_t)&flshcmd); 328854359Sroberto } 328954359Sroberto#endif 329054359Sroberto#endif 329156746Sroberto 329254359Sroberto /* 329354359Sroberto * try to do any special initializations 329454359Sroberto */ 329554359Sroberto if (parse->parse_type->cl_init) 329654359Sroberto { 329754359Sroberto if (parse->parse_type->cl_init(parse)) 329854359Sroberto { 329954359Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 330054359Sroberto return 0; /* well, ok - special initialisation broke */ 330154359Sroberto } 330254359Sroberto } 330354359Sroberto 330454359Sroberto /* 3305182007Sroberto * Insert in async io device list. 330654359Sroberto */ 3307182007Sroberto if (!io_addclock(&parse->generic->io)) 330854359Sroberto { 3309182007Sroberto msyslog(LOG_ERR, 3310182007Sroberto "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CLK_UNIT(parse->peer), parsedev); 3311182007Sroberto parse_shutdown(CLK_UNIT(parse->peer), peer); /* let our cleaning staff do the work */ 3312182007Sroberto return 0; 331354359Sroberto } 331454359Sroberto 331554359Sroberto /* 331654359Sroberto * print out configuration 331754359Sroberto */ 331854359Sroberto NLOG(NLOG_CLOCKINFO) 331954359Sroberto { 332054359Sroberto /* conditional if clause for conditional syslog */ 3321182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (I/O device %s, PPS device %s) added", 332254359Sroberto CLK_UNIT(parse->peer), 3323182007Sroberto parse->parse_type->cl_description, parsedev, 3324182007Sroberto (parse->ppsfd != parse->generic->io.fd) ? parseppsdev : parsedev); 332554359Sroberto 3326182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, trust time %s, precision %d", 332754359Sroberto CLK_UNIT(parse->peer), 3328182007Sroberto parse->peer->stratum, 3329182007Sroberto l_mktime(parse->maxunsync), parse->peer->precision); 333054359Sroberto 3331182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: rootdelay %.6f s, phase adjustment %.6f s, PPS phase adjustment %.6f s, %s IO handling", 333254359Sroberto CLK_UNIT(parse->peer), 333354359Sroberto parse->parse_type->cl_rootdelay, 333454359Sroberto parse->generic->fudgetime1, 3335182007Sroberto parse->ppsphaseadjust, 3336182007Sroberto parse->binding->bd_description); 333754359Sroberto 3338182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CLK_UNIT(parse->peer), 333954359Sroberto parse->parse_type->cl_format); 3340182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: %sPPS support%s", CLK_UNIT(parse->peer), 3341182007Sroberto CLK_PPS(parse->peer) ? "" : "NO ", 3342182007Sroberto CLK_PPS(parse->peer) ? 3343182007Sroberto#ifdef PPS_METHOD 3344182007Sroberto " (implementation " PPS_METHOD ")" 3345182007Sroberto#else 3346182007Sroberto "" 334754359Sroberto#endif 3348182007Sroberto : "" 3349182007Sroberto ); 335054359Sroberto } 335154359Sroberto 335254359Sroberto return 1; 335354359Sroberto} 335454359Sroberto 335554359Sroberto/*-------------------------------------------------- 3356182007Sroberto * parse_ctl - process changes on flags/time values 3357182007Sroberto */ 3358182007Srobertostatic void 3359182007Srobertoparse_ctl( 3360182007Sroberto struct parseunit *parse, 3361280849Scy const struct refclockstat *in 3362182007Sroberto ) 3363182007Sroberto{ 3364182007Sroberto if (in) 3365182007Sroberto { 3366182007Sroberto if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)) 3367182007Sroberto { 3368182007Sroberto parse->flags = (parse->flags & ~(CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) | 3369182007Sroberto (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)); 3370182007Sroberto#if defined(HAVE_PPSAPI) 3371182007Sroberto if (CLK_PPS(parse->peer)) 3372182007Sroberto { 3373182007Sroberto parse_ppsapi(parse); 3374182007Sroberto } 3375182007Sroberto#endif 3376182007Sroberto } 3377182007Sroberto 3378182007Sroberto if (in->haveflags & CLK_HAVETIME1) 3379182007Sroberto { 3380182007Sroberto parse->generic->fudgetime1 = in->fudgetime1; 3381182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new phase adjustment %.6f s", 3382182007Sroberto CLK_UNIT(parse->peer), 3383182007Sroberto parse->generic->fudgetime1); 3384182007Sroberto } 3385182007Sroberto 3386182007Sroberto if (in->haveflags & CLK_HAVETIME2) 3387182007Sroberto { 3388182007Sroberto parse->generic->fudgetime2 = in->fudgetime2; 3389182007Sroberto if (parse->flags & PARSE_TRUSTTIME) 3390182007Sroberto { 3391182007Sroberto parse->maxunsync = (u_long)ABS(in->fudgetime2); 3392182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new trust time %s", 3393182007Sroberto CLK_UNIT(parse->peer), 3394182007Sroberto l_mktime(parse->maxunsync)); 3395182007Sroberto } 3396182007Sroberto else 3397182007Sroberto { 3398182007Sroberto parse->ppsphaseadjust = in->fudgetime2; 3399182007Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: new PPS phase adjustment %.6f s", 3400182007Sroberto CLK_UNIT(parse->peer), 3401182007Sroberto parse->ppsphaseadjust); 3402182007Sroberto#if defined(HAVE_PPSAPI) 3403182007Sroberto if (CLK_PPS(parse->peer)) 3404182007Sroberto { 3405182007Sroberto parse_ppsapi(parse); 3406182007Sroberto } 3407182007Sroberto#endif 3408182007Sroberto } 3409182007Sroberto } 3410182007Sroberto } 3411182007Sroberto} 3412182007Sroberto 3413182007Sroberto/*-------------------------------------------------- 341454359Sroberto * parse_poll - called by the transmit procedure 341554359Sroberto */ 341654359Srobertostatic void 341754359Srobertoparse_poll( 341854359Sroberto int unit, 341954359Sroberto struct peer *peer 342054359Sroberto ) 342154359Sroberto{ 3422280849Scy struct parseunit *parse = peer->procptr->unitptr; 342354359Sroberto 342454359Sroberto if (peer != parse->peer) 342554359Sroberto { 342654359Sroberto msyslog(LOG_ERR, 342754359Sroberto "PARSE receiver #%d: poll: INTERNAL: peer incorrect", 342854359Sroberto unit); 342954359Sroberto return; 343054359Sroberto } 343154359Sroberto 343254359Sroberto /* 343354359Sroberto * Update clock stat counters 343454359Sroberto */ 343554359Sroberto parse->generic->polls++; 343654359Sroberto 343756746Sroberto if (parse->pollneeddata && 3438280849Scy ((int)(current_time - parse->pollneeddata) > (1<<(max(min(parse->peer->hpoll, parse->peer->ppoll), parse->peer->minpoll))))) 343954359Sroberto { 344054359Sroberto /* 344156746Sroberto * start worrying when exceeding a poll inteval 344254359Sroberto * bad news - didn't get a response last time 344354359Sroberto */ 344454359Sroberto parse->lastmissed = current_time; 344554359Sroberto parse_event(parse, CEVNT_TIMEOUT); 344654359Sroberto 344754359Sroberto ERR(ERR_NODATA) 3448182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval (check receiver / wiring)", CLK_UNIT(parse->peer)); 344954359Sroberto } 345054359Sroberto 345154359Sroberto /* 345254359Sroberto * we just mark that we want the next sample for the clock filter 345354359Sroberto */ 345456746Sroberto parse->pollneeddata = current_time; 345554359Sroberto 345654359Sroberto if (parse->parse_type->cl_poll) 345754359Sroberto { 345854359Sroberto parse->parse_type->cl_poll(parse); 345954359Sroberto } 346054359Sroberto 346154359Sroberto cparse_statistics(parse); 346254359Sroberto 346354359Sroberto return; 346454359Sroberto} 346554359Sroberto 346654359Sroberto#define LEN_STATES 300 /* length of state string */ 346754359Sroberto 346854359Sroberto/*-------------------------------------------------- 346954359Sroberto * parse_control - set fudge factors, return statistics 347054359Sroberto */ 347154359Srobertostatic void 347254359Srobertoparse_control( 347354359Sroberto int unit, 3474280849Scy const struct refclockstat *in, 347554359Sroberto struct refclockstat *out, 347654359Sroberto struct peer *peer 347754359Sroberto ) 347854359Sroberto{ 3479280849Scy struct parseunit *parse = peer->procptr->unitptr; 348054359Sroberto parsectl_t tmpctl; 348154359Sroberto 348254359Sroberto static char outstatus[400]; /* status output buffer */ 348354359Sroberto 348454359Sroberto if (out) 348554359Sroberto { 348654359Sroberto out->lencode = 0; 348754359Sroberto out->p_lastcode = 0; 348854359Sroberto out->kv_list = (struct ctl_var *)0; 348954359Sroberto } 349054359Sroberto 349154359Sroberto if (!parse || !parse->peer) 349254359Sroberto { 349354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)", 349454359Sroberto unit); 349554359Sroberto return; 349654359Sroberto } 349754359Sroberto 349854359Sroberto unit = CLK_UNIT(parse->peer); 349954359Sroberto 3500182007Sroberto /* 3501182007Sroberto * handle changes 3502182007Sroberto */ 3503182007Sroberto parse_ctl(parse, in); 3504182007Sroberto 3505182007Sroberto /* 3506182007Sroberto * supply data 3507182007Sroberto */ 350854359Sroberto if (out) 350954359Sroberto { 351054359Sroberto u_long sum = 0; 3511182007Sroberto char *tt, *start; 351254359Sroberto int i; 351354359Sroberto 351454359Sroberto outstatus[0] = '\0'; 351554359Sroberto 351654359Sroberto out->type = REFCLK_PARSE; 351754359Sroberto 351854359Sroberto /* 3519182007Sroberto * keep fudgetime2 in sync with TRUSTTIME/MAXUNSYNC flag1 3520182007Sroberto */ 3521182007Sroberto parse->generic->fudgetime2 = (parse->flags & PARSE_TRUSTTIME) ? (double)parse->maxunsync : parse->ppsphaseadjust; 3522182007Sroberto 3523182007Sroberto /* 352454359Sroberto * figure out skew between PPS and RS232 - just for informational 3525182007Sroberto * purposes 352654359Sroberto */ 3527182007Sroberto if (PARSE_SYNC(parse->timedata.parse_state)) 352854359Sroberto { 3529182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && PARSE_TIMECODE(parse->timedata.parse_state)) 353054359Sroberto { 353154359Sroberto l_fp off; 353254359Sroberto 353354359Sroberto /* 353454359Sroberto * we have a PPS and RS232 signal - calculate the skew 353554359Sroberto * WARNING: assumes on TIMECODE == PULSE (timecode after pulse) 353654359Sroberto */ 3537182007Sroberto off = parse->timedata.parse_stime.fp; 3538182007Sroberto L_SUB(&off, &parse->timedata.parse_ptime.fp); /* true offset */ 353954359Sroberto tt = add_var(&out->kv_list, 80, RO); 3540182007Sroberto snprintf(tt, 80, "refclock_ppsskew=%s", lfptoms(&off, 6)); 354154359Sroberto } 354254359Sroberto } 354354359Sroberto 3544182007Sroberto if (PARSE_PPS(parse->timedata.parse_state)) 354554359Sroberto { 354654359Sroberto tt = add_var(&out->kv_list, 80, RO|DEF); 3547182007Sroberto snprintf(tt, 80, "refclock_ppstime=\"%s\"", gmprettydate(&parse->timedata.parse_ptime.fp)); 354854359Sroberto } 354954359Sroberto 3550182007Sroberto start = tt = add_var(&out->kv_list, 128, RO|DEF); 3551280849Scy tt = ap(start, 128, tt, "refclock_time=\""); 355254359Sroberto 3553182007Sroberto if (parse->timedata.parse_time.fp.l_ui == 0) 355454359Sroberto { 3555280849Scy tt = ap(start, 128, tt, "<UNDEFINED>\""); 355654359Sroberto } 355754359Sroberto else 355854359Sroberto { 3559280849Scy tt = ap(start, 128, tt, "%s\"", 3560280849Scy gmprettydate(&parse->timedata.parse_time.fp)); 356154359Sroberto } 356254359Sroberto 356354359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 356454359Sroberto { 356554359Sroberto ERR(ERR_INTERNAL) 356654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit); 356754359Sroberto } 356854359Sroberto else 356954359Sroberto { 3570182007Sroberto start = tt = add_var(&out->kv_list, 512, RO|DEF); 3571280849Scy tt = ap(start, 512, tt, "refclock_status=\""); 357254359Sroberto 357354359Sroberto /* 357454359Sroberto * copy PPS flags from last read transaction (informational only) 357554359Sroberto */ 3576182007Sroberto tmpctl.parsegettc.parse_state |= parse->timedata.parse_state & 357754359Sroberto (PARSEB_PPS|PARSEB_S_PPS); 357854359Sroberto 3579280849Scy (void)parsestate(tmpctl.parsegettc.parse_state, tt, BUFFER_SIZES(start, tt, 512)); 358054359Sroberto 3581280849Scy tt += strlen(tt); 358254359Sroberto 3583280849Scy tt = ap(start, 512, tt, "\""); 3584280849Scy 358554359Sroberto if (tmpctl.parsegettc.parse_count) 358654359Sroberto mkascii(outstatus+strlen(outstatus), (int)(sizeof(outstatus)- strlen(outstatus) - 1), 3587182007Sroberto tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count)); 358854359Sroberto 358954359Sroberto } 359054359Sroberto 359154359Sroberto tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format; 359254359Sroberto 359354359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 359454359Sroberto { 359554359Sroberto ERR(ERR_INTERNAL) 359654359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit); 359754359Sroberto } 359854359Sroberto else 359954359Sroberto { 3600280849Scy int count = tmpctl.parseformat.parse_count - 1; 360154359Sroberto 3602280849Scy start = tt = add_var(&out->kv_list, 80, RO|DEF); 3603280849Scy tt = ap(start, 80, tt, "refclock_format=\""); 3604280849Scy 3605280849Scy if (count > 0) { 3606280849Scy tt = ap(start, 80, tt, "%*.*s", 3607280849Scy count, 3608280849Scy count, 3609280849Scy tmpctl.parseformat.parse_buffer); 3610280849Scy } 3611280849Scy 3612280849Scy tt = ap(start, 80, tt, "\""); 361354359Sroberto } 361454359Sroberto 361554359Sroberto /* 361654359Sroberto * gather state statistics 361754359Sroberto */ 361854359Sroberto 361954359Sroberto start = tt = add_var(&out->kv_list, LEN_STATES, RO|DEF); 3620280849Scy tt = ap(start, LEN_STATES, tt, "refclock_states=\""); 362154359Sroberto 362254359Sroberto for (i = 0; i <= CEVNT_MAX; i++) 362354359Sroberto { 362454359Sroberto u_long s_time; 362554359Sroberto u_long d = current_time - parse->generic->timestarted; 362654359Sroberto u_long percent; 362754359Sroberto 362854359Sroberto percent = s_time = PARSE_STATETIME(parse, i); 362954359Sroberto 363054359Sroberto while (((u_long)(~0) / 10000) < percent) 363154359Sroberto { 363254359Sroberto percent /= 10; 363354359Sroberto d /= 10; 363454359Sroberto } 363554359Sroberto 363654359Sroberto if (d) 363754359Sroberto percent = (percent * 10000) / d; 363854359Sroberto else 363954359Sroberto percent = 10000; 364054359Sroberto 364154359Sroberto if (s_time) 364254359Sroberto { 364354359Sroberto char item[80]; 364454359Sroberto int count; 364554359Sroberto 3646182007Sroberto snprintf(item, 80, "%s%s%s: %s (%d.%02d%%)", 364754359Sroberto sum ? "; " : "", 364854359Sroberto (parse->generic->currentstatus == i) ? "*" : "", 364954359Sroberto clockstatus((unsigned int)i), 365054359Sroberto l_mktime(s_time), 365154359Sroberto (int)(percent / 100), (int)(percent % 100)); 365254359Sroberto if ((count = strlen(item)) < (LEN_STATES - 40 - (tt - start))) 365354359Sroberto { 3654280849Scy tt = ap(start, LEN_STATES, tt, 3655280849Scy "%s", item); 365654359Sroberto } 365754359Sroberto sum += s_time; 365854359Sroberto } 365954359Sroberto } 366054359Sroberto 3661280849Scy tt = ap(start, LEN_STATES, tt, 3662280849Scy "; running time: %s\"", l_mktime(sum)); 366354359Sroberto 366454359Sroberto tt = add_var(&out->kv_list, 32, RO); 3665182007Sroberto snprintf(tt, 32, "refclock_id=\"%s\"", parse->parse_type->cl_id); 366654359Sroberto 366754359Sroberto tt = add_var(&out->kv_list, 80, RO); 3668182007Sroberto snprintf(tt, 80, "refclock_iomode=\"%s\"", parse->binding->bd_description); 366954359Sroberto 367054359Sroberto tt = add_var(&out->kv_list, 128, RO); 3671182007Sroberto snprintf(tt, 128, "refclock_driver_version=\"%s\"", rcsid); 367254359Sroberto 367354359Sroberto { 367454359Sroberto struct ctl_var *k; 367554359Sroberto 367654359Sroberto k = parse->kv; 367754359Sroberto while (k && !(k->flags & EOV)) 367854359Sroberto { 367954359Sroberto set_var(&out->kv_list, k->text, strlen(k->text)+1, k->flags); 368054359Sroberto k++; 368154359Sroberto } 368254359Sroberto } 368354359Sroberto 368454359Sroberto out->lencode = strlen(outstatus); 368554359Sroberto out->p_lastcode = outstatus; 368654359Sroberto } 368754359Sroberto} 368854359Sroberto 368954359Sroberto/**=========================================================================== 369054359Sroberto ** processing routines 369154359Sroberto **/ 369254359Sroberto 369354359Sroberto/*-------------------------------------------------- 369454359Sroberto * event handling - note that nominal events will also be posted 3695182007Sroberto * keep track of state dwelling times 369654359Sroberto */ 369754359Srobertostatic void 369854359Srobertoparse_event( 369954359Sroberto struct parseunit *parse, 370054359Sroberto int event 370154359Sroberto ) 370254359Sroberto{ 370354359Sroberto if (parse->generic->currentstatus != (u_char) event) 370454359Sroberto { 370554359Sroberto parse->statetime[parse->generic->currentstatus] += current_time - parse->lastchange; 370654359Sroberto parse->lastchange = current_time; 370754359Sroberto 370854359Sroberto if (parse->parse_type->cl_event) 370954359Sroberto parse->parse_type->cl_event(parse, event); 3710280849Scy 3711182007Sroberto if (event == CEVNT_NOMINAL) 371254359Sroberto { 371354359Sroberto NLOG(NLOG_CLOCKSTATUS) 371454359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: SYNCHRONIZED", 371554359Sroberto CLK_UNIT(parse->peer)); 371654359Sroberto } 371754359Sroberto 3718182007Sroberto refclock_report(parse->peer, event); 371954359Sroberto } 372054359Sroberto} 372154359Sroberto 372254359Sroberto/*-------------------------------------------------- 372354359Sroberto * process a PARSE time sample 372454359Sroberto */ 372554359Srobertostatic void 372654359Srobertoparse_process( 372754359Sroberto struct parseunit *parse, 372854359Sroberto parsetime_t *parsetime 372954359Sroberto ) 373054359Sroberto{ 373154359Sroberto l_fp off, rectime, reftime; 373254359Sroberto double fudge; 373354359Sroberto 3734280849Scy /* silence warning: 'off.Ul_i.Xl_i' may be used uninitialized in this function */ 3735280849Scy ZERO(off); 3736280849Scy 373754359Sroberto /* 373854359Sroberto * check for changes in conversion status 373954359Sroberto * (only one for each new status !) 374054359Sroberto */ 374154359Sroberto if (((parsetime->parse_status & CVT_MASK) != CVT_OK) && 374254359Sroberto ((parsetime->parse_status & CVT_MASK) != CVT_NONE) && 3743182007Sroberto (parse->timedata.parse_status != parsetime->parse_status)) 374454359Sroberto { 374554359Sroberto char buffer[400]; 374654359Sroberto 374754359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 374854359Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"", 3749182007Sroberto CLK_UNIT(parse->peer), parsestatus(parsetime->parse_status, buffer, sizeof(buffer))); 375054359Sroberto 375154359Sroberto if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL) 375254359Sroberto { 375354359Sroberto /* 375454359Sroberto * tell more about the story - list time code 375554359Sroberto * there is a slight change for a race condition and 375654359Sroberto * the time code might be overwritten by the next packet 375754359Sroberto */ 375854359Sroberto parsectl_t tmpctl; 375954359Sroberto 376054359Sroberto if (!PARSE_GETTIMECODE(parse, &tmpctl)) 376154359Sroberto { 376254359Sroberto ERR(ERR_INTERNAL) 376354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CLK_UNIT(parse->peer)); 376454359Sroberto } 376554359Sroberto else 376654359Sroberto { 376754359Sroberto ERR(ERR_BADDATA) 3768182007Sroberto msyslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\" (check receiver configuration / wiring)", 376954359Sroberto CLK_UNIT(parse->peer), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, (unsigned)(tmpctl.parsegettc.parse_count - 1))); 377054359Sroberto } 377154359Sroberto } 377254359Sroberto } 377354359Sroberto 377454359Sroberto /* 377554359Sroberto * examine status and post appropriate events 377654359Sroberto */ 377754359Sroberto if ((parsetime->parse_status & CVT_MASK) != CVT_OK) 377854359Sroberto { 377954359Sroberto /* 378054359Sroberto * got bad data - tell the rest of the system 378154359Sroberto */ 378254359Sroberto switch (parsetime->parse_status & CVT_MASK) 378354359Sroberto { 378454359Sroberto case CVT_NONE: 378554359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 378654359Sroberto parse->parse_type->cl_message) 378754359Sroberto parse->parse_type->cl_message(parse, parsetime); 3788182007Sroberto /* 3789182007Sroberto * save PPS information that comes piggyback 3790182007Sroberto */ 3791182007Sroberto if (PARSE_PPS(parsetime->parse_state)) 3792182007Sroberto { 3793182007Sroberto parse->timedata.parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3794182007Sroberto parse->timedata.parse_ptime = parsetime->parse_ptime; 3795182007Sroberto } 379654359Sroberto break; /* well, still waiting - timeout is handled at higher levels */ 379754359Sroberto 379854359Sroberto case CVT_FAIL: 379954359Sroberto if (parsetime->parse_status & CVT_BADFMT) 380054359Sroberto { 380154359Sroberto parse_event(parse, CEVNT_BADREPLY); 380254359Sroberto } 380354359Sroberto else 380454359Sroberto if (parsetime->parse_status & CVT_BADDATE) 380554359Sroberto { 380654359Sroberto parse_event(parse, CEVNT_BADDATE); 380754359Sroberto } 380854359Sroberto else 380954359Sroberto if (parsetime->parse_status & CVT_BADTIME) 381054359Sroberto { 381154359Sroberto parse_event(parse, CEVNT_BADTIME); 381254359Sroberto } 381354359Sroberto else 381454359Sroberto { 381554359Sroberto parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */ 381654359Sroberto } 381754359Sroberto } 381854359Sroberto return; /* skip the rest - useless */ 381954359Sroberto } 382054359Sroberto 382154359Sroberto /* 382254359Sroberto * check for format changes 382354359Sroberto * (in case somebody has swapped clocks 8-) 382454359Sroberto */ 382554359Sroberto if (parse->lastformat != parsetime->parse_format) 382654359Sroberto { 382754359Sroberto parsectl_t tmpctl; 382854359Sroberto 382954359Sroberto tmpctl.parseformat.parse_format = parsetime->parse_format; 383054359Sroberto 383154359Sroberto if (!PARSE_GETFMT(parse, &tmpctl)) 383254359Sroberto { 383354359Sroberto ERR(ERR_INTERNAL) 383454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CLK_UNIT(parse->peer)); 383554359Sroberto } 383654359Sroberto else 383754359Sroberto { 383854359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 383954359Sroberto msyslog(LOG_INFO, "PARSE receiver #%d: packet format \"%s\"", 384054359Sroberto CLK_UNIT(parse->peer), tmpctl.parseformat.parse_buffer); 384154359Sroberto } 384254359Sroberto parse->lastformat = parsetime->parse_format; 384354359Sroberto } 384454359Sroberto 384554359Sroberto /* 384654359Sroberto * now, any changes ? 384754359Sroberto */ 3848182007Sroberto if ((parse->timedata.parse_state ^ parsetime->parse_state) & 3849182007Sroberto ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS)) 385054359Sroberto { 385154359Sroberto char tmp1[200]; 385254359Sroberto char tmp2[200]; 385354359Sroberto /* 3854182007Sroberto * something happend - except for PPS events 385554359Sroberto */ 385654359Sroberto 3857182007Sroberto (void) parsestate(parsetime->parse_state, tmp1, sizeof(tmp1)); 3858182007Sroberto (void) parsestate(parse->timedata.parse_state, tmp2, sizeof(tmp2)); 385954359Sroberto 386054359Sroberto NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */ 386154359Sroberto msyslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s", 386254359Sroberto CLK_UNIT(parse->peer), tmp2, tmp1); 386354359Sroberto } 386454359Sroberto 386554359Sroberto /* 3866182007Sroberto * carry on PPS information if still usable 3867182007Sroberto */ 3868182007Sroberto if (PARSE_PPS(parse->timedata.parse_state) && !PARSE_PPS(parsetime->parse_state)) 3869182007Sroberto { 3870182007Sroberto parsetime->parse_state |= PARSEB_PPS|PARSEB_S_PPS; 3871182007Sroberto parsetime->parse_ptime = parse->timedata.parse_ptime; 3872182007Sroberto } 3873182007Sroberto 3874182007Sroberto /* 387554359Sroberto * remember for future 387654359Sroberto */ 3877182007Sroberto parse->timedata = *parsetime; 387854359Sroberto 387954359Sroberto /* 388054359Sroberto * check to see, whether the clock did a complete powerup or lost PZF signal 388154359Sroberto * and post correct events for current condition 388254359Sroberto */ 388354359Sroberto if (PARSE_POWERUP(parsetime->parse_state)) 388454359Sroberto { 388554359Sroberto /* 388654359Sroberto * this is bad, as we have completely lost synchronisation 388754359Sroberto * well this is a problem with the receiver here 388854359Sroberto * for PARSE Meinberg DCF77 receivers the lost synchronisation 388954359Sroberto * is true as it is the powerup state and the time is taken 389054359Sroberto * from a crude real time clock chip 3891280849Scy * for the PZF/GPS series this is only partly true, as 389254359Sroberto * PARSE_POWERUP only means that the pseudo random 389354359Sroberto * phase shift sequence cannot be found. this is only 389454359Sroberto * bad, if we have never seen the clock in the SYNC 389554359Sroberto * state, where the PHASE and EPOCH are correct. 389654359Sroberto * for reporting events the above business does not 389754359Sroberto * really matter, but we can use the time code 389854359Sroberto * even in the POWERUP state after having seen 389954359Sroberto * the clock in the synchronized state (PZF class 390054359Sroberto * receivers) unless we have had a telegram disruption 390154359Sroberto * after having seen the clock in the SYNC state. we 390254359Sroberto * thus require having seen the clock in SYNC state 390354359Sroberto * *after* having missed telegrams (noresponse) from 390454359Sroberto * the clock. one problem remains: we might use erroneously 390554359Sroberto * POWERUP data if the disruption is shorter than 1 polling 390654359Sroberto * interval. fortunately powerdowns last usually longer than 64 390754359Sroberto * seconds and the receiver is at least 2 minutes in the 390854359Sroberto * POWERUP or NOSYNC state before switching to SYNC 3909280849Scy * for GPS receivers this can mean antenna problems and other causes. 3910280849Scy * the additional grace period can be enables by a clock 3911280849Scy * mode having the PARSE_F_POWERUPTRUST flag in cl_flag set. 391254359Sroberto */ 391354359Sroberto parse_event(parse, CEVNT_FAULT); 391454359Sroberto NLOG(NLOG_CLOCKSTATUS) 391554359Sroberto ERR(ERR_BADSTATUS) 3916280849Scy msyslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED/RECEIVER PROBLEMS", 391754359Sroberto CLK_UNIT(parse->peer)); 391854359Sroberto } 391954359Sroberto else 392054359Sroberto { 392154359Sroberto /* 392254359Sroberto * we have two states left 392354359Sroberto * 392454359Sroberto * SYNC: 392554359Sroberto * this state means that the EPOCH (timecode) and PHASE 392654359Sroberto * information has be read correctly (at least two 392754359Sroberto * successive PARSE timecodes were received correctly) 392854359Sroberto * this is the best possible state - full trust 392954359Sroberto * 393054359Sroberto * NOSYNC: 393154359Sroberto * The clock should be on phase with respect to the second 393254359Sroberto * signal, but the timecode has not been received correctly within 393354359Sroberto * at least the last two minutes. this is a sort of half baked state 393454359Sroberto * for PARSE Meinberg DCF77 clocks this is bad news (clock running 393554359Sroberto * without timecode confirmation) 393654359Sroberto * PZF 535 has also no time confirmation, but the phase should be 393754359Sroberto * very precise as the PZF signal can be decoded 393854359Sroberto */ 393954359Sroberto 394054359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 394154359Sroberto { 394254359Sroberto /* 394354359Sroberto * currently completely synchronized - best possible state 394454359Sroberto */ 394554359Sroberto parse->lastsync = current_time; 394654359Sroberto clear_err(parse, ERR_BADSTATUS); 394754359Sroberto } 394854359Sroberto else 394954359Sroberto { 395054359Sroberto /* 395154359Sroberto * we have had some problems receiving the time code 395254359Sroberto */ 395354359Sroberto parse_event(parse, CEVNT_PROP); 395454359Sroberto NLOG(NLOG_CLOCKSTATUS) 395554359Sroberto ERR(ERR_BADSTATUS) 395654359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: TIMECODE NOT CONFIRMED", 395754359Sroberto CLK_UNIT(parse->peer)); 395854359Sroberto } 395954359Sroberto } 396054359Sroberto 396154359Sroberto fudge = parse->generic->fudgetime1; /* standard RS232 Fudgefactor */ 396254359Sroberto 396354359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 396454359Sroberto { 396554359Sroberto rectime = parsetime->parse_stime.fp; 396654359Sroberto off = reftime = parsetime->parse_time.fp; 396754359Sroberto 396854359Sroberto L_SUB(&off, &rectime); /* prepare for PPS adjustments logic */ 396954359Sroberto 397054359Sroberto#ifdef DEBUG 397154359Sroberto if (debug > 3) 397254359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - initial offset %s\n", 397354359Sroberto CLK_UNIT(parse->peer), 397454359Sroberto prettydate(&reftime), 397554359Sroberto prettydate(&rectime), 397654359Sroberto lfptoa(&off,6)); 397754359Sroberto#endif 397854359Sroberto } 397954359Sroberto 398054359Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 398154359Sroberto { 398254359Sroberto l_fp offset; 3983182007Sroberto double ppsphaseadjust = parse->ppsphaseadjust; 398454359Sroberto 3985182007Sroberto#ifdef HAVE_PPSAPI 398654359Sroberto /* 3987182007Sroberto * set fudge = 0.0 if already included in PPS time stamps 3988182007Sroberto */ 3989280849Scy if (parse->atom.pps_params.mode & (PPS_OFFSETCLEAR|PPS_OFFSETASSERT)) 3990182007Sroberto { 3991182007Sroberto ppsphaseadjust = 0.0; 3992182007Sroberto } 3993182007Sroberto#endif 3994182007Sroberto 3995182007Sroberto /* 399654359Sroberto * we have a PPS signal - much better than the RS232 stuff (we hope) 399754359Sroberto */ 399854359Sroberto offset = parsetime->parse_ptime.fp; 399954359Sroberto 400054359Sroberto#ifdef DEBUG 400154359Sroberto if (debug > 3) 400254359Sroberto printf("PARSE receiver #%d: PPStime %s\n", 400354359Sroberto CLK_UNIT(parse->peer), 400454359Sroberto prettydate(&offset)); 400554359Sroberto#endif 400654359Sroberto if (PARSE_TIMECODE(parsetime->parse_state)) 400754359Sroberto { 4008280849Scy if (M_ISGEQ(off.l_i, off.l_uf, -1, 0x80000000) && 4009280849Scy M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_uf)) 401054359Sroberto { 4011182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 401254359Sroberto 401354359Sroberto /* 401454359Sroberto * RS232 offsets within [-0.5..0.5[ - take PPS offsets 401554359Sroberto */ 401654359Sroberto 401754359Sroberto if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND) 401854359Sroberto { 401954359Sroberto reftime = off = offset; 4020280849Scy if (reftime.l_uf & 0x80000000) 402154359Sroberto reftime.l_ui++; 402254359Sroberto reftime.l_uf = 0; 402356746Sroberto 402454359Sroberto 402554359Sroberto /* 402654359Sroberto * implied on second offset 402754359Sroberto */ 402854359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4029280849Scy off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 403054359Sroberto } 403154359Sroberto else 403254359Sroberto { 403354359Sroberto /* 403454359Sroberto * time code describes pulse 403554359Sroberto */ 403654359Sroberto reftime = off = parsetime->parse_time.fp; 403754359Sroberto 403854359Sroberto L_SUB(&off, &offset); /* true offset */ 403954359Sroberto } 404054359Sroberto } 404154359Sroberto /* 404254359Sroberto * take RS232 offset when PPS when out of bounds 404354359Sroberto */ 404454359Sroberto } 404554359Sroberto else 404654359Sroberto { 4047182007Sroberto fudge = ppsphaseadjust; /* pick PPS fudge factor */ 404854359Sroberto /* 404954359Sroberto * Well, no time code to guide us - assume on second pulse 405054359Sroberto * and pray, that we are within [-0.5..0.5[ 405154359Sroberto */ 405254359Sroberto off = offset; 405354359Sroberto reftime = offset; 4054280849Scy if (reftime.l_uf & 0x80000000) 405554359Sroberto reftime.l_ui++; 405654359Sroberto reftime.l_uf = 0; 405754359Sroberto /* 405854359Sroberto * implied on second offset 405954359Sroberto */ 406054359Sroberto off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */ 4061280849Scy off.l_i = (off.l_uf & 0x80000000) ? -1 : 0; /* sign extend */ 406254359Sroberto } 406354359Sroberto } 406454359Sroberto else 406554359Sroberto { 406654359Sroberto if (!PARSE_TIMECODE(parsetime->parse_state)) 406754359Sroberto { 406854359Sroberto /* 406954359Sroberto * Well, no PPS, no TIMECODE, no more work ... 407054359Sroberto */ 407154359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 407254359Sroberto parse->parse_type->cl_message) 407354359Sroberto parse->parse_type->cl_message(parse, parsetime); 407454359Sroberto return; 407554359Sroberto } 407654359Sroberto } 407754359Sroberto 407854359Sroberto#ifdef DEBUG 407954359Sroberto if (debug > 3) 408054359Sroberto printf("PARSE receiver #%d: Reftime %s, Recvtime %s - final offset %s\n", 408154359Sroberto CLK_UNIT(parse->peer), 408254359Sroberto prettydate(&reftime), 408354359Sroberto prettydate(&rectime), 408454359Sroberto lfptoa(&off,6)); 408554359Sroberto#endif 408654359Sroberto 408754359Sroberto 408854359Sroberto rectime = reftime; 408954359Sroberto L_SUB(&rectime, &off); /* just to keep the ntp interface happy */ 409054359Sroberto 409154359Sroberto#ifdef DEBUG 409254359Sroberto if (debug > 3) 409354359Sroberto printf("PARSE receiver #%d: calculated Reftime %s, Recvtime %s\n", 409454359Sroberto CLK_UNIT(parse->peer), 409554359Sroberto prettydate(&reftime), 409654359Sroberto prettydate(&rectime)); 409754359Sroberto#endif 409854359Sroberto 409954359Sroberto if ((parsetime->parse_status & CVT_ADDITIONAL) && 410054359Sroberto parse->parse_type->cl_message) 410154359Sroberto parse->parse_type->cl_message(parse, parsetime); 410254359Sroberto 410354359Sroberto if (PARSE_SYNC(parsetime->parse_state)) 410454359Sroberto { 410554359Sroberto /* 410654359Sroberto * log OK status 410754359Sroberto */ 410854359Sroberto parse_event(parse, CEVNT_NOMINAL); 410954359Sroberto } 411054359Sroberto 411154359Sroberto clear_err(parse, ERR_BADIO); 411254359Sroberto clear_err(parse, ERR_BADDATA); 411354359Sroberto clear_err(parse, ERR_NODATA); 411454359Sroberto clear_err(parse, ERR_INTERNAL); 411554359Sroberto 411654359Sroberto /* 411754359Sroberto * and now stick it into the clock machine 411854359Sroberto * samples are only valid iff lastsync is not too old and 411954359Sroberto * we have seen the clock in sync at least once 412054359Sroberto * after the last time we didn't see an expected data telegram 4121182007Sroberto * at startup being not in sync is also bad just like 4122280849Scy * POWERUP state unless PARSE_F_POWERUPTRUST is set 412354359Sroberto * see the clock states section above for more reasoning 412454359Sroberto */ 4125280849Scy if (((current_time - parse->lastsync) > parse->maxunsync) || 4126280849Scy (parse->lastsync < parse->lastmissed) || 4127182007Sroberto ((parse->lastsync == 0) && !PARSE_SYNC(parsetime->parse_state)) || 4128280849Scy (((parse->parse_type->cl_flags & PARSE_F_POWERUPTRUST) == 0) && 4129280849Scy PARSE_POWERUP(parsetime->parse_state))) 413054359Sroberto { 413154359Sroberto parse->generic->leap = LEAP_NOTINSYNC; 4132182007Sroberto parse->lastsync = 0; /* wait for full sync again */ 413354359Sroberto } 413454359Sroberto else 413554359Sroberto { 413654359Sroberto if (PARSE_LEAPADD(parsetime->parse_state)) 413754359Sroberto { 413854359Sroberto /* 413954359Sroberto * we pick this state also for time code that pass leap warnings 414054359Sroberto * without direction information (as earth is currently slowing 414154359Sroberto * down). 414254359Sroberto */ 414354359Sroberto parse->generic->leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND; 414454359Sroberto } 414554359Sroberto else 414654359Sroberto if (PARSE_LEAPDEL(parsetime->parse_state)) 414754359Sroberto { 414854359Sroberto parse->generic->leap = LEAP_DELSECOND; 414954359Sroberto } 415054359Sroberto else 415154359Sroberto { 415254359Sroberto parse->generic->leap = LEAP_NOWARNING; 415354359Sroberto } 415454359Sroberto } 4155182007Sroberto 4156182007Sroberto if (parse->generic->leap != LEAP_NOTINSYNC) 4157182007Sroberto { 4158182007Sroberto /* 4159182007Sroberto * only good/trusted samples are interesting 4160182007Sroberto */ 4161182007Sroberto#ifdef DEBUG 4162182007Sroberto if (debug > 2) 4163182007Sroberto { 4164182007Sroberto printf("PARSE receiver #%d: refclock_process_offset(reftime=%s, rectime=%s, Fudge=%f)\n", 4165182007Sroberto CLK_UNIT(parse->peer), 4166182007Sroberto prettydate(&reftime), 4167182007Sroberto prettydate(&rectime), 4168182007Sroberto fudge); 4169182007Sroberto } 4170182007Sroberto#endif 4171182007Sroberto parse->generic->lastref = reftime; 4172182007Sroberto 4173182007Sroberto refclock_process_offset(parse->generic, reftime, rectime, fudge); 4174182007Sroberto 4175280849Scy#ifdef HAVE_PPSAPI 4176182007Sroberto /* 4177182007Sroberto * pass PPS information on to PPS clock 4178182007Sroberto */ 4179182007Sroberto if (PARSE_PPS(parsetime->parse_state) && CLK_PPS(parse->peer)) 4180182007Sroberto { 4181280849Scy parse->peer->flags |= FLAG_PPS; 4182182007Sroberto parse_hardpps(parse, PARSE_HARDPPS_ENABLE); 4183182007Sroberto } 4184280849Scy#endif 4185182007Sroberto } else { 4186182007Sroberto parse_hardpps(parse, PARSE_HARDPPS_DISABLE); 4187280849Scy parse->peer->flags &= ~FLAG_PPS; 4188182007Sroberto } 4189182007Sroberto 419054359Sroberto /* 4191182007Sroberto * ready, unless the machine wants a sample or 4192182007Sroberto * we are in fast startup mode (peer->dist > MAXDISTANCE) 419354359Sroberto */ 4194182007Sroberto if (!parse->pollneeddata && parse->peer->disp <= MAXDISTANCE) 419554359Sroberto return; 419654359Sroberto 419754359Sroberto parse->pollneeddata = 0; 419854359Sroberto 4199182007Sroberto parse->timedata.parse_state &= ~(unsigned)(PARSEB_PPS|PARSEB_S_PPS); 4200182007Sroberto 420154359Sroberto refclock_receive(parse->peer); 420254359Sroberto} 420356746Sroberto 420454359Sroberto/**=========================================================================== 420554359Sroberto ** special code for special clocks 420654359Sroberto **/ 420754359Sroberto 420854359Srobertostatic void 420954359Srobertomk_utcinfo( 421054359Sroberto char *t, 421154359Sroberto int wnt, 421254359Sroberto int wnlsf, 421354359Sroberto int dn, 421454359Sroberto int dtls, 4215182007Sroberto int dtlsf, 4216182007Sroberto int size 421754359Sroberto ) 421854359Sroberto{ 421954359Sroberto l_fp leapdate; 4220182007Sroberto char *start = t; 422154359Sroberto 4222182007Sroberto snprintf(t, size, "current correction %d sec", dtls); 422354359Sroberto t += strlen(t); 422454359Sroberto 422554359Sroberto if (wnlsf < 990) 422654359Sroberto wnlsf += 1024; 422754359Sroberto 422854359Sroberto if (wnt < 990) 422954359Sroberto wnt += 1024; 423054359Sroberto 423154359Sroberto gpstolfp((unsigned short)wnlsf, (unsigned short)dn, 0, &leapdate); 423254359Sroberto 423354359Sroberto if ((dtlsf != dtls) && 423454359Sroberto ((wnlsf - wnt) < 52)) 423554359Sroberto { 4236182007Sroberto snprintf(t, BUFFER_SIZES(start, t, size), ", next correction %d sec on %s, new GPS-UTC offset %d", 423754359Sroberto dtlsf - dtls, gmprettydate(&leapdate), dtlsf); 423854359Sroberto } 423954359Sroberto else 424054359Sroberto { 4241182007Sroberto snprintf(t, BUFFER_SIZES(start, t, size), ", last correction on %s", 424254359Sroberto gmprettydate(&leapdate)); 424354359Sroberto } 424454359Sroberto} 424554359Sroberto 424654359Sroberto#ifdef CLOCK_MEINBERG 424754359Sroberto/**=========================================================================== 424854359Sroberto ** Meinberg GPS166/GPS167 support 424954359Sroberto **/ 425054359Sroberto 425154359Sroberto/*------------------------------------------------------------ 425254359Sroberto * gps16x_message - process GPS16x messages 425354359Sroberto */ 425454359Srobertostatic void 425554359Srobertogps16x_message( 425654359Sroberto struct parseunit *parse, 425754359Sroberto parsetime_t *parsetime 425854359Sroberto ) 425954359Sroberto{ 4260182007Sroberto if (parse->timedata.parse_msglen && parsetime->parse_msg[0] == SOH) 426154359Sroberto { 426254359Sroberto GPS_MSG_HDR header; 426354359Sroberto unsigned char *bufp = (unsigned char *)parsetime->parse_msg + 1; 426454359Sroberto 426554359Sroberto#ifdef DEBUG 426654359Sroberto if (debug > 2) 426754359Sroberto { 426854359Sroberto char msgbuffer[600]; 426954359Sroberto 427054359Sroberto mkreadable(msgbuffer, sizeof(msgbuffer), (char *)parsetime->parse_msg, parsetime->parse_msglen, 1); 427154359Sroberto printf("PARSE receiver #%d: received message (%d bytes) >%s<\n", 427254359Sroberto CLK_UNIT(parse->peer), 427354359Sroberto parsetime->parse_msglen, 427454359Sroberto msgbuffer); 427554359Sroberto } 427654359Sroberto#endif 427754359Sroberto get_mbg_header(&bufp, &header); 427854359Sroberto if (header.gps_hdr_csum == mbg_csum(parsetime->parse_msg + 1, 6) && 427954359Sroberto (header.gps_len == 0 || 428054359Sroberto (header.gps_len < sizeof(parsetime->parse_msg) && 428154359Sroberto header.gps_data_csum == mbg_csum(bufp, header.gps_len)))) 428254359Sroberto { 428354359Sroberto /* 428454359Sroberto * clean message 428554359Sroberto */ 428654359Sroberto switch (header.gps_cmd) 428754359Sroberto { 428854359Sroberto case GPS_SW_REV: 428954359Sroberto { 429054359Sroberto char buffer[64]; 429154359Sroberto SW_REV gps_sw_rev; 429254359Sroberto 429354359Sroberto get_mbg_sw_rev(&bufp, &gps_sw_rev); 4294182007Sroberto snprintf(buffer, sizeof(buffer), "meinberg_gps_version=\"%x.%02x%s%s\"", 429554359Sroberto (gps_sw_rev.code >> 8) & 0xFF, 429654359Sroberto gps_sw_rev.code & 0xFF, 429754359Sroberto gps_sw_rev.name[0] ? " " : "", 429854359Sroberto gps_sw_rev.name); 4299182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 430054359Sroberto } 430154359Sroberto break; 430254359Sroberto 430354359Sroberto case GPS_STAT: 430454359Sroberto { 430554359Sroberto static struct state 430654359Sroberto { 430754359Sroberto unsigned short flag; /* status flag */ 430854359Sroberto unsigned const char *string; /* bit name */ 430954359Sroberto } states[] = 431054359Sroberto { 431154359Sroberto { TM_ANT_DISCONN, (const unsigned char *)"ANTENNA FAULTY" }, 431254359Sroberto { TM_SYN_FLAG, (const unsigned char *)"NO SYNC SIGNAL" }, 431354359Sroberto { TM_NO_SYNC, (const unsigned char *)"NO SYNC POWERUP" }, 431454359Sroberto { TM_NO_POS, (const unsigned char *)"NO POSITION" }, 431554359Sroberto { 0, (const unsigned char *)"" } 431654359Sroberto }; 431754359Sroberto unsigned short status; 431854359Sroberto struct state *s = states; 431954359Sroberto char buffer[512]; 432054359Sroberto char *p, *b; 432154359Sroberto 432254359Sroberto status = get_lsb_short(&bufp); 4323280849Scy p = b = buffer; 4324280849Scy p = ap(buffer, sizeof(buffer), p, 4325280849Scy "meinberg_gps_status=\"[0x%04x] ", 4326280849Scy status); 432754359Sroberto 432854359Sroberto if (status) 432954359Sroberto { 4330280849Scy b = p; 433154359Sroberto while (s->flag) 433254359Sroberto { 433354359Sroberto if (status & s->flag) 433454359Sroberto { 433554359Sroberto if (p != b) 433654359Sroberto { 4337280849Scy p = ap(buffer, sizeof(buffer), p, ", "); 433854359Sroberto } 433954359Sroberto 4340280849Scy p = ap(buffer, sizeof(buffer), p, "%s", (const char *)s->string); 434154359Sroberto } 434254359Sroberto s++; 434354359Sroberto } 4344280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 434554359Sroberto } 434654359Sroberto else 434754359Sroberto { 4348280849Scy p = ap(buffer, sizeof(buffer), p, "<OK>\""); 434954359Sroberto } 435054359Sroberto 4351182007Sroberto set_var(&parse->kv, buffer, strlen(buffer)+1, RO|DEF); 435254359Sroberto } 435354359Sroberto break; 435454359Sroberto 435554359Sroberto case GPS_POS_XYZ: 435654359Sroberto { 435754359Sroberto XYZ xyz; 435854359Sroberto char buffer[256]; 435954359Sroberto 436054359Sroberto get_mbg_xyz(&bufp, xyz); 4361182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(XYZ)=\"%s m, %s m, %s m\"", 436254359Sroberto mfptoa(xyz[XP].l_ui, xyz[XP].l_uf, 1), 436354359Sroberto mfptoa(xyz[YP].l_ui, xyz[YP].l_uf, 1), 436454359Sroberto mfptoa(xyz[ZP].l_ui, xyz[ZP].l_uf, 1)); 436554359Sroberto 436654359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 436754359Sroberto } 436854359Sroberto break; 436954359Sroberto 437054359Sroberto case GPS_POS_LLA: 437154359Sroberto { 437254359Sroberto LLA lla; 437354359Sroberto char buffer[256]; 437454359Sroberto 437554359Sroberto get_mbg_lla(&bufp, lla); 437654359Sroberto 4377182007Sroberto snprintf(buffer, sizeof(buffer), "gps_position(LLA)=\"%s deg, %s deg, %s m\"", 437854359Sroberto mfptoa(lla[LAT].l_ui, lla[LAT].l_uf, 4), 437954359Sroberto mfptoa(lla[LON].l_ui, lla[LON].l_uf, 4), 438054359Sroberto mfptoa(lla[ALT].l_ui, lla[ALT].l_uf, 1)); 438154359Sroberto 438254359Sroberto set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 438354359Sroberto } 438454359Sroberto break; 438554359Sroberto 438654359Sroberto case GPS_TZDL: 438754359Sroberto break; 438854359Sroberto 438954359Sroberto case GPS_PORT_PARM: 439054359Sroberto break; 439154359Sroberto 439254359Sroberto case GPS_SYNTH: 439354359Sroberto break; 439454359Sroberto 439554359Sroberto case GPS_ANT_INFO: 439654359Sroberto { 439754359Sroberto ANT_INFO antinfo; 4398182007Sroberto char buffer[512]; 4399280849Scy char *p, *q; 440054359Sroberto 440154359Sroberto get_mbg_antinfo(&bufp, &antinfo); 4402280849Scy p = buffer; 4403280849Scy p = ap(buffer, sizeof(buffer), p, "meinberg_antenna_status=\""); 440454359Sroberto switch (antinfo.status) 440554359Sroberto { 440654359Sroberto case ANT_INVALID: 4407280849Scy p = ap(buffer, sizeof(buffer), 4408280849Scy p, "<OK>"); 440954359Sroberto break; 441054359Sroberto 441154359Sroberto case ANT_DISCONN: 4412280849Scy q = ap(buffer, sizeof(buffer), 4413280849Scy p, "DISCONNECTED since "); 441454359Sroberto NLOG(NLOG_CLOCKSTATUS) 441554359Sroberto ERR(ERR_BADSTATUS) 441654359Sroberto msyslog(LOG_ERR,"PARSE receiver #%d: ANTENNA FAILURE: %s", 441754359Sroberto CLK_UNIT(parse->peer), p); 441854359Sroberto 4419280849Scy p = q; 4420182007Sroberto mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 442154359Sroberto *p = '\0'; 442254359Sroberto break; 442354359Sroberto 442454359Sroberto case ANT_RECONN: 4425280849Scy p = ap(buffer, sizeof(buffer), 4426280849Scy p, "RECONNECTED on "); 4427182007Sroberto mbg_tm_str(&p, &antinfo.tm_reconn, BUFFER_SIZE(buffer, p)); 4428280849Scy p = ap(buffer, sizeof(buffer), 4429280849Scy p, ", reconnect clockoffset %c%ld.%07ld s, disconnect time ", 443054359Sroberto (antinfo.delta_t < 0) ? '-' : '+', 443154359Sroberto ABS(antinfo.delta_t) / 10000, 443254359Sroberto ABS(antinfo.delta_t) % 10000); 4433182007Sroberto mbg_tm_str(&p, &antinfo.tm_disconn, BUFFER_SIZE(buffer, p)); 443454359Sroberto *p = '\0'; 443554359Sroberto break; 443654359Sroberto 443754359Sroberto default: 4438280849Scy p = ap(buffer, sizeof(buffer), 4439280849Scy p, "bad status 0x%04x", 4440280849Scy antinfo.status); 444154359Sroberto break; 444254359Sroberto } 444354359Sroberto 4444280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 444554359Sroberto 4446280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 444754359Sroberto } 444854359Sroberto break; 444954359Sroberto 445054359Sroberto case GPS_UCAP: 445154359Sroberto break; 445254359Sroberto 445354359Sroberto case GPS_CFGH: 445454359Sroberto { 445554359Sroberto CFGH cfgh; 4456182007Sroberto char buffer[512]; 4457182007Sroberto char *p; 445854359Sroberto 445954359Sroberto get_mbg_cfgh(&bufp, &cfgh); 446054359Sroberto if (cfgh.valid) 446154359Sroberto { 446254359Sroberto int i; 446354359Sroberto 446454359Sroberto p = buffer; 4465280849Scy p = ap(buffer, sizeof(buffer), 4466280849Scy p, "gps_tot_51=\""); 4467182007Sroberto mbg_tgps_str(&p, &cfgh.tot_51, BUFFER_SIZE(buffer, p)); 4468280849Scy p = ap(buffer, sizeof(buffer), 4469280849Scy p, "\""); 4470280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO); 447154359Sroberto 447254359Sroberto p = buffer; 4473280849Scy p = ap(buffer, sizeof(buffer), 4474280849Scy p, "gps_tot_63=\""); 4475182007Sroberto mbg_tgps_str(&p, &cfgh.tot_63, BUFFER_SIZE(buffer, p)); 4476280849Scy p = ap(buffer, sizeof(buffer), 4477280849Scy p, "\""); 4478280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO); 447954359Sroberto 448054359Sroberto p = buffer; 4481280849Scy p = ap(buffer, sizeof(buffer), 4482280849Scy p, "gps_t0a=\""); 4483182007Sroberto mbg_tgps_str(&p, &cfgh.t0a, BUFFER_SIZE(buffer, p)); 4484280849Scy p = ap(buffer, sizeof(buffer), 4485280849Scy p, "\""); 4486280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO); 448754359Sroberto 4488182007Sroberto for (i = MIN_SVNO; i < MAX_SVNO; i++) 448954359Sroberto { 449054359Sroberto p = buffer; 4491280849Scy p = ap(buffer, sizeof(buffer), p, "gps_cfg[%d]=\"[0x%x] ", i, cfgh.cfg[i]); 449254359Sroberto switch (cfgh.cfg[i] & 0x7) 449354359Sroberto { 449454359Sroberto case 0: 4495280849Scy p = ap(buffer, sizeof(buffer), p, "BLOCK I"); 449654359Sroberto break; 449754359Sroberto case 1: 4498280849Scy p = ap(buffer, sizeof(buffer), p, "BLOCK II"); 449954359Sroberto break; 450054359Sroberto default: 4501280849Scy p = ap(buffer, sizeof(buffer), p, "bad CFG"); 450254359Sroberto break; 450354359Sroberto } 4504280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 4505280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO); 450654359Sroberto 450754359Sroberto p = buffer; 4508280849Scy p = ap(buffer, sizeof(buffer), p, "gps_health[%d]=\"[0x%x] ", i, cfgh.health[i]); 450954359Sroberto switch ((cfgh.health[i] >> 5) & 0x7 ) 451054359Sroberto { 451154359Sroberto case 0: 4512280849Scy p = ap(buffer, sizeof(buffer), p, "OK;"); 451354359Sroberto break; 451454359Sroberto case 1: 4515280849Scy p = ap(buffer, sizeof(buffer), p, "PARITY;"); 451654359Sroberto break; 451754359Sroberto case 2: 4518280849Scy p = ap(buffer, sizeof(buffer), p, "TLM/HOW;"); 451954359Sroberto break; 452054359Sroberto case 3: 4521280849Scy p = ap(buffer, sizeof(buffer), p, "Z-COUNT;"); 452254359Sroberto break; 452354359Sroberto case 4: 4524280849Scy p = ap(buffer, sizeof(buffer), p, "SUBFRAME 1,2,3;"); 452554359Sroberto break; 452654359Sroberto case 5: 4527280849Scy p = ap(buffer, sizeof(buffer), p, "SUBFRAME 4,5;"); 452854359Sroberto break; 452954359Sroberto case 6: 4530280849Scy p = ap(buffer, sizeof(buffer), p, "UPLOAD BAD;"); 453154359Sroberto break; 453254359Sroberto case 7: 4533280849Scy p = ap(buffer, sizeof(buffer), p, "DATA BAD;"); 453454359Sroberto break; 453554359Sroberto } 453654359Sroberto 453754359Sroberto switch (cfgh.health[i] & 0x1F) 453854359Sroberto { 453954359Sroberto case 0: 4540280849Scy p = ap(buffer, sizeof(buffer), p, "SIGNAL OK"); 454154359Sroberto break; 454254359Sroberto case 0x1C: 4543280849Scy p = ap(buffer, sizeof(buffer), p, "SV TEMP OUT"); 454454359Sroberto break; 454554359Sroberto case 0x1D: 4546280849Scy p = ap(buffer, sizeof(buffer), p, "SV WILL BE TEMP OUT"); 454754359Sroberto break; 454854359Sroberto case 0x1E: 454954359Sroberto break; 455054359Sroberto case 0x1F: 4551280849Scy p = ap(buffer, sizeof(buffer), p, "MULTIPLE ERRS"); 455254359Sroberto break; 455354359Sroberto default: 4554280849Scy p = ap(buffer, sizeof(buffer), p, "TRANSMISSION PROBLEMS"); 455554359Sroberto break; 455654359Sroberto } 455754359Sroberto 4558280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 4559280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO); 456054359Sroberto } 456154359Sroberto } 456254359Sroberto } 456354359Sroberto break; 456454359Sroberto 456554359Sroberto case GPS_ALM: 456654359Sroberto break; 456754359Sroberto 456854359Sroberto case GPS_EPH: 456954359Sroberto break; 457054359Sroberto 457154359Sroberto case GPS_UTC: 457254359Sroberto { 457354359Sroberto UTC utc; 457454359Sroberto char buffer[512]; 457554359Sroberto char *p; 457654359Sroberto 457754359Sroberto p = buffer; 457854359Sroberto 457954359Sroberto get_mbg_utc(&bufp, &utc); 458054359Sroberto 458154359Sroberto if (utc.valid) 458254359Sroberto { 4583280849Scy p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\""); 4584280849Scy mk_utcinfo(p, utc.t0t.wn, utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf, BUFFER_SIZE(buffer, p)); 458554359Sroberto p += strlen(p); 4586280849Scy p = ap(buffer, sizeof(buffer), p, "\""); 458754359Sroberto } 458854359Sroberto else 458954359Sroberto { 4590280849Scy p = ap(buffer, sizeof(buffer), p, "gps_utc_correction=\"<NO UTC DATA>\""); 459154359Sroberto } 4592280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 459354359Sroberto } 459454359Sroberto break; 459554359Sroberto 459654359Sroberto case GPS_IONO: 459754359Sroberto break; 459854359Sroberto 459954359Sroberto case GPS_ASCII_MSG: 460054359Sroberto { 460154359Sroberto ASCII_MSG gps_ascii_msg; 460254359Sroberto char buffer[128]; 460354359Sroberto 460454359Sroberto get_mbg_ascii_msg(&bufp, &gps_ascii_msg); 460554359Sroberto 460654359Sroberto if (gps_ascii_msg.valid) 460754359Sroberto { 460854359Sroberto char buffer1[128]; 460954359Sroberto mkreadable(buffer1, sizeof(buffer1), gps_ascii_msg.s, strlen(gps_ascii_msg.s), (int)0); 461054359Sroberto 4611182007Sroberto snprintf(buffer, sizeof(buffer), "gps_message=\"%s\"", buffer1); 461254359Sroberto } 461354359Sroberto else 4614280849Scy snprintf(buffer, sizeof(buffer), "gps_message=<NONE>"); 461554359Sroberto 4616280849Scy set_var(&parse->kv, buffer, sizeof(buffer), RO|DEF); 461754359Sroberto } 461854359Sroberto 461954359Sroberto break; 462054359Sroberto 462154359Sroberto default: 462254359Sroberto break; 462354359Sroberto } 462454359Sroberto } 462554359Sroberto else 462654359Sroberto { 462754359Sroberto 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)", 462854359Sroberto CLK_UNIT(parse->peer), 462954359Sroberto header.gps_hdr_csum, mbg_csum(parsetime->parse_msg + 1, 6), 463054359Sroberto header.gps_len, 463154359Sroberto header.gps_data_csum, mbg_csum(bufp, (unsigned)((header.gps_len < sizeof(parsetime->parse_msg)) ? header.gps_len : 0))); 463254359Sroberto } 463354359Sroberto } 463454359Sroberto 463554359Sroberto return; 463654359Sroberto} 463754359Sroberto 463854359Sroberto/*------------------------------------------------------------ 463954359Sroberto * gps16x_poll - query the reciver peridically 464054359Sroberto */ 464154359Srobertostatic void 464254359Srobertogps16x_poll( 464354359Sroberto struct peer *peer 464454359Sroberto ) 464554359Sroberto{ 4646280849Scy struct parseunit *parse = peer->procptr->unitptr; 464754359Sroberto 464854359Sroberto static GPS_MSG_HDR sequence[] = 464954359Sroberto { 465054359Sroberto { GPS_SW_REV, 0, 0, 0 }, 465154359Sroberto { GPS_STAT, 0, 0, 0 }, 465254359Sroberto { GPS_UTC, 0, 0, 0 }, 465354359Sroberto { GPS_ASCII_MSG, 0, 0, 0 }, 465454359Sroberto { GPS_ANT_INFO, 0, 0, 0 }, 465554359Sroberto { GPS_CFGH, 0, 0, 0 }, 465654359Sroberto { GPS_POS_XYZ, 0, 0, 0 }, 465754359Sroberto { GPS_POS_LLA, 0, 0, 0 }, 465854359Sroberto { (unsigned short)~0, 0, 0, 0 } 465954359Sroberto }; 4660280849Scy 466154359Sroberto int rtc; 466254359Sroberto unsigned char cmd_buffer[64]; 466354359Sroberto unsigned char *outp = cmd_buffer; 466454359Sroberto GPS_MSG_HDR *header; 466554359Sroberto 466654359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 466754359Sroberto { 4668280849Scy parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 466954359Sroberto } 467054359Sroberto 467154359Sroberto if (sequence[parse->localstate].gps_cmd == (unsigned short)~0) 467254359Sroberto parse->localstate = 0; 467354359Sroberto 467454359Sroberto header = sequence + parse->localstate++; 467554359Sroberto 467654359Sroberto *outp++ = SOH; /* start command */ 467754359Sroberto 467854359Sroberto put_mbg_header(&outp, header); 467954359Sroberto outp = cmd_buffer + 1; 468054359Sroberto 468154359Sroberto header->gps_hdr_csum = (short)mbg_csum(outp, 6); 468254359Sroberto put_mbg_header(&outp, header); 468354359Sroberto 468454359Sroberto#ifdef DEBUG 468554359Sroberto if (debug > 2) 468654359Sroberto { 468754359Sroberto char buffer[128]; 468854359Sroberto 468954359Sroberto mkreadable(buffer, sizeof(buffer), (char *)cmd_buffer, (unsigned)(outp - cmd_buffer), 1); 469054359Sroberto printf("PARSE receiver #%d: transmitted message #%ld (%d bytes) >%s<\n", 469154359Sroberto CLK_UNIT(parse->peer), 469254359Sroberto parse->localstate - 1, 469354359Sroberto (int)(outp - cmd_buffer), 469454359Sroberto buffer); 469554359Sroberto } 469654359Sroberto#endif 469754359Sroberto 469854359Sroberto rtc = write(parse->generic->io.fd, cmd_buffer, (unsigned long)(outp - cmd_buffer)); 469954359Sroberto 470054359Sroberto if (rtc < 0) 470154359Sroberto { 470254359Sroberto ERR(ERR_BADIO) 470354359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: gps16x_poll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 470454359Sroberto } 470554359Sroberto else 470654359Sroberto if (rtc != outp - cmd_buffer) 470754359Sroberto { 470854359Sroberto ERR(ERR_BADIO) 470954359Sroberto 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)); 471054359Sroberto } 471154359Sroberto 471254359Sroberto clear_err(parse, ERR_BADIO); 471354359Sroberto return; 471454359Sroberto} 471554359Sroberto 471654359Sroberto/*-------------------------------------------------- 471754359Sroberto * init routine - setup timer 471854359Sroberto */ 471954359Srobertostatic int 472054359Srobertogps16x_poll_init( 472154359Sroberto struct parseunit *parse 472254359Sroberto ) 472354359Sroberto{ 472454359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 472554359Sroberto { 4726280849Scy parse->peer->procptr->action = gps16x_poll; 472754359Sroberto gps16x_poll(parse->peer); 472854359Sroberto } 472954359Sroberto 473054359Sroberto return 0; 473154359Sroberto} 473254359Sroberto 473354359Sroberto#else 473454359Srobertostatic void 473554359Srobertogps16x_message( 473654359Sroberto struct parseunit *parse, 473754359Sroberto parsetime_t *parsetime 473854359Sroberto ) 473954359Sroberto{} 474054359Srobertostatic int 474154359Srobertogps16x_poll_init( 474254359Sroberto struct parseunit *parse 474354359Sroberto ) 474454359Sroberto{ 474554359Sroberto return 1; 474654359Sroberto} 474754359Sroberto#endif /* CLOCK_MEINBERG */ 474854359Sroberto 474954359Sroberto/**=========================================================================== 475054359Sroberto ** clock polling support 475154359Sroberto **/ 475254359Sroberto 475354359Sroberto/*-------------------------------------------------- 475454359Sroberto * direct poll routine 475554359Sroberto */ 475654359Srobertostatic void 475754359Srobertopoll_dpoll( 475854359Sroberto struct parseunit *parse 475954359Sroberto ) 476054359Sroberto{ 476154359Sroberto int rtc; 476254359Sroberto const char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string; 476354359Sroberto int ct = ((poll_info_t *)parse->parse_type->cl_data)->count; 476454359Sroberto 476554359Sroberto rtc = write(parse->generic->io.fd, ps, (unsigned long)ct); 476654359Sroberto if (rtc < 0) 476754359Sroberto { 476854359Sroberto ERR(ERR_BADIO) 476954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 477054359Sroberto } 477154359Sroberto else 477254359Sroberto if (rtc != ct) 477354359Sroberto { 477454359Sroberto ERR(ERR_BADIO) 477554359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CLK_UNIT(parse->peer), rtc, ct); 477654359Sroberto } 477754359Sroberto clear_err(parse, ERR_BADIO); 477854359Sroberto} 477954359Sroberto 478054359Sroberto/*-------------------------------------------------- 478154359Sroberto * periodic poll routine 478254359Sroberto */ 478354359Srobertostatic void 478454359Srobertopoll_poll( 478554359Sroberto struct peer *peer 478654359Sroberto ) 478754359Sroberto{ 4788280849Scy struct parseunit *parse = peer->procptr->unitptr; 478954359Sroberto 479054359Sroberto if (parse->parse_type->cl_poll) 479154359Sroberto parse->parse_type->cl_poll(parse); 479254359Sroberto 479354359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 479454359Sroberto { 4795280849Scy parse->peer->procptr->nextaction = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate; 479654359Sroberto } 479754359Sroberto} 479854359Sroberto 479954359Sroberto/*-------------------------------------------------- 480054359Sroberto * init routine - setup timer 480154359Sroberto */ 480254359Srobertostatic int 480354359Srobertopoll_init( 480454359Sroberto struct parseunit *parse 480554359Sroberto ) 480654359Sroberto{ 480754359Sroberto if (((poll_info_t *)parse->parse_type->cl_data)->rate) 480854359Sroberto { 4809280849Scy parse->peer->procptr->action = poll_poll; 481054359Sroberto poll_poll(parse->peer); 481154359Sroberto } 481254359Sroberto 481354359Sroberto return 0; 481454359Sroberto} 481556746Sroberto 481654359Sroberto/**=========================================================================== 481754359Sroberto ** Trimble support 481854359Sroberto **/ 481954359Sroberto 482054359Sroberto/*------------------------------------------------------------- 482154359Sroberto * trimble TAIP init routine - setup EOL and then do poll_init. 482254359Sroberto */ 482354359Srobertostatic int 482454359Srobertotrimbletaip_init( 482554359Sroberto struct parseunit *parse 482654359Sroberto ) 482754359Sroberto{ 482854359Sroberto#ifdef HAVE_TERMIOS 482954359Sroberto struct termios tio; 483054359Sroberto#endif 483154359Sroberto#ifdef HAVE_SYSV_TTYS 483254359Sroberto struct termio tio; 483354359Sroberto#endif 483454359Sroberto /* 483554359Sroberto * configure terminal line for trimble receiver 483654359Sroberto */ 483754359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 483854359Sroberto { 483954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 484054359Sroberto return 0; 484154359Sroberto } 484254359Sroberto else 484354359Sroberto { 484454359Sroberto tio.c_cc[VEOL] = TRIMBLETAIP_EOL; 484554359Sroberto 484654359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 484754359Sroberto { 484854359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tio): %m", CLK_UNIT(parse->peer)); 484954359Sroberto return 0; 485054359Sroberto } 485154359Sroberto } 485254359Sroberto return poll_init(parse); 485354359Sroberto} 485454359Sroberto 485554359Sroberto/*-------------------------------------------------- 485654359Sroberto * trimble TAIP event routine - reset receiver upon data format trouble 485754359Sroberto */ 485854359Srobertostatic const char *taipinit[] = { 485954359Sroberto ">FPV00000000<", 486054359Sroberto ">SRM;ID_FLAG=F;CS_FLAG=T;EC_FLAG=F;FR_FLAG=T;CR_FLAG=F<", 486154359Sroberto ">FTM00020001<", 486254359Sroberto (char *)0 486354359Sroberto}; 486454359Sroberto 486554359Srobertostatic void 486654359Srobertotrimbletaip_event( 486754359Sroberto struct parseunit *parse, 486854359Sroberto int event 486954359Sroberto ) 487054359Sroberto{ 487154359Sroberto switch (event) 487254359Sroberto { 487354359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 487454359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 487554359Sroberto { 487654359Sroberto const char **iv; 487754359Sroberto 487854359Sroberto iv = taipinit; 487954359Sroberto while (*iv) 488054359Sroberto { 488154359Sroberto int rtc = write(parse->generic->io.fd, *iv, strlen(*iv)); 488254359Sroberto if (rtc < 0) 488354359Sroberto { 488454359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 488554359Sroberto return; 488654359Sroberto } 488754359Sroberto else 488854359Sroberto { 4889280849Scy if (rtc != (int)strlen(*iv)) 489054359Sroberto { 489154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: failed to send cmd incomplete (%d of %d bytes sent)", 489254359Sroberto CLK_UNIT(parse->peer), rtc, (int)strlen(*iv)); 489354359Sroberto return; 489454359Sroberto } 489554359Sroberto } 489654359Sroberto iv++; 489754359Sroberto } 489854359Sroberto 489954359Sroberto NLOG(NLOG_CLOCKINFO) 490054359Sroberto ERR(ERR_BADIO) 490154359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_event: RECEIVER INITIALIZED", 490254359Sroberto CLK_UNIT(parse->peer)); 490354359Sroberto } 490454359Sroberto break; 490554359Sroberto 490654359Sroberto default: /* ignore */ 490754359Sroberto break; 490854359Sroberto } 490954359Sroberto} 491054359Sroberto 491154359Sroberto/* 491254359Sroberto * This driver supports the Trimble SVee Six Plus GPS receiver module. 491354359Sroberto * It should support other Trimble receivers which use the Trimble Standard 491454359Sroberto * Interface Protocol (see below). 491554359Sroberto * 491654359Sroberto * The module has a serial I/O port for command/data and a 1 pulse-per-second 491754359Sroberto * output, about 1 microsecond wide. The leading edge of the pulse is 491854359Sroberto * coincident with the change of the GPS second. This is the same as 491954359Sroberto * the change of the UTC second +/- ~1 microsecond. Some other clocks 492054359Sroberto * specifically use a feature in the data message as a timing reference, but 492154359Sroberto * the SVee Six Plus does not do this. In fact there is considerable jitter 492254359Sroberto * on the timing of the messages, so this driver only supports the use 492354359Sroberto * of the PPS pulse for accurate timing. Where it is determined that 492454359Sroberto * the offset is way off, when first starting up ntpd for example, 492554359Sroberto * the timing of the data stream is used until the offset becomes low enough 492656746Sroberto * (|offset| < CLOCK_MAX), at which point the pps offset is used. 492754359Sroberto * 492854359Sroberto * It can use either option for receiving PPS information - the 'ppsclock' 492954359Sroberto * stream pushed onto the serial data interface to timestamp the Carrier 493054359Sroberto * Detect interrupts, where the 1PPS connects to the CD line. This only 493154359Sroberto * works on SunOS 4.1.x currently. To select this, define PPSPPS in 493254359Sroberto * Config.local. The other option is to use a pulse-stretcher/level-converter 493354359Sroberto * to convert the PPS pulse into a RS232 start pulse & feed this into another 493454359Sroberto * tty port. To use this option, define PPSCLK in Config.local. The pps input, 493554359Sroberto * by whichever method, is handled in ntp_loopfilter.c 493654359Sroberto * 493754359Sroberto * The receiver uses a serial message protocol called Trimble Standard 493854359Sroberto * Interface Protocol (it can support others but this driver only supports 493954359Sroberto * TSIP). Messages in this protocol have the following form: 494054359Sroberto * 494154359Sroberto * <DLE><id> ... <data> ... <DLE><ETX> 494254359Sroberto * 494354359Sroberto * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled 494454359Sroberto * on transmission and compressed back to one on reception. Otherwise 494554359Sroberto * the values of data bytes can be anything. The serial interface is RS-422 494654359Sroberto * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits 494754359Sroberto * in total!), and 1 stop bit. The protocol supports byte, integer, single, 494854359Sroberto * and double datatypes. Integers are two bytes, sent most significant first. 494954359Sroberto * Singles are IEEE754 single precision floating point numbers (4 byte) sent 495054359Sroberto * sign & exponent first. Doubles are IEEE754 double precision floating point 495154359Sroberto * numbers (8 byte) sent sign & exponent first. 495254359Sroberto * The receiver supports a large set of messages, only a small subset of 495354359Sroberto * which are used here. From driver to receiver the following are used: 495454359Sroberto * 495554359Sroberto * ID Description 495654359Sroberto * 495754359Sroberto * 21 Request current time 495854359Sroberto * 22 Mode Select 495954359Sroberto * 2C Set/Request operating parameters 496054359Sroberto * 2F Request UTC info 496154359Sroberto * 35 Set/Request I/O options 496254359Sroberto 496354359Sroberto * From receiver to driver the following are recognised: 496454359Sroberto * 496554359Sroberto * ID Description 496654359Sroberto * 496754359Sroberto * 41 GPS Time 496854359Sroberto * 44 Satellite selection, PDOP, mode 496954359Sroberto * 46 Receiver health 497054359Sroberto * 4B Machine code/status 497154359Sroberto * 4C Report operating parameters (debug only) 497254359Sroberto * 4F UTC correction data (used to get leap second warnings) 497354359Sroberto * 55 I/O options (debug only) 497454359Sroberto * 497554359Sroberto * All others are accepted but ignored. 497654359Sroberto * 497754359Sroberto */ 497854359Sroberto 497954359Sroberto#define PI 3.1415926535898 /* lots of sig figs */ 498054359Sroberto#define D2R PI/180.0 498154359Sroberto 498254359Sroberto/*------------------------------------------------------------------- 498354359Sroberto * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command 498454359Sroberto * interface to the receiver. 498554359Sroberto * 498654359Sroberto * CAVEAT: the sendflt, sendint routines are byte order dependend and 498754359Sroberto * float implementation dependend - these must be converted to portable 498854359Sroberto * versions ! 498954359Sroberto * 499054359Sroberto * CURRENT LIMITATION: float implementation. This runs only on systems 499154359Sroberto * with IEEE754 floats as native floats 499254359Sroberto */ 499354359Sroberto 499454359Srobertotypedef struct trimble 499554359Sroberto{ 499654359Sroberto u_long last_msg; /* last message received */ 4997182007Sroberto u_long last_reset; /* last time a reset was issued */ 499854359Sroberto u_char qtracking; /* query tracking status */ 499954359Sroberto u_long ctrack; /* current tracking set */ 500054359Sroberto u_long ltrack; /* last tracking set */ 500154359Sroberto} trimble_t; 500254359Sroberto 500354359Srobertounion uval { 500454359Sroberto u_char bd[8]; 500554359Sroberto int iv; 500654359Sroberto float fv; 500754359Sroberto double dv; 500854359Sroberto}; 500954359Sroberto 501054359Srobertostruct txbuf 501154359Sroberto{ 501254359Sroberto short idx; /* index to first unused byte */ 501354359Sroberto u_char *txt; /* pointer to actual data buffer */ 501454359Sroberto}; 501554359Sroberto 5016280849Scyvoid sendcmd (struct txbuf *buf, int c); 5017280849Scyvoid sendbyte (struct txbuf *buf, int b); 5018280849Scyvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5019280849Scyvoid sendint (struct txbuf *buf, int a); 5020280849Scyvoid sendflt (struct txbuf *buf, double a); 502156746Sroberto 502254359Srobertovoid 502354359Srobertosendcmd( 502454359Sroberto struct txbuf *buf, 502554359Sroberto int c 502654359Sroberto ) 502754359Sroberto{ 502854359Sroberto buf->txt[0] = DLE; 502954359Sroberto buf->txt[1] = (u_char)c; 503054359Sroberto buf->idx = 2; 503154359Sroberto} 503254359Sroberto 5033280849Scyvoid sendcmd (struct txbuf *buf, int c); 5034280849Scyvoid sendbyte (struct txbuf *buf, int b); 5035280849Scyvoid sendetx (struct txbuf *buf, struct parseunit *parse); 5036280849Scyvoid sendint (struct txbuf *buf, int a); 5037280849Scyvoid sendflt (struct txbuf *buf, double a); 5038182007Sroberto 503954359Srobertovoid 504054359Srobertosendbyte( 504154359Sroberto struct txbuf *buf, 504254359Sroberto int b 504354359Sroberto ) 504454359Sroberto{ 504554359Sroberto if (b == DLE) 504654359Sroberto buf->txt[buf->idx++] = DLE; 504754359Sroberto buf->txt[buf->idx++] = (u_char)b; 504854359Sroberto} 504954359Sroberto 505054359Srobertovoid 505154359Srobertosendetx( 505254359Sroberto struct txbuf *buf, 505354359Sroberto struct parseunit *parse 505454359Sroberto ) 505554359Sroberto{ 505654359Sroberto buf->txt[buf->idx++] = DLE; 505754359Sroberto buf->txt[buf->idx++] = ETX; 505854359Sroberto 505954359Sroberto if (write(parse->generic->io.fd, buf->txt, (unsigned long)buf->idx) != buf->idx) 506054359Sroberto { 506154359Sroberto ERR(ERR_BADIO) 506254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CLK_UNIT(parse->peer)); 506354359Sroberto } 506454359Sroberto else 506554359Sroberto { 506654359Sroberto#ifdef DEBUG 506754359Sroberto if (debug > 2) 506854359Sroberto { 506954359Sroberto char buffer[256]; 507054359Sroberto 507154359Sroberto mkreadable(buffer, sizeof(buffer), (char *)buf->txt, (unsigned)buf->idx, 1); 507254359Sroberto printf("PARSE receiver #%d: transmitted message (%d bytes) >%s<\n", 507354359Sroberto CLK_UNIT(parse->peer), 507454359Sroberto buf->idx, buffer); 507554359Sroberto } 507654359Sroberto#endif 507754359Sroberto clear_err(parse, ERR_BADIO); 507854359Sroberto } 507954359Sroberto} 508054359Sroberto 508154359Srobertovoid 508254359Srobertosendint( 508354359Sroberto struct txbuf *buf, 508454359Sroberto int a 508554359Sroberto ) 508654359Sroberto{ 508754359Sroberto /* send 16bit int, msbyte first */ 508854359Sroberto sendbyte(buf, (u_char)((a>>8) & 0xff)); 508954359Sroberto sendbyte(buf, (u_char)(a & 0xff)); 509054359Sroberto} 509154359Sroberto 509254359Srobertovoid 509354359Srobertosendflt( 509454359Sroberto struct txbuf *buf, 509554359Sroberto double a 509654359Sroberto ) 509754359Sroberto{ 509854359Sroberto int i; 509954359Sroberto union uval uval; 510054359Sroberto 510154359Sroberto uval.fv = a; 510254359Sroberto#ifdef WORDS_BIGENDIAN 510354359Sroberto for (i=0; i<=3; i++) 510454359Sroberto#else 510554359Sroberto for (i=3; i>=0; i--) 510654359Sroberto#endif 510754359Sroberto sendbyte(buf, uval.bd[i]); 510854359Sroberto} 510954359Sroberto 511054359Sroberto#define TRIM_POS_OPT 0x13 /* output position with high precision */ 511154359Sroberto#define TRIM_TIME_OPT 0x03 /* use UTC time stamps, on second */ 511254359Sroberto 511354359Sroberto/*-------------------------------------------------- 511454359Sroberto * trimble TSIP setup routine 511554359Sroberto */ 511654359Srobertostatic int 511754359Srobertotrimbletsip_setup( 511854359Sroberto struct parseunit *parse, 511954359Sroberto const char *reason 512056746Sroberto ) 512154359Sroberto{ 512254359Sroberto u_char buffer[256]; 512354359Sroberto struct txbuf buf; 5124182007Sroberto trimble_t *t = parse->localdata; 512554359Sroberto 5126182007Sroberto if (t && t->last_reset && 5127182007Sroberto ((t->last_reset + TRIMBLE_RESET_HOLDOFF) > current_time)) { 5128182007Sroberto return 1; /* not yet */ 5129182007Sroberto } 5130182007Sroberto 5131182007Sroberto if (t) 5132182007Sroberto t->last_reset = current_time; 5133182007Sroberto 513454359Sroberto buf.txt = buffer; 513554359Sroberto 513654359Sroberto sendcmd(&buf, CMD_CVERSION); /* request software versions */ 513756746Sroberto sendetx(&buf, parse); 513856746Sroberto 513954359Sroberto sendcmd(&buf, CMD_COPERPARAM); /* set operating parameters */ 514056746Sroberto sendbyte(&buf, 4); /* static */ 514156746Sroberto sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */ 514256746Sroberto sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */ 514356746Sroberto sendflt(&buf, 12.0); /* PDOP mask = 12 */ 514456746Sroberto sendflt(&buf, 8.0); /* PDOP switch level = 8 */ 514556746Sroberto sendetx(&buf, parse); 514656746Sroberto 514754359Sroberto sendcmd(&buf, CMD_CMODESEL); /* fix mode select */ 5148182007Sroberto sendbyte(&buf, 1); /* time transfer mode */ 514956746Sroberto sendetx(&buf, parse); 515056746Sroberto 515154359Sroberto sendcmd(&buf, CMD_CMESSAGE); /* request system message */ 515256746Sroberto sendetx(&buf, parse); 515356746Sroberto 515454359Sroberto sendcmd(&buf, CMD_CSUPER); /* superpacket fix */ 515556746Sroberto sendbyte(&buf, 0x2); /* binary mode */ 515656746Sroberto sendetx(&buf, parse); 515756746Sroberto 515854359Sroberto sendcmd(&buf, CMD_CIOOPTIONS); /* set I/O options */ 515954359Sroberto sendbyte(&buf, TRIM_POS_OPT); /* position output */ 516054359Sroberto sendbyte(&buf, 0x00); /* no velocity output */ 516154359Sroberto sendbyte(&buf, TRIM_TIME_OPT); /* UTC, compute on seconds */ 516254359Sroberto sendbyte(&buf, 0x00); /* no raw measurements */ 516356746Sroberto sendetx(&buf, parse); 516456746Sroberto 516554359Sroberto sendcmd(&buf, CMD_CUTCPARAM); /* request UTC correction data */ 516654359Sroberto sendetx(&buf, parse); 516754359Sroberto 516854359Sroberto NLOG(NLOG_CLOCKINFO) 516954359Sroberto ERR(ERR_BADIO) 517054359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_setup: RECEIVER RE-INITIALIZED (%s)", CLK_UNIT(parse->peer), reason); 517154359Sroberto 517254359Sroberto return 0; 517354359Sroberto} 517454359Sroberto 517554359Sroberto/*-------------------------------------------------- 517654359Sroberto * TRIMBLE TSIP check routine 517754359Sroberto */ 517854359Srobertostatic void 517954359Srobertotrimble_check( 518054359Sroberto struct peer *peer 518154359Sroberto ) 518254359Sroberto{ 5183280849Scy struct parseunit *parse = peer->procptr->unitptr; 518454359Sroberto trimble_t *t = parse->localdata; 518554359Sroberto u_char buffer[256]; 518654359Sroberto struct txbuf buf; 518754359Sroberto buf.txt = buffer; 518854359Sroberto 518954359Sroberto if (t) 519054359Sroberto { 519154359Sroberto if (current_time > t->last_msg + TRIMBLETSIP_IDLE_TIME) 519254359Sroberto (void)trimbletsip_setup(parse, "message timeout"); 519354359Sroberto } 5194182007Sroberto 519554359Sroberto poll_poll(parse->peer); /* emit query string and re-arm timer */ 519654359Sroberto 5197182007Sroberto if (t && t->qtracking) 519854359Sroberto { 519954359Sroberto u_long oldsats = t->ltrack & ~t->ctrack; 520054359Sroberto 520154359Sroberto t->qtracking = 0; 520254359Sroberto t->ltrack = t->ctrack; 520354359Sroberto 520454359Sroberto if (oldsats) 520554359Sroberto { 520654359Sroberto int i; 520754359Sroberto 5208182007Sroberto for (i = 0; oldsats; i++) { 520954359Sroberto if (oldsats & (1 << i)) 521054359Sroberto { 521154359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 521254359Sroberto sendbyte(&buf, i+1); /* old sat */ 521354359Sroberto sendetx(&buf, parse); 521454359Sroberto } 5215182007Sroberto oldsats &= ~(1 << i); 5216182007Sroberto } 521754359Sroberto } 521854359Sroberto 521954359Sroberto sendcmd(&buf, CMD_CSTATTRACK); 522054359Sroberto sendbyte(&buf, 0x00); /* current tracking set */ 522154359Sroberto sendetx(&buf, parse); 522254359Sroberto } 522354359Sroberto} 522454359Sroberto 522554359Sroberto/*-------------------------------------------------- 522654359Sroberto * TRIMBLE TSIP end routine 522754359Sroberto */ 522854359Srobertostatic void 522954359Srobertotrimbletsip_end( 523054359Sroberto struct parseunit *parse 523154359Sroberto ) 523254359Sroberto{ trimble_t *t = parse->localdata; 523354359Sroberto 523454359Sroberto if (t) 523554359Sroberto { 523654359Sroberto free(t); 5237280849Scy parse->localdata = NULL; 523854359Sroberto } 5239280849Scy parse->peer->procptr->nextaction = 0; 5240280849Scy parse->peer->procptr->action = NULL; 524154359Sroberto} 524254359Sroberto 524354359Sroberto/*-------------------------------------------------- 524454359Sroberto * TRIMBLE TSIP init routine 524554359Sroberto */ 524654359Srobertostatic int 524754359Srobertotrimbletsip_init( 524854359Sroberto struct parseunit *parse 524954359Sroberto ) 525054359Sroberto{ 525154359Sroberto#if defined(VEOL) || defined(VEOL2) 525254359Sroberto#ifdef HAVE_TERMIOS 525354359Sroberto struct termios tio; /* NEEDED FOR A LONG TIME ! */ 525454359Sroberto#endif 525554359Sroberto#ifdef HAVE_SYSV_TTYS 525654359Sroberto struct termio tio; /* NEEDED FOR A LONG TIME ! */ 525754359Sroberto#endif 525854359Sroberto /* 525954359Sroberto * allocate local data area 526054359Sroberto */ 526154359Sroberto if (!parse->localdata) 526254359Sroberto { 526354359Sroberto trimble_t *t; 526454359Sroberto 526554359Sroberto t = (trimble_t *)(parse->localdata = emalloc(sizeof(trimble_t))); 526654359Sroberto 526754359Sroberto if (t) 526854359Sroberto { 526954359Sroberto memset((char *)t, 0, sizeof(trimble_t)); 527054359Sroberto t->last_msg = current_time; 527154359Sroberto } 527254359Sroberto } 527354359Sroberto 5274280849Scy parse->peer->procptr->action = trimble_check; 5275280849Scy parse->peer->procptr->nextaction = current_time; 527654359Sroberto 527754359Sroberto /* 527854359Sroberto * configure terminal line for ICANON mode with VEOL characters 527954359Sroberto */ 528054359Sroberto if (TTY_GETATTR(parse->generic->io.fd, &tio) == -1) 528154359Sroberto { 528254359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcgetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 528354359Sroberto return 0; 528454359Sroberto } 528554359Sroberto else 528654359Sroberto { 528754359Sroberto if ((parse_clockinfo[CLK_TYPE(parse->peer)].cl_lflag & ICANON)) 528854359Sroberto { 528954359Sroberto#ifdef VEOL 529054359Sroberto tio.c_cc[VEOL] = ETX; 529154359Sroberto#endif 529254359Sroberto#ifdef VEOL2 529354359Sroberto tio.c_cc[VEOL2] = DLE; 529454359Sroberto#endif 529556746Sroberto } 529654359Sroberto 529754359Sroberto if (TTY_SETATTR(parse->generic->io.fd, &tio) == -1) 529854359Sroberto { 529954359Sroberto msyslog(LOG_ERR, "PARSE receiver #%d: trimbletsip_init: tcsetattr(%d, &tio): %m", CLK_UNIT(parse->peer), parse->generic->io.fd); 530054359Sroberto return 0; 530154359Sroberto } 530254359Sroberto } 530354359Sroberto#endif 530454359Sroberto return trimbletsip_setup(parse, "initial startup"); 530554359Sroberto} 530654359Sroberto 530754359Sroberto/*------------------------------------------------------------ 530854359Sroberto * trimbletsip_event - handle Trimble events 530954359Sroberto * simple evente handler - attempt to re-initialize receiver 531054359Sroberto */ 531154359Srobertostatic void 531254359Srobertotrimbletsip_event( 531354359Sroberto struct parseunit *parse, 531454359Sroberto int event 531554359Sroberto ) 531654359Sroberto{ 531754359Sroberto switch (event) 531854359Sroberto { 531954359Sroberto case CEVNT_BADREPLY: /* reset on garbled input */ 532054359Sroberto case CEVNT_TIMEOUT: /* reset on no input */ 532154359Sroberto (void)trimbletsip_setup(parse, "event BAD_REPLY/TIMEOUT"); 532254359Sroberto break; 532354359Sroberto 532454359Sroberto default: /* ignore */ 532554359Sroberto break; 532654359Sroberto } 532754359Sroberto} 532854359Sroberto 532954359Sroberto/* 533054359Sroberto * getflt, getint convert fields in the incoming data into the 533154359Sroberto * appropriate type of item 533254359Sroberto * 533354359Sroberto * CAVEAT: these routines are currently definitely byte order dependent 533454359Sroberto * and assume Representation(float) == IEEE754 533554359Sroberto * These functions MUST be converted to portable versions (especially 533654359Sroberto * converting the float representation into ntp_fp formats in order 533754359Sroberto * to avoid floating point operations at all! 533854359Sroberto */ 533954359Sroberto 534054359Srobertostatic float 534154359Srobertogetflt( 534254359Sroberto u_char *bp 534354359Sroberto ) 534454359Sroberto{ 534554359Sroberto union uval uval; 534654359Sroberto 534754359Sroberto#ifdef WORDS_BIGENDIAN 534854359Sroberto uval.bd[0] = *bp++; 534954359Sroberto uval.bd[1] = *bp++; 535054359Sroberto uval.bd[2] = *bp++; 535154359Sroberto uval.bd[3] = *bp; 535254359Sroberto#else /* ! WORDS_BIGENDIAN */ 535354359Sroberto uval.bd[3] = *bp++; 535454359Sroberto uval.bd[2] = *bp++; 535554359Sroberto uval.bd[1] = *bp++; 535654359Sroberto uval.bd[0] = *bp; 535754359Sroberto#endif /* ! WORDS_BIGENDIAN */ 535854359Sroberto return uval.fv; 535954359Sroberto} 536054359Sroberto 536154359Srobertostatic double 536254359Srobertogetdbl( 536354359Sroberto u_char *bp 536454359Sroberto ) 536554359Sroberto{ 536654359Sroberto union uval uval; 536754359Sroberto 536854359Sroberto#ifdef WORDS_BIGENDIAN 536954359Sroberto uval.bd[0] = *bp++; 537054359Sroberto uval.bd[1] = *bp++; 537154359Sroberto uval.bd[2] = *bp++; 537254359Sroberto uval.bd[3] = *bp++; 537354359Sroberto uval.bd[4] = *bp++; 537454359Sroberto uval.bd[5] = *bp++; 537554359Sroberto uval.bd[6] = *bp++; 537654359Sroberto uval.bd[7] = *bp; 537754359Sroberto#else /* ! WORDS_BIGENDIAN */ 537854359Sroberto uval.bd[7] = *bp++; 537954359Sroberto uval.bd[6] = *bp++; 538054359Sroberto uval.bd[5] = *bp++; 538154359Sroberto uval.bd[4] = *bp++; 538254359Sroberto uval.bd[3] = *bp++; 538354359Sroberto uval.bd[2] = *bp++; 538454359Sroberto uval.bd[1] = *bp++; 538554359Sroberto uval.bd[0] = *bp; 538654359Sroberto#endif /* ! WORDS_BIGENDIAN */ 538754359Sroberto return uval.dv; 538854359Sroberto} 538954359Sroberto 539054359Srobertostatic int 539154359Srobertogetshort( 539254359Sroberto unsigned char *p 539354359Sroberto ) 539454359Sroberto{ 539554359Sroberto return get_msb_short(&p); 539654359Sroberto} 539754359Sroberto 539854359Sroberto/*-------------------------------------------------- 539954359Sroberto * trimbletsip_message - process trimble messages 540054359Sroberto */ 540154359Sroberto#define RTOD (180.0 / 3.1415926535898) 540254359Sroberto#define mb(_X_) (buffer[2+(_X_)]) /* shortcut for buffer access */ 540354359Sroberto 540454359Srobertostatic void 540554359Srobertotrimbletsip_message( 540654359Sroberto struct parseunit *parse, 540754359Sroberto parsetime_t *parsetime 540854359Sroberto ) 540954359Sroberto{ 541054359Sroberto unsigned char *buffer = parsetime->parse_msg; 541154359Sroberto unsigned int size = parsetime->parse_msglen; 541254359Sroberto 541354359Sroberto if ((size < 4) || 541454359Sroberto (buffer[0] != DLE) || 541554359Sroberto (buffer[size-1] != ETX) || 541654359Sroberto (buffer[size-2] != DLE)) 541754359Sroberto { 541854359Sroberto#ifdef DEBUG 541954359Sroberto if (debug > 2) { 5420280849Scy size_t i; 542154359Sroberto 542254359Sroberto printf("TRIMBLE BAD packet, size %d:\n ", size); 542354359Sroberto for (i = 0; i < size; i++) { 542454359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 542554359Sroberto if (i%16 == 15) printf("\n\t"); 542654359Sroberto } 542754359Sroberto printf("\n"); 542854359Sroberto } 542954359Sroberto#endif 543054359Sroberto return; 543154359Sroberto } 543254359Sroberto else 543354359Sroberto { 543454359Sroberto int var_flag; 543554359Sroberto trimble_t *tr = parse->localdata; 543654359Sroberto unsigned int cmd = buffer[1]; 543754359Sroberto char pbuffer[200]; 543854359Sroberto char *t = pbuffer; 543954359Sroberto cmd_info_t *s; 544054359Sroberto 544154359Sroberto#ifdef DEBUG 544254359Sroberto if (debug > 3) { 5443280849Scy size_t i; 544454359Sroberto 544554359Sroberto printf("TRIMBLE packet 0x%02x, size %d:\n ", cmd, size); 544654359Sroberto for (i = 0; i < size; i++) { 544754359Sroberto printf ("%2.2x, ", buffer[i]&0xff); 544854359Sroberto if (i%16 == 15) printf("\n\t"); 544954359Sroberto } 545054359Sroberto printf("\n"); 545154359Sroberto } 545254359Sroberto#endif 545354359Sroberto 545454359Sroberto if (tr) 545554359Sroberto tr->last_msg = current_time; 545654359Sroberto 545754359Sroberto s = trimble_convert(cmd, trimble_rcmds); 545854359Sroberto 545954359Sroberto if (s) 546054359Sroberto { 5461280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%s=\"", s->varname); 546254359Sroberto } 546354359Sroberto else 546454359Sroberto { 5465182007Sroberto DPRINTF(1, ("TRIMBLE UNKNOWN COMMAND 0x%02x\n", cmd)); 546654359Sroberto return; 546754359Sroberto } 546854359Sroberto 546954359Sroberto var_flag = s->varmode; 547054359Sroberto 547154359Sroberto switch(cmd) 547254359Sroberto { 547354359Sroberto case CMD_RCURTIME: 5474280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%f, %d, %f", 5475182007Sroberto getflt((unsigned char *)&mb(0)), getshort((unsigned char *)&mb(4)), 5476182007Sroberto getflt((unsigned char *)&mb(6))); 547754359Sroberto break; 547854359Sroberto 547954359Sroberto case CMD_RBEST4: 5480280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 548154359Sroberto switch (mb(0) & 0xF) 548254359Sroberto { 548354359Sroberto default: 5484280849Scy t = ap(pbuffer, sizeof(pbuffer), t, 5485280849Scy "0x%x", mb(0) & 0x7); 548654359Sroberto break; 548754359Sroberto 548854359Sroberto case 1: 5489280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "0D"); 549054359Sroberto break; 549154359Sroberto 549254359Sroberto case 3: 5493280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 549454359Sroberto break; 549554359Sroberto 549654359Sroberto case 4: 5497280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 549854359Sroberto break; 549954359Sroberto } 550054359Sroberto if (mb(0) & 0x10) 5501280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 550254359Sroberto else 5503280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 550454359Sroberto 5505280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "satellites %02d %02d %02d %02d, PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f", 550654359Sroberto mb(1), mb(2), mb(3), mb(4), 550754359Sroberto getflt((unsigned char *)&mb(5)), 550854359Sroberto getflt((unsigned char *)&mb(9)), 550954359Sroberto getflt((unsigned char *)&mb(13)), 551054359Sroberto getflt((unsigned char *)&mb(17))); 551154359Sroberto 551254359Sroberto break; 551354359Sroberto 551454359Sroberto case CMD_RVERSION: 5515280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%d.%d (%d/%d/%d)", 551654359Sroberto mb(0)&0xff, mb(1)&0xff, 1900+(mb(4)&0xff), mb(2)&0xff, mb(3)&0xff); 551754359Sroberto break; 551854359Sroberto 551954359Sroberto case CMD_RRECVHEALTH: 552054359Sroberto { 552154359Sroberto static const char *msgs[] = 552254359Sroberto { 552354359Sroberto "Battery backup failed", 552454359Sroberto "Signal processor error", 552554359Sroberto "Alignment error, channel or chip 1", 552654359Sroberto "Alignment error, channel or chip 2", 552754359Sroberto "Antenna feed line fault", 552854359Sroberto "Excessive ref freq. error", 552954359Sroberto "<BIT 6>", 553054359Sroberto "<BIT 7>" 553154359Sroberto }; 553254359Sroberto 553354359Sroberto int i, bits; 553454359Sroberto 553554359Sroberto switch (mb(0) & 0xFF) 553654359Sroberto { 553754359Sroberto default: 5538280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "illegal value 0x%02x", mb(0) & 0xFF); 553954359Sroberto break; 554054359Sroberto case 0x00: 5541280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "doing position fixes"); 554254359Sroberto break; 554354359Sroberto case 0x01: 5544280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "no GPS time yet"); 554554359Sroberto break; 554654359Sroberto case 0x03: 5547280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "PDOP too high"); 554854359Sroberto break; 554954359Sroberto case 0x08: 5550280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "no usable satellites"); 555154359Sroberto break; 555254359Sroberto case 0x09: 5553280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "only ONE usable satellite"); 555454359Sroberto break; 555554359Sroberto case 0x0A: 5556280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "only TWO usable satellites"); 555754359Sroberto break; 555854359Sroberto case 0x0B: 5559280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "only THREE usable satellites"); 556054359Sroberto break; 556154359Sroberto case 0x0C: 5562280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "the chosen satellite is unusable"); 556354359Sroberto break; 556454359Sroberto } 556554359Sroberto 556654359Sroberto bits = mb(1) & 0xFF; 556754359Sroberto 556854359Sroberto for (i = 0; i < 8; i++) 556954359Sroberto if (bits & (0x1<<i)) 557054359Sroberto { 5571280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 557254359Sroberto } 557354359Sroberto } 557454359Sroberto break; 557554359Sroberto 557654359Sroberto case CMD_RMESSAGE: 5577182007Sroberto mkreadable(t, (int)BUFFER_SIZE(pbuffer, t), (char *)&mb(0), (unsigned)(size - 2 - (&mb(0) - buffer)), 0); 557854359Sroberto break; 557954359Sroberto 558054359Sroberto case CMD_RMACHSTAT: 558154359Sroberto { 558254359Sroberto static const char *msgs[] = 558354359Sroberto { 558454359Sroberto "Synthesizer Fault", 558554359Sroberto "Battery Powered Time Clock Fault", 558654359Sroberto "A-to-D Converter Fault", 558754359Sroberto "The almanac stored in the receiver is not complete and current", 558854359Sroberto "<BIT 4>", 558954359Sroberto "<BIT 5", 559054359Sroberto "<BIT 6>", 559154359Sroberto "<BIT 7>" 559254359Sroberto }; 559354359Sroberto 559454359Sroberto int i, bits; 559554359Sroberto 5596280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "machine id 0x%02x", mb(0) & 0xFF); 559754359Sroberto bits = mb(1) & 0xFF; 559854359Sroberto 559954359Sroberto for (i = 0; i < 8; i++) 560054359Sroberto if (bits & (0x1<<i)) 560154359Sroberto { 5602280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", %s", msgs[i]); 560354359Sroberto } 560454359Sroberto 5605280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", Superpackets %ssupported", (mb(2) & 0xFF) ? "" :"un" ); 560654359Sroberto } 560754359Sroberto break; 560854359Sroberto 560954359Sroberto case CMD_ROPERPARAM: 5610280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%2x %.1f %.1f %.1f %.1f", 561154359Sroberto mb(0), getflt((unsigned char *)&mb(1)), getflt((unsigned char *)&mb(5)), 561254359Sroberto getflt((unsigned char *)&mb(9)), getflt((unsigned char *)&mb(13))); 561354359Sroberto break; 561454359Sroberto 561554359Sroberto case CMD_RUTCPARAM: 561654359Sroberto { 561754359Sroberto float t0t = getflt((unsigned char *)&mb(14)); 561854359Sroberto short wnt = getshort((unsigned char *)&mb(18)); 561954359Sroberto short dtls = getshort((unsigned char *)&mb(12)); 562054359Sroberto short wnlsf = getshort((unsigned char *)&mb(20)); 562154359Sroberto short dn = getshort((unsigned char *)&mb(22)); 562254359Sroberto short dtlsf = getshort((unsigned char *)&mb(24)); 562354359Sroberto 562454359Sroberto if ((int)t0t != 0) 5625280849Scy { 5626280849Scy mk_utcinfo(t, wnt, wnlsf, dn, dtls, dtlsf, BUFFER_SIZE(pbuffer, t)); 5627280849Scy } 562854359Sroberto else 5629280849Scy { 5630280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "<NO UTC DATA>"); 5631280849Scy } 563254359Sroberto } 563354359Sroberto break; 563454359Sroberto 563554359Sroberto case CMD_RSAT1BIAS: 5636280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%.1fm %.2fm/s at %.1fs", 563754359Sroberto getflt(&mb(0)), getflt(&mb(4)), getflt(&mb(8))); 563854359Sroberto break; 563954359Sroberto 564054359Sroberto case CMD_RIOOPTIONS: 564154359Sroberto { 5642280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%02x %02x %02x %02x", 564354359Sroberto mb(0), mb(1), mb(2), mb(3)); 564454359Sroberto if (mb(0) != TRIM_POS_OPT || 564554359Sroberto mb(2) != TRIM_TIME_OPT) 564654359Sroberto { 564754359Sroberto (void)trimbletsip_setup(parse, "bad io options"); 564854359Sroberto } 564954359Sroberto } 565054359Sroberto break; 565154359Sroberto 565254359Sroberto case CMD_RSPOSXYZ: 565354359Sroberto { 565454359Sroberto double x = getflt((unsigned char *)&mb(0)); 565554359Sroberto double y = getflt((unsigned char *)&mb(4)); 565654359Sroberto double z = getflt((unsigned char *)&mb(8)); 565754359Sroberto double f = getflt((unsigned char *)&mb(12)); 565854359Sroberto 565954359Sroberto if (f > 0.0) 5660280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm, time_of_fix= %f sec", 566154359Sroberto x, y, z, 566254359Sroberto f); 566354359Sroberto else 5664280849Scy return; 566554359Sroberto } 566654359Sroberto break; 566754359Sroberto 566854359Sroberto case CMD_RSLLAPOS: 566954359Sroberto { 567054359Sroberto double lat = getflt((unsigned char *)&mb(0)); 567154359Sroberto double lng = getflt((unsigned char *)&mb(4)); 567254359Sroberto double f = getflt((unsigned char *)&mb(12)); 567354359Sroberto 567454359Sroberto if (f > 0.0) 5675280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, long %f %c, alt %.2fm", 567654359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 567754359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 567854359Sroberto getflt((unsigned char *)&mb(8))); 567954359Sroberto else 5680280849Scy return; 568154359Sroberto } 568254359Sroberto break; 568354359Sroberto 568454359Sroberto case CMD_RDOUBLEXYZ: 568554359Sroberto { 568654359Sroberto double x = getdbl((unsigned char *)&mb(0)); 568754359Sroberto double y = getdbl((unsigned char *)&mb(8)); 568854359Sroberto double z = getdbl((unsigned char *)&mb(16)); 5689280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "x= %.1fm, y= %.1fm, z= %.1fm", 569054359Sroberto x, y, z); 569154359Sroberto } 569254359Sroberto break; 569354359Sroberto 569454359Sroberto case CMD_RDOUBLELLA: 569554359Sroberto { 569654359Sroberto double lat = getdbl((unsigned char *)&mb(0)); 569754359Sroberto double lng = getdbl((unsigned char *)&mb(8)); 5698280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "lat %f %c, lon %f %c, alt %.2fm", 569954359Sroberto ((lat < 0.0) ? (-lat) : (lat))*RTOD, (lat < 0.0 ? 'S' : 'N'), 570054359Sroberto ((lng < 0.0) ? (-lng) : (lng))*RTOD, (lng < 0.0 ? 'W' : 'E'), 570154359Sroberto getdbl((unsigned char *)&mb(16))); 570254359Sroberto } 570354359Sroberto break; 570454359Sroberto 570554359Sroberto case CMD_RALLINVIEW: 570654359Sroberto { 570754359Sroberto int i, sats; 570854359Sroberto 5709280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "mode: "); 571054359Sroberto switch (mb(0) & 0x7) 571154359Sroberto { 571254359Sroberto default: 5713280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "0x%x", mb(0) & 0x7); 571454359Sroberto break; 571554359Sroberto 571654359Sroberto case 3: 5717280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "2D"); 571854359Sroberto break; 571954359Sroberto 572054359Sroberto case 4: 5721280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "3D"); 572254359Sroberto break; 572354359Sroberto } 572454359Sroberto if (mb(0) & 0x8) 5725280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-MANUAL, "); 572654359Sroberto else 5727280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "-AUTO, "); 572854359Sroberto 572954359Sroberto sats = (mb(0)>>4) & 0xF; 573054359Sroberto 5731280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "PDOP %.2f, HDOP %.2f, VDOP %.2f, TDOP %.2f, %d satellite%s in view: ", 573254359Sroberto getflt((unsigned char *)&mb(1)), 573354359Sroberto getflt((unsigned char *)&mb(5)), 573454359Sroberto getflt((unsigned char *)&mb(9)), 573554359Sroberto getflt((unsigned char *)&mb(13)), 573654359Sroberto sats, (sats == 1) ? "" : "s"); 573754359Sroberto 573854359Sroberto for (i=0; i < sats; i++) 573954359Sroberto { 5740280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "%s%02d", i ? ", " : "", mb(17+i)); 574154359Sroberto if (tr) 574254359Sroberto tr->ctrack |= (1 << (mb(17+i)-1)); 574354359Sroberto } 574454359Sroberto 574554359Sroberto if (tr) 5746280849Scy { /* mark for tracking status query */ 574754359Sroberto tr->qtracking = 1; 574854359Sroberto } 574954359Sroberto } 575054359Sroberto break; 575154359Sroberto 575254359Sroberto case CMD_RSTATTRACK: 575354359Sroberto { 5754280849Scy t = ap(pbuffer, sizeof(pbuffer), t-2, "[%02d]=\"", mb(0)); /* add index to var name */ 575554359Sroberto if (getflt((unsigned char *)&mb(4)) < 0.0) 575654359Sroberto { 5757280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "<NO MEASUREMENTS>"); 575854359Sroberto var_flag &= ~DEF; 575954359Sroberto } 576054359Sroberto else 576154359Sroberto { 5762280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "ch=%d, acq=%s, eph=%d, signal_level= %5.2f, elevation= %5.2f, azimuth= %6.2f", 576354359Sroberto (mb(1) & 0xFF)>>3, 576454359Sroberto mb(2) ? ((mb(2) == 1) ? "ACQ" : "SRCH") : "NEVER", 576554359Sroberto mb(3), 576654359Sroberto getflt((unsigned char *)&mb(4)), 576754359Sroberto getflt((unsigned char *)&mb(12)) * RTOD, 576854359Sroberto getflt((unsigned char *)&mb(16)) * RTOD); 576954359Sroberto if (mb(20)) 577054359Sroberto { 577154359Sroberto var_flag &= ~DEF; 5772280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", OLD"); 577354359Sroberto } 577454359Sroberto if (mb(22)) 577554359Sroberto { 577654359Sroberto if (mb(22) == 1) 5777280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", BAD PARITY"); 577854359Sroberto else 577954359Sroberto if (mb(22) == 2) 5780280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", BAD EPH HEALTH"); 578154359Sroberto } 578254359Sroberto if (mb(23)) 5783280849Scy t = ap(pbuffer, sizeof(pbuffer), t, ", collecting data"); 578454359Sroberto } 578554359Sroberto } 578654359Sroberto break; 578754359Sroberto 578854359Sroberto default: 5789280849Scy t = ap(pbuffer, sizeof(pbuffer), t, "<UNDECODED>"); 579054359Sroberto break; 579154359Sroberto } 5792182007Sroberto 5793280849Scy t = ap(pbuffer, sizeof(pbuffer), t,"\""); 579454359Sroberto set_var(&parse->kv, pbuffer, sizeof(pbuffer), var_flag); 579554359Sroberto } 579654359Sroberto} 579754359Sroberto 579854359Sroberto 579954359Sroberto/**============================================================ 580054359Sroberto ** RAWDCF support 580154359Sroberto **/ 580254359Sroberto 580354359Sroberto/*-------------------------------------------------- 580456746Sroberto * rawdcf_init_1 - set up modem lines for RAWDCF receivers 580556746Sroberto * SET DTR line 580654359Sroberto */ 580754359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 580854359Srobertostatic int 580956746Srobertorawdcf_init_1( 581054359Sroberto struct parseunit *parse 581154359Sroberto ) 581254359Sroberto{ 581382498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 581454359Sroberto /* 581554359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 581654359Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 581754359Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 581854359Sroberto */ 581982498Sroberto int sl232; 582082498Sroberto 582182498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 582282498Sroberto { 582382498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 582482498Sroberto return 0; 582582498Sroberto } 582682498Sroberto 582754359Sroberto#ifdef TIOCM_DTR 582882498Sroberto sl232 = (sl232 & ~TIOCM_RTS) | TIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 582954359Sroberto#else 583082498Sroberto sl232 = (sl232 & ~CIOCM_RTS) | CIOCM_DTR; /* turn on DTR, clear RTS for power supply */ 583154359Sroberto#endif 583254359Sroberto 583354359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 583454359Sroberto { 583556746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m", CLK_UNIT(parse->peer)); 583654359Sroberto } 583754359Sroberto return 0; 583854359Sroberto} 583954359Sroberto#else 584054359Srobertostatic int 5841132451Srobertorawdcfdtr_init_1( 584254359Sroberto struct parseunit *parse 584354359Sroberto ) 584454359Sroberto{ 584556746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_1: WARNING: OS interface incapable of setting DTR to power DCF modules", CLK_UNIT(parse->peer)); 584654359Sroberto return 0; 584754359Sroberto} 584854359Sroberto#endif /* DTR initialisation type */ 584954359Sroberto 585054359Sroberto/*-------------------------------------------------- 585156746Sroberto * rawdcf_init_2 - set up modem lines for RAWDCF receivers 585256746Sroberto * CLR DTR line, SET RTS line 585354359Sroberto */ 585456746Sroberto#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS)) 585554359Srobertostatic int 585656746Srobertorawdcf_init_2( 585754359Sroberto struct parseunit *parse 585854359Sroberto ) 585954359Sroberto{ 586082498Sroberto /* fixed 2000 for using with Linux by Wolfram Pienkoss <wp@bszh.de> */ 586154359Sroberto /* 586254359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 586356746Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 586456746Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 586554359Sroberto */ 586682498Sroberto int sl232; 586782498Sroberto 586882498Sroberto if (ioctl(parse->generic->io.fd, TIOCMGET, (caddr_t)&sl232) == -1) 586982498Sroberto { 587082498Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMGET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 587182498Sroberto return 0; 587282498Sroberto } 587382498Sroberto 587454359Sroberto#ifdef TIOCM_RTS 587582498Sroberto sl232 = (sl232 & ~TIOCM_DTR) | TIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 587654359Sroberto#else 587782498Sroberto sl232 = (sl232 & ~CIOCM_DTR) | CIOCM_RTS; /* turn on RTS, clear DTR for power supply */ 587854359Sroberto#endif 587954359Sroberto 588054359Sroberto if (ioctl(parse->generic->io.fd, TIOCMSET, (caddr_t)&sl232) == -1) 588154359Sroberto { 588256746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_RTS): %m", CLK_UNIT(parse->peer)); 588354359Sroberto } 588454359Sroberto return 0; 588554359Sroberto} 588654359Sroberto#else 588754359Srobertostatic int 588856746Srobertorawdcf_init_2( 588954359Sroberto struct parseunit *parse 589054359Sroberto ) 589154359Sroberto{ 589256746Sroberto msyslog(LOG_NOTICE, "PARSE receiver #%d: rawdcf_init_2: WARNING: OS interface incapable of setting RTS to power DCF modules", CLK_UNIT(parse->peer)); 589354359Sroberto return 0; 589454359Sroberto} 589556746Sroberto#endif /* DTR initialisation type */ 589654359Sroberto 589754359Sroberto#else /* defined(REFCLOCK) && defined(PARSE) */ 5898280849ScyNONEMPTY_TRANSLATION_UNIT 589954359Sroberto#endif /* defined(REFCLOCK) && defined(PARSE) */ 590054359Sroberto 590154359Sroberto/* 590254359Sroberto * History: 590354359Sroberto * 590454359Sroberto * refclock_parse.c,v 5905280849Scy * Revision 4.81 2009/05/01 10:15:29 kardel 5906280849Scy * use new refclock_ppsapi interface 5907280849Scy * 5908182007Sroberto * Revision 4.80 2007/08/11 12:06:29 kardel 5909182007Sroberto * update comments wrt/ to PPS 5910182007Sroberto * 5911182007Sroberto * Revision 4.79 2007/08/11 11:52:23 kardel 5912182007Sroberto * - terminate io bindings before io_closeclock() will close our file descriptor 5913182007Sroberto * 5914182007Sroberto * Revision 4.78 2006/12/22 20:08:27 kardel 5915182007Sroberto * Bug 746 (RFE): add configuration for Expert mouseCLOCK USB v2.0 as mode 19 5916182007Sroberto * 5917182007Sroberto * Revision 4.77 2006/08/05 07:44:49 kardel 5918182007Sroberto * support optionally separate PPS devices via /dev/refclockpps-{0..3} 5919182007Sroberto * 5920182007Sroberto * Revision 4.76 2006/06/22 18:40:47 kardel 5921182007Sroberto * clean up signedness (gcc 4) 5922182007Sroberto * 5923182007Sroberto * Revision 4.75 2006/06/22 16:58:10 kardel 5924182007Sroberto * Bug #632: call parse_ppsapi() in parse_ctl() when updating 5925182007Sroberto * the PPS offset. Fix sign of offset passed to kernel. 5926182007Sroberto * 5927182007Sroberto * Revision 4.74 2006/06/18 21:18:37 kardel 5928182007Sroberto * NetBSD Coverity CID 3796: possible NULL deref 5929182007Sroberto * 5930182007Sroberto * Revision 4.73 2006/05/26 14:23:46 kardel 5931182007Sroberto * cleanup of copyright info 5932182007Sroberto * 5933182007Sroberto * Revision 4.72 2006/05/26 14:19:43 kardel 5934182007Sroberto * cleanup of ioctl cruft 5935182007Sroberto * 5936182007Sroberto * Revision 4.71 2006/05/26 14:15:57 kardel 5937182007Sroberto * delay adding refclock to async refclock io after all initializations 5938182007Sroberto * 5939182007Sroberto * Revision 4.70 2006/05/25 18:20:50 kardel 5940182007Sroberto * bug #619 5941182007Sroberto * terminate parse io engine after de-registering 5942182007Sroberto * from refclock io engine 5943182007Sroberto * 5944182007Sroberto * Revision 4.69 2006/05/25 17:28:02 kardel 5945182007Sroberto * complete refclock io structure initialization *before* inserting it into the 5946182007Sroberto * refclock input machine (avoids null pointer deref) (bug #619) 5947182007Sroberto * 5948182007Sroberto * Revision 4.68 2006/05/01 17:02:51 kardel 5949182007Sroberto * copy receiver method also for newlwy created receive buffers 5950182007Sroberto * 5951182007Sroberto * Revision 4.67 2006/05/01 14:37:29 kardel 5952182007Sroberto * If an input buffer parses into more than one message do insert the 5953182007Sroberto * parsed message in a new input buffer instead of processing it 5954182007Sroberto * directly. This avoids deed complicated processing in signal 5955182007Sroberto * handling. 5956182007Sroberto * 5957182007Sroberto * Revision 4.66 2006/03/18 00:45:30 kardel 5958182007Sroberto * coverity fixes found in NetBSD coverity scan 5959182007Sroberto * 5960182007Sroberto * Revision 4.65 2006/01/26 06:08:33 kardel 5961182007Sroberto * output errno on PPS setup failure 5962182007Sroberto * 5963182007Sroberto * Revision 4.64 2005/11/09 20:44:47 kardel 5964182007Sroberto * utilize full PPS timestamp resolution from PPS API 5965182007Sroberto * 5966182007Sroberto * Revision 4.63 2005/10/07 22:10:25 kardel 5967182007Sroberto * bounded buffer implementation 5968182007Sroberto * 5969182007Sroberto * Revision 4.62.2.2 2005/09/25 10:20:16 kardel 5970182007Sroberto * avoid unexpected buffer overflows due to sprintf("%f") on strange floats: 5971182007Sroberto * replace almost all str* and *printf functions be their buffer bounded 5972182007Sroberto * counterparts 5973182007Sroberto * 5974182007Sroberto * Revision 4.62.2.1 2005/08/27 16:19:27 kardel 5975182007Sroberto * limit re-set rate of trimble clocks 5976182007Sroberto * 5977182007Sroberto * Revision 4.62 2005/08/06 17:40:00 kardel 5978182007Sroberto * cleanup size handling wrt/ to buffer boundaries 5979182007Sroberto * 5980182007Sroberto * Revision 4.61 2005/07/27 21:16:19 kardel 5981182007Sroberto * fix a long (> 11 years) misconfiguration wrt/ Meinberg cflag factory 5982182007Sroberto * default setup. CSTOPB was missing for the 7E2 default data format of 5983182007Sroberto * the DCF77 clocks. 5984182007Sroberto * 5985182007Sroberto * Revision 4.60 2005/07/17 21:14:44 kardel 5986182007Sroberto * change contents of version string to include the RCS/CVS Id 5987182007Sroberto * 5988182007Sroberto * Revision 4.59 2005/07/06 06:56:38 kardel 5989182007Sroberto * syntax error 5990182007Sroberto * 5991182007Sroberto * Revision 4.58 2005/07/04 13:10:40 kardel 5992182007Sroberto * fix bug 455: tripping over NULL pointer on cleanup 5993182007Sroberto * fix shadow storage logic for ppsphaseadjust and trustime wrt/ time2 5994182007Sroberto * fix compiler warnings for some platforms wrt/ printf formatstrings and 5995182007Sroberto * varying structure element sizes 5996182007Sroberto * reorder assignment in binding to avoid tripping over NULL pointers 5997182007Sroberto * 5998182007Sroberto * Revision 4.57 2005/06/25 09:25:19 kardel 5999182007Sroberto * sort out log output sequence 6000182007Sroberto * 6001182007Sroberto * Revision 4.56 2005/06/14 21:47:27 kardel 6002182007Sroberto * collect samples only if samples are ok (sync or trusted flywheel) 6003182007Sroberto * propagate pps phase adjustment value to kernel via PPSAPI to help HARDPPS 6004182007Sroberto * en- and dis-able HARDPPS in correlation to receiver sync state 6005182007Sroberto * 6006182007Sroberto * Revision 4.55 2005/06/02 21:28:31 kardel 6007182007Sroberto * clarify trust logic 6008182007Sroberto * 6009182007Sroberto * Revision 4.54 2005/06/02 17:06:49 kardel 6010182007Sroberto * change status reporting to use fixed refclock_report() 6011182007Sroberto * 6012182007Sroberto * Revision 4.53 2005/06/02 16:33:31 kardel 6013182007Sroberto * fix acceptance of clocks unsync clocks right at start 6014182007Sroberto * 6015182007Sroberto * Revision 4.52 2005/05/26 21:55:06 kardel 6016182007Sroberto * cleanup status reporting 6017182007Sroberto * 6018182007Sroberto * Revision 4.51 2005/05/26 19:19:14 kardel 6019182007Sroberto * implement fast refclock startup 6020182007Sroberto * 6021182007Sroberto * Revision 4.50 2005/04/16 20:51:35 kardel 6022280849Scy * set hardpps_enable = 1 when binding a kernel PPS source 6023182007Sroberto * 6024182007Sroberto * Revision 4.49 2005/04/16 17:29:26 kardel 6025182007Sroberto * add non polling clock type 18 for just listenning to Meinberg clocks 6026182007Sroberto * 6027182007Sroberto * Revision 4.48 2005/04/16 16:22:27 kardel 6028182007Sroberto * bk sync 20050415 ntp-dev 6029182007Sroberto * 6030182007Sroberto * Revision 4.47 2004/11/29 10:42:48 kardel 6031182007Sroberto * bk sync ntp-dev 20041129 6032182007Sroberto * 6033182007Sroberto * Revision 4.46 2004/11/29 10:26:29 kardel 6034182007Sroberto * keep fudgetime2 in sync with trusttime/ppsphaseadjust depending in flag1 6035182007Sroberto * 6036182007Sroberto * Revision 4.45 2004/11/14 20:53:20 kardel 6037182007Sroberto * clear PPS flags after using them 6038182007Sroberto * 6039182007Sroberto * Revision 4.44 2004/11/14 15:29:41 kardel 6040182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style 6041182007Sroberto * 6042182007Sroberto * Revision 4.43 2001/05/26 22:53:16 kardel 6043182007Sroberto * 20010526 reconcilation 6044182007Sroberto * 6045182007Sroberto * Revision 4.42 2000/05/14 15:31:51 kardel 6046182007Sroberto * PPSAPI && RAWDCF modemline support 6047182007Sroberto * 6048182007Sroberto * Revision 4.41 2000/04/09 19:50:45 kardel 6049182007Sroberto * fixed rawdcfdtr_init() -> rawdcf_init_1 6050182007Sroberto * 6051182007Sroberto * Revision 4.40 2000/04/09 15:27:55 kardel 6052182007Sroberto * modem line fiddle in rawdcf_init_2 6053182007Sroberto * 6054182007Sroberto * Revision 4.39 2000/03/18 09:16:55 kardel 6055182007Sroberto * PPSAPI integration 6056182007Sroberto * 6057182007Sroberto * Revision 4.38 2000/03/05 20:25:06 kardel 6058182007Sroberto * support PPSAPI 6059182007Sroberto * 6060182007Sroberto * Revision 4.37 2000/03/05 20:11:14 kardel 6061182007Sroberto * 4.0.99g reconcilation 6062182007Sroberto * 606356746Sroberto * Revision 4.36 1999/11/28 17:18:20 kardel 606456746Sroberto * disabled burst mode 606556746Sroberto * 606656746Sroberto * Revision 4.35 1999/11/28 09:14:14 kardel 606756746Sroberto * RECON_4_0_98F 606856746Sroberto * 606956746Sroberto * Revision 4.34 1999/05/14 06:08:05 kardel 607056746Sroberto * store current_time in a suitable container (u_long) 607156746Sroberto * 607256746Sroberto * Revision 4.33 1999/05/13 21:48:38 kardel 607356746Sroberto * double the no response timeout interval 607456746Sroberto * 607556746Sroberto * Revision 4.32 1999/05/13 20:09:13 kardel 607656746Sroberto * complain only about missing polls after a full poll interval 607756746Sroberto * 607856746Sroberto * Revision 4.31 1999/05/13 19:59:32 kardel 607956746Sroberto * add clock type 16 for RTS set DTR clr in RAWDCF 608056746Sroberto * 608156746Sroberto * Revision 4.30 1999/02/28 20:36:43 kardel 608256746Sroberto * fixed printf fmt 608356746Sroberto * 608454359Sroberto * Revision 4.29 1999/02/28 19:58:23 kardel 608554359Sroberto * updated copyright information 608654359Sroberto * 608754359Sroberto * Revision 4.28 1999/02/28 19:01:50 kardel 608854359Sroberto * improved debug out on sent Meinberg messages 608954359Sroberto * 609054359Sroberto * Revision 4.27 1999/02/28 18:05:55 kardel 609154359Sroberto * no linux/ppsclock.h stuff 609254359Sroberto * 609354359Sroberto * Revision 4.26 1999/02/28 15:27:27 kardel 609454359Sroberto * wharton clock integration 609554359Sroberto * 609654359Sroberto * Revision 4.25 1999/02/28 14:04:46 kardel 609754359Sroberto * added missing double quotes to UTC information string 609854359Sroberto * 609954359Sroberto * Revision 4.24 1999/02/28 12:06:50 kardel 610054359Sroberto * (parse_control): using gmprettydate instead of prettydate() 610154359Sroberto * (mk_utcinfo): new function for formatting GPS derived UTC information 610254359Sroberto * (gps16x_message): changed to use mk_utcinfo() 610354359Sroberto * (trimbletsip_message): changed to use mk_utcinfo() 610454359Sroberto * ignoring position information in unsynchronized mode 610554359Sroberto * (parse_start): augument linux support for optional ASYNC_LOW_LATENCY 610654359Sroberto * 610754359Sroberto * Revision 4.23 1999/02/23 19:47:53 kardel 610854359Sroberto * fixed #endifs 610954359Sroberto * (stream_receive): fixed formats 611054359Sroberto * 611154359Sroberto * Revision 4.22 1999/02/22 06:21:02 kardel 611254359Sroberto * use new autoconfig symbols 611354359Sroberto * 611454359Sroberto * Revision 4.21 1999/02/21 12:18:13 kardel 611554359Sroberto * 4.91f reconcilation 611654359Sroberto * 611754359Sroberto * Revision 4.20 1999/02/21 10:53:36 kardel 611854359Sroberto * initial Linux PPSkit version 611954359Sroberto * 612054359Sroberto * Revision 4.19 1999/02/07 09:10:45 kardel 612154359Sroberto * clarify STREAMS mitigation rules in comment 612254359Sroberto * 612354359Sroberto * Revision 4.18 1998/12/20 23:45:34 kardel 612454359Sroberto * fix types and warnings 612554359Sroberto * 612654359Sroberto * Revision 4.17 1998/11/15 21:24:51 kardel 612754359Sroberto * cannot access mbg_ routines when CLOCK_MEINBERG 612854359Sroberto * is not defined 612954359Sroberto * 613054359Sroberto * Revision 4.16 1998/11/15 20:28:17 kardel 613154359Sroberto * Release 4.0.73e13 reconcilation 613254359Sroberto * 613354359Sroberto * Revision 4.15 1998/08/22 21:56:08 kardel 613454359Sroberto * fixed IO handling for non-STREAM IO 613554359Sroberto * 613654359Sroberto * Revision 4.14 1998/08/16 19:00:48 kardel 613754359Sroberto * (gps16x_message): reduced UTC parameter information (dropped A0,A1) 613854359Sroberto * made uval a local variable (killed one of the last globals) 613954359Sroberto * (sendetx): added logging of messages when in debug mode 614054359Sroberto * (trimble_check): added periodic checks to facilitate re-initialization 614154359Sroberto * (trimbletsip_init): made use of EOL character if in non-kernel operation 614254359Sroberto * (trimbletsip_message): extended message interpretation 614354359Sroberto * (getdbl): fixed data conversion 614454359Sroberto * 614554359Sroberto * Revision 4.13 1998/08/09 22:29:13 kardel 614654359Sroberto * Trimble TSIP support 614754359Sroberto * 614854359Sroberto * Revision 4.12 1998/07/11 10:05:34 kardel 614954359Sroberto * Release 4.0.73d reconcilation 615054359Sroberto * 615154359Sroberto * Revision 4.11 1998/06/14 21:09:42 kardel 615254359Sroberto * Sun acc cleanup 615354359Sroberto * 615454359Sroberto * Revision 4.10 1998/06/13 12:36:45 kardel 615554359Sroberto * signed/unsigned, name clashes 615654359Sroberto * 615754359Sroberto * Revision 4.9 1998/06/12 15:30:00 kardel 615854359Sroberto * prototype fixes 615954359Sroberto * 616054359Sroberto * Revision 4.8 1998/06/12 11:19:42 kardel 616154359Sroberto * added direct input processing routine for refclocks in 616254359Sroberto * order to avaiod that single character io gobbles up all 616354359Sroberto * receive buffers and drops input data. (Problem started 616454359Sroberto * with fast machines so a character a buffer was possible 616554359Sroberto * one of the few cases where faster machines break existing 616654359Sroberto * allocation algorithms) 616754359Sroberto * 616854359Sroberto * Revision 4.7 1998/06/06 18:35:20 kardel 616954359Sroberto * (parse_start): added BURST mode initialisation 617054359Sroberto * 617154359Sroberto * Revision 4.6 1998/05/27 06:12:46 kardel 617254359Sroberto * RAWDCF_BASEDELAY default added 617354359Sroberto * old comment removed 617454359Sroberto * casts for ioctl() 617554359Sroberto * 617654359Sroberto * Revision 4.5 1998/05/25 22:05:09 kardel 617754359Sroberto * RAWDCF_SETDTR option removed 617854359Sroberto * clock type 14 attempts to set DTR for 617954359Sroberto * power supply of RAWDCF receivers 618054359Sroberto * 618154359Sroberto * Revision 4.4 1998/05/24 16:20:47 kardel 618254359Sroberto * updated comments referencing Meinberg clocks 618354359Sroberto * added RAWDCF clock with DTR set option as type 14 618454359Sroberto * 618554359Sroberto * Revision 4.3 1998/05/24 10:48:33 kardel 618654359Sroberto * calibrated CONRAD RAWDCF default fudge factor 618754359Sroberto * 618854359Sroberto * Revision 4.2 1998/05/24 09:59:35 kardel 618954359Sroberto * corrected version information (ntpq support) 619054359Sroberto * 619154359Sroberto * Revision 4.1 1998/05/24 09:52:31 kardel 619254359Sroberto * use fixed format only (new IO model) 619354359Sroberto * output debug to stdout instead of msyslog() 619454359Sroberto * don't include >"< in ASCII output in order not to confuse 619554359Sroberto * ntpq parsing 619654359Sroberto * 619754359Sroberto * Revision 4.0 1998/04/10 19:52:11 kardel 619854359Sroberto * Start 4.0 release version numbering 619954359Sroberto * 620054359Sroberto * Revision 1.2 1998/04/10 19:28:04 kardel 620154359Sroberto * initial NTP VERSION 4 integration of PARSE with GPS166 binary support 620254359Sroberto * derived from 3.105.1.2 from V3 tree 620354359Sroberto * 620454359Sroberto * Revision information 3.1 - 3.105 from log deleted 1998/04/10 kardel 620554359Sroberto * 620654359Sroberto */ 6207