1106163Sroberto/* 2106163Sroberto * refclock_tt560 - clock driver for the TrueTime 560 IRIG-B decoder 3106163Sroberto */ 4106163Sroberto 5106163Sroberto#ifdef HAVE_CONFIG_H 6106163Sroberto#include <config.h> 7106163Sroberto#endif 8106163Sroberto 9106163Sroberto#if defined(REFCLOCK) && defined(CLOCK_TT560) 10106163Sroberto 11106163Sroberto#include "ntpd.h" 12106163Sroberto#include "ntp_io.h" 13106163Sroberto#include "ntp_refclock.h" 14106163Sroberto#include "ntp_unixtime.h" 15106163Sroberto#include "sys/tt560_api.h" 16106163Sroberto#include "ntp_stdlib.h" 17106163Sroberto 18106163Sroberto#include <stdio.h> 19106163Sroberto#include <ctype.h> 20106163Sroberto 21106163Sroberto/* 22106163Sroberto * This driver supports the TrueTime 560 IRIG-B decoder for the PCI bus. 23106163Sroberto */ 24106163Sroberto 25106163Sroberto/* 26106163Sroberto * TT560 interface definitions 27106163Sroberto */ 28106163Sroberto#define DEVICE "/dev/tt560%d" /* device name and unit */ 29106163Sroberto#define PRECISION (-20) /* precision assumed (1 us) */ 30106163Sroberto#define REFID "IRIG" /* reference ID */ 31106163Sroberto#define DESCRIPTION "TrueTime 560 IRIG-B PCI Decoder" 32106163Sroberto 33106163Sroberto/* 34106163Sroberto * Unit control structure 35106163Sroberto */ 36106163Srobertostruct tt560unit { 37106163Sroberto tt_mem_space_t *tt_mem; /* mapped address of PCI board */ 38106163Sroberto time_freeze_reg_t tt560rawt; /* data returned from PCI board */ 39106163Sroberto}; 40106163Sroberto 41106163Srobertotypedef union byteswap_u 42106163Sroberto{ 43106163Sroberto unsigned int long_word; 44106163Sroberto unsigned char byte[4]; 45106163Sroberto} byteswap_t; 46106163Sroberto 47106163Sroberto/* 48106163Sroberto * Function prototypes 49106163Sroberto */ 50280849Scystatic int tt560_start (int, struct peer *); 51280849Scystatic void tt560_shutdown (int, struct peer *); 52280849Scystatic void tt560_poll (int unit, struct peer *); 53106163Sroberto 54106163Sroberto/* 55106163Sroberto * Transfer vector 56106163Sroberto */ 57106163Srobertostruct refclock refclock_tt560 = { 58106163Sroberto tt560_start, /* clock_start */ 59106163Sroberto tt560_shutdown, /* clock_shutdown */ 60106163Sroberto tt560_poll, /* clock_poll */ 61106163Sroberto noentry, /* clock_control (not used) */ 62106163Sroberto noentry, /* clock_init (not used) */ 63106163Sroberto noentry, /* clock_buginfo (not used) */ 64106163Sroberto NOFLAGS /* clock_flags (not used) */ 65106163Sroberto}; 66106163Sroberto 67106163Sroberto 68106163Sroberto/* 69106163Sroberto * tt560_start - open the TT560 device and initialize data for processing 70106163Sroberto */ 71106163Srobertostatic int 72106163Srobertott560_start( 73106163Sroberto int unit, 74106163Sroberto struct peer *peer 75106163Sroberto ) 76106163Sroberto{ 77106163Sroberto register struct tt560unit *up; 78106163Sroberto struct refclockproc *pp; 79280849Scy char device[20]; 80280849Scy int fd; 81280849Scy caddr_t membase; 82106163Sroberto 83106163Sroberto /* 84106163Sroberto * Open TT560 device 85106163Sroberto */ 86280849Scy snprintf(device, sizeof(device), DEVICE, unit); 87106163Sroberto fd = open(device, O_RDWR); 88106163Sroberto if (fd == -1) { 89106163Sroberto msyslog(LOG_ERR, "tt560_start: open of %s: %m", device); 90106163Sroberto return (0); 91106163Sroberto } 92106163Sroberto 93106163Sroberto /* 94106163Sroberto * Map the device registers into user space. 95106163Sroberto */ 96106163Sroberto membase = mmap ((caddr_t) 0, TTIME_MEMORY_SIZE, 97106163Sroberto PROT_READ | PROT_WRITE, 98106163Sroberto MAP_SHARED, fd, (off_t)0); 99106163Sroberto 100106163Sroberto if (membase == (caddr_t) -1) { 101106163Sroberto msyslog(LOG_ERR, "tt560_start: mapping of %s: %m", device); 102106163Sroberto (void) close(fd); 103106163Sroberto return (0); 104106163Sroberto } 105106163Sroberto 106106163Sroberto /* 107106163Sroberto * Allocate and initialize unit structure 108106163Sroberto */ 109106163Sroberto if (!(up = (struct tt560unit *) emalloc(sizeof(struct tt560unit)))) { 110106163Sroberto (void) close(fd); 111106163Sroberto return (0); 112106163Sroberto } 113106163Sroberto memset((char *)up, 0, sizeof(struct tt560unit)); 114106163Sroberto up->tt_mem = (tt_mem_space_t *)membase; 115106163Sroberto pp = peer->procptr; 116106163Sroberto pp->io.clock_recv = noentry; 117106163Sroberto pp->io.srcclock = (caddr_t)peer; 118106163Sroberto pp->io.datalen = 0; 119106163Sroberto pp->io.fd = fd; 120106163Sroberto pp->unitptr = (caddr_t)up; 121106163Sroberto 122106163Sroberto /* 123106163Sroberto * Initialize miscellaneous peer variables 124106163Sroberto */ 125106163Sroberto peer->precision = PRECISION; 126106163Sroberto pp->clockdesc = DESCRIPTION; 127106163Sroberto memcpy((char *)&pp->refid, REFID, 4); 128106163Sroberto return (1); 129106163Sroberto} 130106163Sroberto 131106163Sroberto 132106163Sroberto/* 133106163Sroberto * tt560_shutdown - shut down the clock 134106163Sroberto */ 135106163Srobertostatic void 136106163Srobertott560_shutdown( 137106163Sroberto int unit, 138106163Sroberto struct peer *peer 139106163Sroberto ) 140106163Sroberto{ 141106163Sroberto register struct tt560unit *up; 142106163Sroberto struct refclockproc *pp; 143106163Sroberto 144106163Sroberto pp = peer->procptr; 145106163Sroberto up = (struct tt560unit *)pp->unitptr; 146106163Sroberto io_closeclock(&pp->io); 147106163Sroberto free(up); 148106163Sroberto} 149106163Sroberto 150106163Sroberto 151106163Sroberto/* 152106163Sroberto * tt560_poll - called by the transmit procedure 153106163Sroberto */ 154106163Srobertostatic void 155106163Srobertott560_poll( 156106163Sroberto int unit, 157106163Sroberto struct peer *peer 158106163Sroberto ) 159106163Sroberto{ 160106163Sroberto register struct tt560unit *up; 161106163Sroberto struct refclockproc *pp; 162106163Sroberto time_freeze_reg_t *tp; 163106163Sroberto tt_mem_space_t *mp; 164106163Sroberto 165106163Sroberto int i; 166106163Sroberto unsigned int *p_time_t, *tt_mem_t; 167106163Sroberto 168106163Sroberto /* 169106163Sroberto * This is the main routine. It snatches the time from the TT560 170106163Sroberto * board and tacks on a local timestamp. 171106163Sroberto */ 172106163Sroberto pp = peer->procptr; 173106163Sroberto up = (struct tt560unit *)pp->unitptr; 174106163Sroberto mp = up->tt_mem; 175106163Sroberto tp = &up->tt560rawt; 176106163Sroberto 177106163Sroberto p_time_t = (unsigned int *)tp; 178106163Sroberto tt_mem_t = (unsigned int *)&mp->time_freeze_reg; 179106163Sroberto 180106163Sroberto *tt_mem_t = 0; /* update the time freeze register */ 181106163Sroberto /* and copy time stamp to memory */ 182106163Sroberto for (i=0; i < TIME_FREEZE_REG_LEN; i++) { 183106163Sroberto *p_time_t = byte_swap(*tt_mem_t); 184106163Sroberto p_time_t++; 185106163Sroberto tt_mem_t++; 186106163Sroberto } 187106163Sroberto 188106163Sroberto get_systime(&pp->lastrec); 189106163Sroberto pp->polls++; 190106163Sroberto 191106163Sroberto /* 192106163Sroberto * We get down to business, check the timecode format and decode 193106163Sroberto * its contents. If the timecode has invalid length or is not in 194106163Sroberto * proper format, we declare bad format and exit. Note: we 195106163Sroberto * can't use the sec/usec conversion produced by the driver, 196106163Sroberto * since the year may be suspect. All format error checking is 197280849Scy * done by the snprintf() and sscanf() routines. 198106163Sroberto */ 199280849Scy snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), 200106163Sroberto "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", 201106163Sroberto tp->hun_day, tp->tens_day, tp->unit_day, 202106163Sroberto tp->tens_hour, tp->unit_hour, 203106163Sroberto tp->tens_min, tp->unit_min, 204106163Sroberto tp->tens_sec, tp->unit_sec, 205106163Sroberto tp->hun_ms, tp->tens_ms, tp->unit_ms, 206106163Sroberto tp->hun_us, tp->tens_us, tp->unit_us, 207106163Sroberto tp->status); 208106163Sroberto pp->lencode = strlen(pp->a_lastcode); 209106163Sroberto#ifdef DEBUG 210106163Sroberto if (debug) 211106163Sroberto printf("tt560: time %s timecode %d %s\n", 212106163Sroberto ulfptoa(&pp->lastrec, 6), pp->lencode, 213106163Sroberto pp->a_lastcode); 214106163Sroberto#endif 215106163Sroberto if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", 216106163Sroberto &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->usec) 217106163Sroberto != 5) { 218106163Sroberto refclock_report(peer, CEVNT_BADTIME); 219106163Sroberto return; 220106163Sroberto } 221106163Sroberto if ((tp->status & 0x6) != 0x6) 222106163Sroberto pp->leap = LEAP_NOTINSYNC; 223106163Sroberto else 224106163Sroberto pp->leap = LEAP_NOWARNING; 225106163Sroberto if (!refclock_process(pp)) { 226106163Sroberto refclock_report(peer, CEVNT_BADTIME); 227106163Sroberto return; 228106163Sroberto } 229106163Sroberto if (pp->coderecv == pp->codeproc) { 230106163Sroberto refclock_report(peer, CEVNT_TIMEOUT); 231106163Sroberto return; 232106163Sroberto } 233106163Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 234106163Sroberto refclock_receive(peer); 235106163Sroberto} 236106163Sroberto 237106163Sroberto/****************************************************************** 238106163Sroberto * 239106163Sroberto * byte_swap 240106163Sroberto * 241106163Sroberto * Inputs: 32 bit integer 242106163Sroberto * 243106163Sroberto * Output: byte swapped 32 bit integer. 244106163Sroberto * 245106163Sroberto * This routine is used to compensate for the byte alignment 246106163Sroberto * differences between big-endian and little-endian integers. 247106163Sroberto * 248106163Sroberto ******************************************************************/ 249106163Srobertostatic unsigned int 250106163Srobertobyte_swap(unsigned int input_num) 251106163Sroberto{ 252106163Sroberto byteswap_t byte_swap; 253106163Sroberto unsigned char temp; 254106163Sroberto 255106163Sroberto byte_swap.long_word = input_num; 256106163Sroberto 257106163Sroberto temp = byte_swap.byte[3]; 258106163Sroberto byte_swap.byte[3] = byte_swap.byte[0]; 259106163Sroberto byte_swap.byte[0] = temp; 260106163Sroberto 261106163Sroberto temp = byte_swap.byte[2]; 262106163Sroberto byte_swap.byte[2] = byte_swap.byte[1]; 263106163Sroberto byte_swap.byte[1] = temp; 264106163Sroberto 265106163Sroberto return (byte_swap.long_word); 266106163Sroberto} 267106163Sroberto 268106163Sroberto#else 269106163Srobertoint refclock_tt560_bs; 270106163Sroberto#endif /* REFCLOCK */ 271