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