154359Sroberto/* 254359Sroberto * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock 354359Sroberto */ 482498Sroberto 554359Sroberto#ifdef HAVE_CONFIG_H 682498Sroberto# include <config.h> 754359Sroberto#endif 854359Sroberto 954359Sroberto#if defined(REFCLOCK) && defined(CLOCK_LEITCH) 1054359Sroberto 1154359Sroberto#include "ntpd.h" 1254359Sroberto#include "ntp_io.h" 1354359Sroberto#include "ntp_refclock.h" 1454359Sroberto#include "ntp_unixtime.h" 1554359Sroberto 1682498Sroberto#include <stdio.h> 1782498Sroberto#include <ctype.h> 1882498Sroberto 1954359Sroberto#ifdef STREAM 2054359Sroberto#include <stropts.h> 2154359Sroberto#if defined(LEITCHCLK) 2254359Sroberto#include <sys/clkdefs.h> 2354359Sroberto#endif /* LEITCHCLK */ 2454359Sroberto#endif /* STREAM */ 2554359Sroberto 2654359Sroberto#include "ntp_stdlib.h" 2754359Sroberto 2854359Sroberto 2954359Sroberto/* 3054359Sroberto * Driver for Leitch CSD-5300 Master Clock System 3154359Sroberto * 3254359Sroberto * COMMANDS: 3354359Sroberto * DATE: D <CR> 3454359Sroberto * TIME: T <CR> 3554359Sroberto * STATUS: S <CR> 3654359Sroberto * LOOP: L <CR> 3754359Sroberto * 3854359Sroberto * FORMAT: 3954359Sroberto * DATE: YYMMDD<CR> 4054359Sroberto * TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/ 4154359Sroberto * second bondaried on the stop bit of the <CR> 4254359Sroberto * second boundaries at '/' above. 4354359Sroberto * STATUS: G (good), D (diag fail), T (time not provided) or 4454359Sroberto * P (last phone update failed) 4554359Sroberto */ 4654359Sroberto#define MAXUNITS 1 /* max number of LEITCH units */ 4754359Sroberto#define LEITCHREFID "ATOM" /* reference id */ 4854359Sroberto#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver" 4954359Sroberto#define LEITCH232 "/dev/leitch%d" /* name of radio device */ 5054359Sroberto#define SPEED232 B300 /* uart speed (300 baud) */ 51182007Sroberto#ifdef DEBUG 5254359Sroberto#define leitch_send(A,M) \ 5354359Srobertoif (debug) fprintf(stderr,"write leitch %s\n",M); \ 5454359Srobertoif ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\ 55182007Sroberto if (debug) \ 56182007Sroberto fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \ 57182007Sroberto else \ 58182007Sroberto msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);} 59182007Sroberto#else 60182007Sroberto#define leitch_send(A,M) \ 61182007Srobertoif ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\ 62182007Sroberto msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);} 63182007Sroberto#endif 64182007Sroberto 6554359Sroberto#define STATE_IDLE 0 6654359Sroberto#define STATE_DATE 1 6754359Sroberto#define STATE_TIME1 2 6854359Sroberto#define STATE_TIME2 3 6954359Sroberto#define STATE_TIME3 4 7054359Sroberto 7154359Sroberto/* 7254359Sroberto * LEITCH unit control structure 7354359Sroberto */ 7454359Srobertostruct leitchunit { 7554359Sroberto struct peer *peer; 7654359Sroberto struct refclockio leitchio; 7754359Sroberto u_char unit; 7854359Sroberto short year; 7954359Sroberto short yearday; 8054359Sroberto short month; 8154359Sroberto short day; 8254359Sroberto short hour; 8354359Sroberto short second; 8454359Sroberto short minute; 8554359Sroberto short state; 8654359Sroberto u_short fudge1; 8754359Sroberto l_fp reftime1; 8854359Sroberto l_fp reftime2; 8954359Sroberto l_fp reftime3; 9054359Sroberto l_fp codetime1; 9154359Sroberto l_fp codetime2; 9254359Sroberto l_fp codetime3; 9354359Sroberto u_long yearstart; 9454359Sroberto}; 9554359Sroberto 9654359Sroberto/* 9754359Sroberto * Function prototypes 9854359Sroberto */ 9954359Srobertostatic void leitch_init P((void)); 10054359Srobertostatic int leitch_start P((int, struct peer *)); 10154359Srobertostatic void leitch_shutdown P((int, struct peer *)); 10254359Srobertostatic void leitch_poll P((int, struct peer *)); 10354359Srobertostatic void leitch_control P((int, struct refclockstat *, struct refclockstat *, struct peer *)); 10454359Sroberto#define leitch_buginfo noentry 10554359Srobertostatic void leitch_receive P((struct recvbuf *)); 10654359Srobertostatic void leitch_process P((struct leitchunit *)); 10754359Sroberto#if 0 10854359Srobertostatic void leitch_timeout P((struct peer *)); 10954359Sroberto#endif 11054359Srobertostatic int leitch_get_date P((struct recvbuf *, struct leitchunit *)); 11154359Srobertostatic int leitch_get_time P((struct recvbuf *, struct leitchunit *, int)); 11254359Srobertostatic int days_per_year P((int)); 11354359Sroberto 11454359Srobertostatic struct leitchunit leitchunits[MAXUNITS]; 11554359Srobertostatic u_char unitinuse[MAXUNITS]; 11654359Srobertostatic u_char stratumtouse[MAXUNITS]; 11754359Srobertostatic u_int32 refid[MAXUNITS]; 11854359Sroberto 11954359Srobertostatic char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 12054359Sroberto 12154359Sroberto/* 12254359Sroberto * Transfer vector 12354359Sroberto */ 12454359Srobertostruct refclock refclock_leitch = { 12554359Sroberto leitch_start, leitch_shutdown, leitch_poll, 12654359Sroberto leitch_control, leitch_init, leitch_buginfo, NOFLAGS 12754359Sroberto}; 12854359Sroberto 12954359Sroberto/* 13054359Sroberto * leitch_init - initialize internal leitch driver data 13154359Sroberto */ 13254359Srobertostatic void 13354359Srobertoleitch_init(void) 13454359Sroberto{ 13554359Sroberto int i; 13654359Sroberto 13754359Sroberto memset((char*)leitchunits, 0, sizeof(leitchunits)); 13854359Sroberto memset((char*)unitinuse, 0, sizeof(unitinuse)); 13954359Sroberto for (i = 0; i < MAXUNITS; i++) 14054359Sroberto memcpy((char *)&refid[i], LEITCHREFID, 4); 14154359Sroberto} 14254359Sroberto 14354359Sroberto/* 14454359Sroberto * leitch_shutdown - shut down a LEITCH clock 14554359Sroberto */ 14654359Srobertostatic void 14754359Srobertoleitch_shutdown( 14854359Sroberto int unit, 14954359Sroberto struct peer *peer 15054359Sroberto ) 15154359Sroberto{ 15254359Sroberto#ifdef DEBUG 15354359Sroberto if (debug) 15454359Sroberto fprintf(stderr, "leitch_shutdown()\n"); 15554359Sroberto#endif 15654359Sroberto} 15754359Sroberto 15854359Sroberto/* 15954359Sroberto * leitch_poll - called by the transmit procedure 16054359Sroberto */ 16154359Srobertostatic void 16254359Srobertoleitch_poll( 16354359Sroberto int unit, 16454359Sroberto struct peer *peer 16554359Sroberto ) 16654359Sroberto{ 16754359Sroberto struct leitchunit *leitch; 16854359Sroberto 16954359Sroberto /* start the state machine rolling */ 17054359Sroberto 17154359Sroberto#ifdef DEBUG 17254359Sroberto if (debug) 17354359Sroberto fprintf(stderr, "leitch_poll()\n"); 17454359Sroberto#endif 175182007Sroberto if (unit >= MAXUNITS) { 17654359Sroberto /* XXXX syslog it */ 17754359Sroberto return; 17854359Sroberto } 17954359Sroberto 18054359Sroberto leitch = &leitchunits[unit]; 18154359Sroberto 18254359Sroberto if (leitch->state != STATE_IDLE) { 18354359Sroberto /* reset and wait for next poll */ 18454359Sroberto /* XXXX syslog it */ 18554359Sroberto leitch->state = STATE_IDLE; 18654359Sroberto } else { 18754359Sroberto leitch_send(leitch,"D\r"); 18854359Sroberto leitch->state = STATE_DATE; 18954359Sroberto } 19054359Sroberto} 19154359Sroberto 19254359Srobertostatic void 19354359Srobertoleitch_control( 19454359Sroberto int unit, 19554359Sroberto struct refclockstat *in, 19654359Sroberto struct refclockstat *out, 19754359Sroberto struct peer *passed_peer 19854359Sroberto ) 19954359Sroberto{ 20054359Sroberto if (unit >= MAXUNITS) { 20154359Sroberto msyslog(LOG_ERR, 20254359Sroberto "leitch_control: unit %d invalid", unit); 20354359Sroberto return; 20454359Sroberto } 20554359Sroberto 20654359Sroberto if (in) { 20754359Sroberto if (in->haveflags & CLK_HAVEVAL1) 20854359Sroberto stratumtouse[unit] = (u_char)(in->fudgeval1); 20954359Sroberto if (in->haveflags & CLK_HAVEVAL2) 21054359Sroberto refid[unit] = in->fudgeval2; 21154359Sroberto if (unitinuse[unit]) { 21254359Sroberto struct peer *peer; 21354359Sroberto 21454359Sroberto peer = (&leitchunits[unit])->peer; 21554359Sroberto peer->stratum = stratumtouse[unit]; 21654359Sroberto peer->refid = refid[unit]; 21754359Sroberto } 21854359Sroberto } 21954359Sroberto 22054359Sroberto if (out) { 22154359Sroberto memset((char *)out, 0, sizeof (struct refclockstat)); 22254359Sroberto out->type = REFCLK_ATOM_LEITCH; 22354359Sroberto out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2; 22454359Sroberto out->fudgeval1 = (int32)stratumtouse[unit]; 22554359Sroberto out->fudgeval2 = refid[unit]; 22654359Sroberto out->p_lastcode = ""; 22754359Sroberto out->clockdesc = LEITCH_DESCRIPTION; 22854359Sroberto } 22954359Sroberto} 23054359Sroberto 23154359Sroberto/* 23254359Sroberto * leitch_start - open the LEITCH devices and initialize data for processing 23354359Sroberto */ 23454359Srobertostatic int 23554359Srobertoleitch_start( 23654359Sroberto int unit, 23754359Sroberto struct peer *peer 23854359Sroberto ) 23954359Sroberto{ 24054359Sroberto struct leitchunit *leitch; 24154359Sroberto int fd232; 24254359Sroberto char leitchdev[20]; 24354359Sroberto 24454359Sroberto /* 24554359Sroberto * Check configuration info. 24654359Sroberto */ 24754359Sroberto if (unit >= MAXUNITS) { 24854359Sroberto msyslog(LOG_ERR, "leitch_start: unit %d invalid", unit); 24954359Sroberto return (0); 25054359Sroberto } 25154359Sroberto 25254359Sroberto if (unitinuse[unit]) { 25354359Sroberto msyslog(LOG_ERR, "leitch_start: unit %d in use", unit); 25454359Sroberto return (0); 25554359Sroberto } 25654359Sroberto 25754359Sroberto /* 25854359Sroberto * Open serial port. 25954359Sroberto */ 26054359Sroberto (void) sprintf(leitchdev, LEITCH232, unit); 26154359Sroberto fd232 = open(leitchdev, O_RDWR, 0777); 26254359Sroberto if (fd232 == -1) { 26354359Sroberto msyslog(LOG_ERR, 26454359Sroberto "leitch_start: open of %s: %m", leitchdev); 26554359Sroberto return (0); 26654359Sroberto } 26754359Sroberto 26854359Sroberto leitch = &leitchunits[unit]; 26954359Sroberto memset((char*)leitch, 0, sizeof(*leitch)); 27054359Sroberto 27154359Sroberto#if defined(HAVE_SYSV_TTYS) 27254359Sroberto /* 27354359Sroberto * System V serial line parameters (termio interface) 27454359Sroberto * 27554359Sroberto */ 27654359Sroberto { struct termio ttyb; 27754359Sroberto if (ioctl(fd232, TCGETA, &ttyb) < 0) { 27854359Sroberto msyslog(LOG_ERR, 27954359Sroberto "leitch_start: ioctl(%s, TCGETA): %m", leitchdev); 28054359Sroberto goto screwed; 28154359Sroberto } 28254359Sroberto ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL; 28354359Sroberto ttyb.c_oflag = 0; 28454359Sroberto ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD; 28554359Sroberto ttyb.c_lflag = ICANON; 28654359Sroberto ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0'; 28754359Sroberto if (ioctl(fd232, TCSETA, &ttyb) < 0) { 28854359Sroberto msyslog(LOG_ERR, 28954359Sroberto "leitch_start: ioctl(%s, TCSETA): %m", leitchdev); 29054359Sroberto goto screwed; 29154359Sroberto } 29254359Sroberto } 29354359Sroberto#endif /* HAVE_SYSV_TTYS */ 29454359Sroberto#if defined(HAVE_TERMIOS) 29554359Sroberto /* 29654359Sroberto * POSIX serial line parameters (termios interface) 29754359Sroberto * 29854359Sroberto * The LEITCHCLK option provides timestamping at the driver level. 29954359Sroberto * It requires the tty_clk streams module. 30054359Sroberto */ 30154359Sroberto { struct termios ttyb, *ttyp; 30254359Sroberto 30354359Sroberto ttyp = &ttyb; 30454359Sroberto if (tcgetattr(fd232, ttyp) < 0) { 30554359Sroberto msyslog(LOG_ERR, 30654359Sroberto "leitch_start: tcgetattr(%s): %m", leitchdev); 30754359Sroberto goto screwed; 30854359Sroberto } 30954359Sroberto ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL; 31054359Sroberto ttyp->c_oflag = 0; 31154359Sroberto ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD; 31254359Sroberto ttyp->c_lflag = ICANON; 31354359Sroberto ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0'; 31454359Sroberto if (tcsetattr(fd232, TCSANOW, ttyp) < 0) { 31554359Sroberto msyslog(LOG_ERR, 31654359Sroberto "leitch_start: tcsetattr(%s): %m", leitchdev); 31754359Sroberto goto screwed; 31854359Sroberto } 31954359Sroberto if (tcflush(fd232, TCIOFLUSH) < 0) { 32054359Sroberto msyslog(LOG_ERR, 32154359Sroberto "leitch_start: tcflush(%s): %m", leitchdev); 32254359Sroberto goto screwed; 32354359Sroberto } 32454359Sroberto } 32554359Sroberto#endif /* HAVE_TERMIOS */ 32654359Sroberto#ifdef STREAM 32754359Sroberto#if defined(LEITCHCLK) 32854359Sroberto if (ioctl(fd232, I_PUSH, "clk") < 0) 32954359Sroberto msyslog(LOG_ERR, 33054359Sroberto "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev); 33154359Sroberto if (ioctl(fd232, CLK_SETSTR, "\n") < 0) 33254359Sroberto msyslog(LOG_ERR, 33354359Sroberto "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev); 33454359Sroberto#endif /* LEITCHCLK */ 33554359Sroberto#endif /* STREAM */ 33654359Sroberto#if defined(HAVE_BSD_TTYS) 33754359Sroberto /* 33854359Sroberto * 4.3bsd serial line parameters (sgttyb interface) 33954359Sroberto * 34054359Sroberto * The LEITCHCLK option provides timestamping at the driver level. 34154359Sroberto * It requires the tty_clk line discipline and 4.3bsd or later. 34254359Sroberto */ 34354359Sroberto { struct sgttyb ttyb; 34454359Sroberto#if defined(LEITCHCLK) 34554359Sroberto int ldisc = CLKLDISC; 34654359Sroberto#endif /* LEITCHCLK */ 34754359Sroberto 34854359Sroberto if (ioctl(fd232, TIOCGETP, &ttyb) < 0) { 34954359Sroberto msyslog(LOG_ERR, 35054359Sroberto "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev); 35154359Sroberto goto screwed; 35254359Sroberto } 35354359Sroberto ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232; 35454359Sroberto#if defined(LEITCHCLK) 35554359Sroberto ttyb.sg_erase = ttyb.sg_kill = '\r'; 35654359Sroberto ttyb.sg_flags = RAW; 35754359Sroberto#else 35854359Sroberto ttyb.sg_erase = ttyb.sg_kill = '\0'; 35954359Sroberto ttyb.sg_flags = EVENP|ODDP|CRMOD; 36054359Sroberto#endif /* LEITCHCLK */ 36154359Sroberto if (ioctl(fd232, TIOCSETP, &ttyb) < 0) { 36254359Sroberto msyslog(LOG_ERR, 36354359Sroberto "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev); 36454359Sroberto goto screwed; 36554359Sroberto } 36654359Sroberto#if defined(LEITCHCLK) 36754359Sroberto if (ioctl(fd232, TIOCSETD, &ldisc) < 0) { 36854359Sroberto msyslog(LOG_ERR, 36954359Sroberto "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev); 37054359Sroberto goto screwed; 37154359Sroberto } 37254359Sroberto#endif /* LEITCHCLK */ 37354359Sroberto } 37454359Sroberto#endif /* HAVE_BSD_TTYS */ 37554359Sroberto 37654359Sroberto /* 37754359Sroberto * Set up the structures 37854359Sroberto */ 37954359Sroberto leitch->peer = peer; 38054359Sroberto leitch->unit = unit; 38154359Sroberto leitch->state = STATE_IDLE; 38254359Sroberto leitch->fudge1 = 15; /* 15ms */ 38354359Sroberto 38454359Sroberto leitch->leitchio.clock_recv = leitch_receive; 38554359Sroberto leitch->leitchio.srcclock = (caddr_t) leitch; 38654359Sroberto leitch->leitchio.datalen = 0; 38754359Sroberto leitch->leitchio.fd = fd232; 38854359Sroberto if (!io_addclock(&leitch->leitchio)) { 38954359Sroberto goto screwed; 39054359Sroberto } 39154359Sroberto 39254359Sroberto /* 39354359Sroberto * All done. Initialize a few random peer variables, then 39454359Sroberto * return success. 39554359Sroberto */ 39654359Sroberto peer->precision = 0; 39754359Sroberto peer->stratum = stratumtouse[unit]; 39854359Sroberto peer->refid = refid[unit]; 39954359Sroberto unitinuse[unit] = 1; 40054359Sroberto return(1); 40154359Sroberto 40254359Sroberto /* 40354359Sroberto * Something broke; abandon ship. 40454359Sroberto */ 40554359Sroberto screwed: 40654359Sroberto close(fd232); 40754359Sroberto return(0); 40854359Sroberto} 40954359Sroberto 41054359Sroberto/* 41154359Sroberto * leitch_receive - receive data from the serial interface on a leitch 41254359Sroberto * clock 41354359Sroberto */ 41454359Srobertostatic void 41554359Srobertoleitch_receive( 41654359Sroberto struct recvbuf *rbufp 41754359Sroberto ) 41854359Sroberto{ 41954359Sroberto struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock; 42054359Sroberto 42154359Sroberto#ifdef DEBUG 42254359Sroberto if (debug) 42354359Sroberto fprintf(stderr, "leitch_recieve(%*.*s)\n", 42454359Sroberto rbufp->recv_length, rbufp->recv_length, 42554359Sroberto rbufp->recv_buffer); 42654359Sroberto#endif 42754359Sroberto if (rbufp->recv_length != 7) 42854359Sroberto return; /* The date is return with a trailing newline, 42954359Sroberto discard it. */ 43054359Sroberto 43154359Sroberto switch (leitch->state) { 43254359Sroberto case STATE_IDLE: /* unexpected, discard and resync */ 43354359Sroberto return; 43454359Sroberto case STATE_DATE: 43554359Sroberto if (!leitch_get_date(rbufp,leitch)) { 43654359Sroberto leitch->state = STATE_IDLE; 43754359Sroberto break; 43854359Sroberto } 43954359Sroberto leitch_send(leitch,"T\r"); 44054359Sroberto#ifdef DEBUG 44154359Sroberto if (debug) 44254359Sroberto fprintf(stderr, "%u\n",leitch->yearday); 44354359Sroberto#endif 44454359Sroberto leitch->state = STATE_TIME1; 44554359Sroberto break; 44654359Sroberto case STATE_TIME1: 44754359Sroberto if (!leitch_get_time(rbufp,leitch,1)) { 44854359Sroberto } 44954359Sroberto if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, 45054359Sroberto leitch->second, 1, rbufp->recv_time.l_ui, 45154359Sroberto &leitch->yearstart, &leitch->reftime1.l_ui)) { 45254359Sroberto leitch->state = STATE_IDLE; 45354359Sroberto break; 45454359Sroberto } 455132451Sroberto leitch->reftime1.l_uf = 0; 45654359Sroberto#ifdef DEBUG 45754359Sroberto if (debug) 45854359Sroberto fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui); 45954359Sroberto#endif 46054359Sroberto MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf); 46154359Sroberto leitch->codetime1 = rbufp->recv_time; 46254359Sroberto leitch->state = STATE_TIME2; 46354359Sroberto break; 46454359Sroberto case STATE_TIME2: 46554359Sroberto if (!leitch_get_time(rbufp,leitch,2)) { 46654359Sroberto } 46754359Sroberto if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, 46854359Sroberto leitch->second, 1, rbufp->recv_time.l_ui, 46954359Sroberto &leitch->yearstart, &leitch->reftime2.l_ui)) { 47054359Sroberto leitch->state = STATE_IDLE; 47154359Sroberto break; 47254359Sroberto } 47354359Sroberto#ifdef DEBUG 47454359Sroberto if (debug) 47554359Sroberto fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui); 47654359Sroberto#endif 47754359Sroberto MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf); 47854359Sroberto leitch->codetime2 = rbufp->recv_time; 47954359Sroberto leitch->state = STATE_TIME3; 48054359Sroberto break; 48154359Sroberto case STATE_TIME3: 48254359Sroberto if (!leitch_get_time(rbufp,leitch,3)) { 48354359Sroberto } 48454359Sroberto if (!clocktime(leitch->yearday,leitch->hour,leitch->minute, 48554359Sroberto leitch->second, GMT, rbufp->recv_time.l_ui, 48654359Sroberto &leitch->yearstart, &leitch->reftime3.l_ui)) { 48754359Sroberto leitch->state = STATE_IDLE; 48854359Sroberto break; 48954359Sroberto } 49054359Sroberto#ifdef DEBUG 49154359Sroberto if (debug) 49254359Sroberto fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui); 49354359Sroberto#endif 49454359Sroberto MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf); 49554359Sroberto leitch->codetime3 = rbufp->recv_time; 49654359Sroberto leitch_process(leitch); 49754359Sroberto leitch->state = STATE_IDLE; 49854359Sroberto break; 49954359Sroberto default: 50054359Sroberto msyslog(LOG_ERR, 50154359Sroberto "leitech_receive: invalid state %d unit %d", 50254359Sroberto leitch->state, leitch->unit); 50354359Sroberto } 50454359Sroberto} 50554359Sroberto 50654359Sroberto/* 50754359Sroberto * leitch_process - process a pile of samples from the clock 50854359Sroberto * 50954359Sroberto * This routine uses a three-stage median filter to calculate offset and 51054359Sroberto * dispersion. reduce jitter. The dispersion is calculated as the span 51154359Sroberto * of the filter (max - min), unless the quality character (format 2) is 51254359Sroberto * non-blank, in which case the dispersion is calculated on the basis of 51354359Sroberto * the inherent tolerance of the internal radio oscillator, which is 51454359Sroberto * +-2e-5 according to the radio specifications. 51554359Sroberto */ 51654359Srobertostatic void 51754359Srobertoleitch_process( 51854359Sroberto struct leitchunit *leitch 51954359Sroberto ) 52054359Sroberto{ 52154359Sroberto l_fp off; 52254359Sroberto l_fp tmp_fp; 52354359Sroberto /*double doffset;*/ 52454359Sroberto 52554359Sroberto off = leitch->reftime1; 52654359Sroberto L_SUB(&off,&leitch->codetime1); 52754359Sroberto tmp_fp = leitch->reftime2; 52854359Sroberto L_SUB(&tmp_fp,&leitch->codetime2); 52954359Sroberto if (L_ISGEQ(&off,&tmp_fp)) 53054359Sroberto off = tmp_fp; 53154359Sroberto tmp_fp = leitch->reftime3; 53254359Sroberto L_SUB(&tmp_fp,&leitch->codetime3); 53354359Sroberto 53454359Sroberto if (L_ISGEQ(&off,&tmp_fp)) 53554359Sroberto off = tmp_fp; 53654359Sroberto /*LFPTOD(&off, doffset);*/ 53754359Sroberto refclock_receive(leitch->peer); 53854359Sroberto} 53954359Sroberto 54054359Sroberto/* 54154359Sroberto * days_per_year 54254359Sroberto */ 54354359Srobertostatic int 54454359Srobertodays_per_year( 54554359Sroberto int year 54654359Sroberto ) 54754359Sroberto{ 54854359Sroberto if (year%4) { /* not a potential leap year */ 54954359Sroberto return (365); 55054359Sroberto } else { 55154359Sroberto if (year % 100) { /* is a leap year */ 55254359Sroberto return (366); 55354359Sroberto } else { 55454359Sroberto if (year % 400) { 55554359Sroberto return (365); 55654359Sroberto } else { 55754359Sroberto return (366); 55854359Sroberto } 55954359Sroberto } 56054359Sroberto } 56154359Sroberto} 56254359Sroberto 56354359Srobertostatic int 56454359Srobertoleitch_get_date( 56554359Sroberto struct recvbuf *rbufp, 56654359Sroberto struct leitchunit *leitch 56754359Sroberto ) 56854359Sroberto{ 56954359Sroberto int i; 57054359Sroberto 57154359Sroberto if (rbufp->recv_length < 6) 57254359Sroberto return(0); 57354359Sroberto#undef BAD /* confict: defined as (-1) in AIX sys/param.h */ 57454359Sroberto#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9') 57554359Sroberto if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) 57654359Sroberto return(0); 57754359Sroberto#define ATOB(A) ((rbufp->recv_buffer[A])-'0') 57854359Sroberto leitch->year = ATOB(0)*10 + ATOB(1); 57954359Sroberto leitch->month = ATOB(2)*10 + ATOB(3); 58054359Sroberto leitch->day = ATOB(4)*10 + ATOB(5); 58154359Sroberto 58254359Sroberto /* sanity checks */ 58354359Sroberto if (leitch->month > 12) 58454359Sroberto return(0); 58554359Sroberto if (leitch->day > days_in_month[leitch->month-1]) 58654359Sroberto return(0); 58754359Sroberto 58854359Sroberto /* calculate yearday */ 58954359Sroberto i = 0; 59054359Sroberto leitch->yearday = leitch->day; 59154359Sroberto 59254359Sroberto while ( i < (leitch->month-1) ) 59354359Sroberto leitch->yearday += days_in_month[i++]; 59454359Sroberto 59554359Sroberto if ((days_per_year((leitch->year>90?1900:2000)+leitch->year)==365) && 59654359Sroberto leitch->month > 2) 59754359Sroberto leitch->yearday--; 59854359Sroberto 59954359Sroberto return(1); 60054359Sroberto} 60154359Sroberto 60254359Sroberto/* 60354359Sroberto * leitch_get_time 60454359Sroberto */ 60554359Srobertostatic int 60654359Srobertoleitch_get_time( 60754359Sroberto struct recvbuf *rbufp, 60854359Sroberto struct leitchunit *leitch, 60954359Sroberto int which 61054359Sroberto ) 61154359Sroberto{ 61254359Sroberto if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5)) 61354359Sroberto return(0); 61454359Sroberto leitch->hour = ATOB(0)*10 +ATOB(1); 61554359Sroberto leitch->minute = ATOB(2)*10 +ATOB(3); 61654359Sroberto leitch->second = ATOB(4)*10 +ATOB(5); 61754359Sroberto 61854359Sroberto if ((leitch->hour > 23) || (leitch->minute > 60) || 61954359Sroberto (leitch->second > 60)) 62054359Sroberto return(0); 62154359Sroberto return(1); 62254359Sroberto} 62354359Sroberto 62454359Sroberto#else 62554359Srobertoint refclock_leitch_bs; 62654359Sroberto#endif /* REFCLOCK */ 627