refclock_tpro.c revision 82498
154359Sroberto/* 254359Sroberto * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader 354359Sroberto */ 454359Sroberto 554359Sroberto#ifdef HAVE_CONFIG_H 654359Sroberto#include <config.h> 754359Sroberto#endif 854359Sroberto 954359Sroberto#if defined(REFCLOCK) && defined(CLOCK_TPRO) 1054359Sroberto 1154359Sroberto#include "ntpd.h" 1254359Sroberto#include "ntp_io.h" 1354359Sroberto#include "ntp_refclock.h" 1454359Sroberto#include "ntp_unixtime.h" 1554359Sroberto#include "sys/tpro.h" 1654359Sroberto#include "ntp_stdlib.h" 1754359Sroberto 1882498Sroberto#include <stdio.h> 1982498Sroberto#include <ctype.h> 2082498Sroberto 2154359Sroberto/* 2254359Sroberto * This driver supports the KSI/Odetecs TPRO-S IRIG-B reader and TPRO- 2354359Sroberto * SAT GPS receiver for the Sun Microsystems SBus. It requires that the 2454359Sroberto * tpro.o device driver be installed and loaded. 2554359Sroberto */ 2654359Sroberto 2754359Sroberto/* 2854359Sroberto * TPRO interface definitions 2954359Sroberto */ 3054359Sroberto#define DEVICE "/dev/tpro%d" /* device name and unit */ 3154359Sroberto#define PRECISION (-20) /* precision assumed (1 us) */ 3254359Sroberto#define REFID "IRIG" /* reference ID */ 3354359Sroberto#define DESCRIPTION "KSI/Odetics TPRO/S IRIG Interface" /* WRU */ 3454359Sroberto 3554359Sroberto/* 3654359Sroberto * Unit control structure 3754359Sroberto */ 3854359Srobertostruct tprounit { 3954359Sroberto struct tproval tprodata; /* data returned from tpro read */ 4054359Sroberto}; 4154359Sroberto 4254359Sroberto/* 4354359Sroberto * Function prototypes 4454359Sroberto */ 4554359Srobertostatic int tpro_start P((int, struct peer *)); 4654359Srobertostatic void tpro_shutdown P((int, struct peer *)); 4754359Srobertostatic void tpro_poll P((int unit, struct peer *)); 4854359Sroberto 4954359Sroberto/* 5054359Sroberto * Transfer vector 5154359Sroberto */ 5254359Srobertostruct refclock refclock_tpro = { 5354359Sroberto tpro_start, /* start up driver */ 5454359Sroberto tpro_shutdown, /* shut down driver */ 5554359Sroberto tpro_poll, /* transmit poll message */ 5654359Sroberto noentry, /* not used (old tpro_control) */ 5754359Sroberto noentry, /* initialize driver (not used) */ 5854359Sroberto noentry, /* not used (old tpro_buginfo) */ 5954359Sroberto NOFLAGS /* not used */ 6054359Sroberto}; 6154359Sroberto 6254359Sroberto 6354359Sroberto/* 6454359Sroberto * tpro_start - open the TPRO device and initialize data for processing 6554359Sroberto */ 6654359Srobertostatic int 6754359Srobertotpro_start( 6854359Sroberto int unit, 6954359Sroberto struct peer *peer 7054359Sroberto ) 7154359Sroberto{ 7254359Sroberto register struct tprounit *up; 7354359Sroberto struct refclockproc *pp; 7454359Sroberto char device[20]; 7554359Sroberto int fd; 7654359Sroberto 7754359Sroberto /* 7854359Sroberto * Open TPRO device 7954359Sroberto */ 8054359Sroberto (void)sprintf(device, DEVICE, unit); 8154359Sroberto fd = open(device, O_RDONLY | O_NDELAY, 0777); 8254359Sroberto if (fd == -1) { 8354359Sroberto msyslog(LOG_ERR, "tpro_start: open of %s: %m", device); 8454359Sroberto return (0); 8554359Sroberto } 8654359Sroberto 8754359Sroberto /* 8854359Sroberto * Allocate and initialize unit structure 8954359Sroberto */ 9054359Sroberto if (!(up = (struct tprounit *) emalloc(sizeof(struct tprounit)))) { 9154359Sroberto (void) close(fd); 9254359Sroberto return (0); 9354359Sroberto } 9454359Sroberto memset((char *)up, 0, sizeof(struct tprounit)); 9554359Sroberto pp = peer->procptr; 9654359Sroberto pp->io.clock_recv = noentry; 9754359Sroberto pp->io.srcclock = (caddr_t)peer; 9854359Sroberto pp->io.datalen = 0; 9954359Sroberto pp->io.fd = fd; 10054359Sroberto pp->unitptr = (caddr_t)up; 10154359Sroberto 10254359Sroberto /* 10354359Sroberto * Initialize miscellaneous peer variables 10454359Sroberto */ 10554359Sroberto peer->precision = PRECISION; 10654359Sroberto peer->burst = NSTAGE; 10754359Sroberto pp->clockdesc = DESCRIPTION; 10854359Sroberto memcpy((char *)&pp->refid, REFID, 4); 10954359Sroberto return (1); 11054359Sroberto} 11154359Sroberto 11254359Sroberto 11354359Sroberto/* 11454359Sroberto * tpro_shutdown - shut down the clock 11554359Sroberto */ 11654359Srobertostatic void 11754359Srobertotpro_shutdown( 11854359Sroberto int unit, 11954359Sroberto struct peer *peer 12054359Sroberto ) 12154359Sroberto{ 12254359Sroberto register struct tprounit *up; 12354359Sroberto struct refclockproc *pp; 12454359Sroberto 12554359Sroberto pp = peer->procptr; 12654359Sroberto up = (struct tprounit *)pp->unitptr; 12754359Sroberto io_closeclock(&pp->io); 12854359Sroberto free(up); 12954359Sroberto} 13054359Sroberto 13154359Sroberto 13254359Sroberto/* 13354359Sroberto * tpro_poll - called by the transmit procedure 13454359Sroberto */ 13554359Srobertostatic void 13654359Srobertotpro_poll( 13754359Sroberto int unit, 13854359Sroberto struct peer *peer 13954359Sroberto ) 14054359Sroberto{ 14154359Sroberto register struct tprounit *up; 14254359Sroberto struct refclockproc *pp; 14354359Sroberto struct tproval *tp; 14454359Sroberto 14554359Sroberto /* 14654359Sroberto * This is the main routine. It snatches the time from the TPRO 14754359Sroberto * board and tacks on a local timestamp. 14854359Sroberto */ 14954359Sroberto pp = peer->procptr; 15054359Sroberto up = (struct tprounit *)pp->unitptr; 15154359Sroberto 15254359Sroberto tp = &up->tprodata; 15354359Sroberto if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) { 15454359Sroberto refclock_report(peer, CEVNT_FAULT); 15554359Sroberto return; 15654359Sroberto } 15754359Sroberto get_systime(&pp->lastrec); 15854359Sroberto pp->polls++; 15954359Sroberto 16054359Sroberto /* 16154359Sroberto * We get down to business, check the timecode format and decode 16254359Sroberto * its contents. If the timecode has invalid length or is not in 16354359Sroberto * proper format, we declare bad format and exit. Note: we 16454359Sroberto * can't use the sec/usec conversion produced by the driver, 16554359Sroberto * since the year may be suspect. All format error checking is 16654359Sroberto * done by the sprintf() and sscanf() routines. 16754359Sroberto */ 16854359Sroberto sprintf(pp->a_lastcode, 16954359Sroberto "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", 17054359Sroberto tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1, 17154359Sroberto tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100, 17254359Sroberto tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1, 17354359Sroberto tp->status); 17454359Sroberto pp->lencode = strlen(pp->a_lastcode); 17554359Sroberto#ifdef DEBUG 17654359Sroberto if (debug) 17754359Sroberto printf("tpro: time %s timecode %d %s\n", 17854359Sroberto ulfptoa(&pp->lastrec, 6), pp->lencode, 17954359Sroberto pp->a_lastcode); 18054359Sroberto#endif 18154359Sroberto if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day, 18254359Sroberto &pp->hour, &pp->minute, &pp->second, &pp->usec) 18354359Sroberto != 5) { 18454359Sroberto refclock_report(peer, CEVNT_BADTIME); 18554359Sroberto return; 18654359Sroberto } 18754359Sroberto if (!tp->status & 0x3) 18854359Sroberto pp->leap = LEAP_NOTINSYNC; 18954359Sroberto else 19054359Sroberto pp->leap = LEAP_NOWARNING; 19154359Sroberto if (!refclock_process(pp)) { 19254359Sroberto refclock_report(peer, CEVNT_BADTIME); 19354359Sroberto return; 19454359Sroberto } 19554359Sroberto if (peer->burst > 0) 19654359Sroberto return; 19754359Sroberto if (pp->coderecv == pp->codeproc) { 19854359Sroberto refclock_report(peer, CEVNT_TIMEOUT); 19954359Sroberto return; 20054359Sroberto } 20154359Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 20254359Sroberto refclock_receive(peer); 20354359Sroberto peer->burst = NSTAGE; 20454359Sroberto} 20554359Sroberto 20654359Sroberto#else 20754359Srobertoint refclock_tpro_bs; 20854359Sroberto#endif /* REFCLOCK */ 209