154359Sroberto/* refclock_bancomm.c - clock driver for the Datum/Bancomm bc635VME 254359Sroberto * Time and Frequency Processor. It requires the BANCOMM bc635VME/ 354359Sroberto * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x 454359Sroberto * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc 554359Sroberto * IIi-cEngine running Solaris 2.6. 654359Sroberto * 754359Sroberto * Author(s): Ganesh Ramasivan & Gary Cliff, Computing Devices Canada, 854359Sroberto * Ottawa, Canada 954359Sroberto * 1054359Sroberto * Date: July 1999 1154359Sroberto * 1254359Sroberto * Note(s): The refclock type has been defined as 16. 1354359Sroberto * 1454359Sroberto * This program has been modelled after the Bancomm driver 1554359Sroberto * originally written by R. Schmidt of Time Service, U.S. 1654359Sroberto * Naval Observatory for a HP-UX machine. Since the original 1754359Sroberto * authors no longer plan to maintain this code, all 1854359Sroberto * references to the HP-UX vme2 driver subsystem bave been 1954359Sroberto * removed. Functions vme_report_event(), vme_receive(), 2054359Sroberto * vme_control() and vme_buginfo() have been deleted because 2154359Sroberto * they are no longer being used. 2254359Sroberto * 23182007Sroberto * 04/28/2005 Rob Neal 24182007Sroberto * Modified to add support for Symmetricom bc637PCI-U Time & 25182007Sroberto * Frequency Processor. 26290001Sglebius * 2/21/2007 Ali Ghorashi 27290001Sglebius * Modified to add support for Symmetricom bc637PCI-U Time & 28290001Sglebius * Frequency Processor on Solaris. 29290001Sglebius * Tested on Solaris 10 with a bc635 card. 30290001Sglebius * 31182007Sroberto * Card bus type (VME/VXI or PCI) and environment are specified via the 32182007Sroberto * "mode" keyword on the server command in ntp.conf. 33290001Sglebius * server 127.127.16.u prefer mode M 34290001Sglebius * where u is the id (usually 0) of the entry in /dev (/dev/stfp0) 35290001Sglebius * 36290001Sglebius * and M is one of the following modes: 37182007Sroberto * 1 : FreeBSD PCI 635/637. 38182007Sroberto * 2 : Linux or Windows PCI 635/637. 39290001Sglebius * 3 : Solaris PCI 635/637 40182007Sroberto * not specified, or other number: 41182007Sroberto * : Assumed to be VME/VXI legacy Bancomm card on Solaris. 42182007Sroberto * Linux and Windows platforms require Symmetricoms' proprietary driver 43290001Sglebius * for the TFP card. 44290001Sglebius * Solaris requires Symmetricom's driver and its header file (freely distributed) to 45290001Sglebius * be installed and running. 4654359Sroberto */ 4754359Sroberto 4854359Sroberto#ifdef HAVE_CONFIG_H 4954359Sroberto#include <config.h> 5054359Sroberto#endif 5154359Sroberto 5254359Sroberto#if defined(REFCLOCK) && defined(CLOCK_BANC) 5354359Sroberto 5454359Sroberto#include "ntpd.h" 5554359Sroberto#include "ntp_io.h" 5654359Sroberto#include "ntp_refclock.h" 5754359Sroberto#include "ntp_unixtime.h" 5854359Sroberto#include "ntp_stdlib.h" 5954359Sroberto 6082498Sroberto#include <stdio.h> 6182498Sroberto#include <syslog.h> 6282498Sroberto#include <ctype.h> 6382498Sroberto 6454359Srobertostruct btfp_time /* Structure for reading 5 time words */ 6554359Sroberto /* in one ioctl(2) operation. */ 6654359Sroberto{ 6754359Sroberto unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/ 6854359Sroberto}; 6954359Sroberto/* SunOS5 ioctl commands definitions.*/ 7054359Sroberto#define BTFPIOC ( 'b'<< 8 ) 7154359Sroberto#define IOCIO( l, n ) ( BTFPIOC | n ) 7254359Sroberto#define IOCIOR( l, n, s ) ( BTFPIOC | n ) 7354359Sroberto#define IOCIORN( l, n, s ) ( BTFPIOC | n ) 7454359Sroberto#define IOCIOWN( l, n, s ) ( BTFPIOC | n ) 7554359Sroberto 7654359Sroberto/***** Simple ioctl commands *****/ 7754359Sroberto#define RUNLOCK IOCIOR(b, 19, int ) /* Release Capture Lockout */ 7854359Sroberto#define RCR0 IOCIOR(b, 22, int ) /* Read control register zero.*/ 7954359Sroberto#define WCR0 IOCIOWN(b, 23, int) /* Write control register zero*/ 8054359Sroberto/***** Compound ioctl commands *****/ 8154359Sroberto 8254359Sroberto/* Read all 5 time words in one call. */ 8354359Sroberto#define READTIME IOCIORN(b, 32, sizeof( struct btfp_time )) 84182007Sroberto 85182007Sroberto#if defined(__FreeBSD__) 86182007Sroberto#undef READTIME 87182007Sroberto#define READTIME _IOR('u', 5, struct btfp_time ) 88182007Sroberto#endif 89182007Sroberto 90290001Sglebius/* Solaris specific section */ 91290001Sglebiusstruct stfp_tm { 92290001Sglebius int32_t tm_sec; 93290001Sglebius int32_t tm_min; 94290001Sglebius int32_t tm_hour; 95290001Sglebius int32_t tm_mday; 96290001Sglebius int32_t tm_mon; 97290001Sglebius int32_t tm_year; 98290001Sglebius int32_t tm_wday; 99290001Sglebius int32_t tm_yday; 100290001Sglebius int32_t tm_isdst; 101290001Sglebius}; 10254359Sroberto 103290001Sglebiusstruct stfp_time { 104290001Sglebius struct stfp_tm tm; 105290001Sglebius int32_t usec; /* usec 0 - 999999 */ 106290001Sglebius int32_t hnsec; /* hnsec 0 - 9 (hundreds of nsecs) */ 107290001Sglebius int32_t status; 108290001Sglebius}; 109290001Sglebius 110290001Sglebius#define SELTIMEFORMAT 2 111290001Sglebius# define TIME_DECIMAL 0 112290001Sglebius# define TIME_BINARY 1 113290001Sglebius 114290001Sglebius#if defined(__sun__) 115290001Sglebius#undef READTIME 116290001Sglebius#define READTIME 9 117290001Sglebius#endif /** __sun___ **/ 118290001Sglebius/* end solaris specific section */ 119290001Sglebius 120290001Sglebiusstruct vmedate { /* structure returned by get_vmetime.c */ 12154359Sroberto unsigned short year; 12254359Sroberto unsigned short day; 12354359Sroberto unsigned short hr; 12454359Sroberto unsigned short mn; 12554359Sroberto unsigned short sec; 126182007Sroberto long frac; 12754359Sroberto unsigned short status; 12854359Sroberto}; 12954359Sroberto 130182007Srobertotypedef void *SYMMT_PCI_HANDLE; 13154359Sroberto 13254359Sroberto/* 13354359Sroberto * VME interface parameters. 13454359Sroberto */ 13554359Sroberto#define VMEPRECISION (-21) /* precision assumed (1 us) */ 13654359Sroberto#define USNOREFID "BTFP" /* or whatever */ 13754359Sroberto#define VMEREFID "BTFP" /* reference id */ 13854359Sroberto#define VMEDESCRIPTION "Bancomm bc635 TFP" /* who we are */ 13954359Sroberto#define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */ 14054359Sroberto/* clock type 16 is used here */ 14154359Sroberto#define GMT 0 /* hour offset from Greenwich */ 14254359Sroberto 14354359Sroberto/* 14454359Sroberto * Imported from ntp_timer module 14554359Sroberto */ 14654359Srobertoextern u_long current_time; /* current time(s) */ 14754359Sroberto 14854359Sroberto/* 14954359Sroberto * VME unit control structure. 15054359Sroberto * Changes made to vmeunit structure. Most members are now available in the 15154359Sroberto * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan 15254359Sroberto */ 15354359Srobertostruct vmeunit { 15454359Sroberto struct vmedate vmedata; /* data returned from vme read */ 15554359Sroberto u_long lasttime; /* last time clock heard from */ 15654359Sroberto}; 15754359Sroberto 15854359Sroberto/* 15954359Sroberto * Function prototypes 16054359Sroberto */ 16154359Srobertostatic int vme_start (int, struct peer *); 16254359Srobertostatic void vme_shutdown (int, struct peer *); 16354359Srobertostatic void vme_receive (struct recvbuf *); 16454359Srobertostatic void vme_poll (int unit, struct peer *); 165182007Srobertostruct vmedate *get_datumtime(struct vmedate *); 166290001Sglebiusvoid tvme_fill(struct vmedate *, uint32_t btm[2]); 167290001Sglebiusvoid stfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp); 168290001Sglebiusinline const char *DEVICE_NAME(int n); 169290001Sglebius 170290001Sglebius 171182007Sroberto/* 172182007Sroberto * Define the bc*() functions as weak so we can compile/link without them. 173182007Sroberto * Only clients with the card will have the proprietary vendor device driver 174182007Sroberto * and interface library needed for use on Linux/Windows platforms. 175182007Sroberto */ 176182007Srobertoextern uint32_t __attribute__ ((weak)) bcReadBinTime(SYMMT_PCI_HANDLE, uint32_t *, uint32_t*, uint8_t*); 177182007Srobertoextern SYMMT_PCI_HANDLE __attribute__ ((weak)) bcStartPci(void); 178182007Srobertoextern void __attribute__ ((weak)) bcStopPci(SYMMT_PCI_HANDLE); 17954359Sroberto 18054359Sroberto/* 18154359Sroberto * Transfer vector 18254359Sroberto */ 18354359Srobertostruct refclock refclock_bancomm = { 18482498Sroberto vme_start, /* start up driver */ 18582498Sroberto vme_shutdown, /* shut down driver */ 18682498Sroberto vme_poll, /* transmit poll message */ 18782498Sroberto noentry, /* not used (old vme_control) */ 18882498Sroberto noentry, /* initialize driver */ 18982498Sroberto noentry, /* not used (old vme_buginfo) */ 19082498Sroberto NOFLAGS /* not used */ 19154359Sroberto}; 19254359Sroberto 19354359Srobertoint fd_vme; /* file descriptor for ioctls */ 19454359Srobertoint regvalue; 195182007Srobertoint tfp_type; /* mode selector, indicate platform and driver interface */ 196182007SrobertoSYMMT_PCI_HANDLE stfp_handle; 19754359Sroberto 198290001Sglebius/** 199290001Sglebius * this macro returns the device name based on 200290001Sglebius * the platform we are running on and the device number 201290001Sglebius */ 202290001Sglebius#if defined(__sun__) 203290001Sglebiusinline const char *DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/stfp%d",n);return s;} 204290001Sglebius#else 205290001Sglebiusinline const char* DEVICE_NAME(int n) {static char s[20]={0}; snprintf(s,19,"/dev/btfp%d",n);return s;} 206290001Sglebius#endif /**__sun__**/ 20754359Sroberto 20854359Sroberto/* 20954359Sroberto * vme_start - open the VME device and initialize data for processing 21054359Sroberto */ 21154359Srobertostatic int 21254359Srobertovme_start( 21354359Sroberto int unit, 21454359Sroberto struct peer *peer 21554359Sroberto ) 21654359Sroberto{ 21754359Sroberto register struct vmeunit *vme; 21854359Sroberto struct refclockproc *pp; 21954359Sroberto int dummy; 22054359Sroberto char vmedev[20]; 221182007Sroberto 222182007Sroberto tfp_type = (int)(peer->ttl); 223182007Sroberto switch (tfp_type) { 224182007Sroberto case 1: 225290001Sglebius case 3: 226182007Sroberto break; 227182007Sroberto case 2: 228182007Sroberto stfp_handle = bcStartPci(); /* init the card in lin/win */ 229182007Sroberto break; 230182007Sroberto default: 231182007Sroberto break; 232182007Sroberto } 23354359Sroberto /* 23454359Sroberto * Open VME device 23554359Sroberto */ 23654359Sroberto#ifdef DEBUG 23754359Sroberto 238290001Sglebius printf("Opening DATUM DEVICE %s\n",DEVICE_NAME(peer->refclkunit)); 23954359Sroberto#endif 240290001Sglebius if ( (fd_vme = open(DEVICE_NAME(peer->refclkunit), O_RDWR)) < 0) { 24154359Sroberto msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev); 24254359Sroberto return (0); 24354359Sroberto } 244182007Sroberto else { 245182007Sroberto switch (tfp_type) { 246182007Sroberto case 1: break; 247182007Sroberto case 2: break; 248290001Sglebius case 3:break; 249182007Sroberto default: 250182007Sroberto /* Release capture lockout in case it was set before. */ 251182007Sroberto if( ioctl( fd_vme, RUNLOCK, &dummy ) ) 252182007Sroberto msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m"); 25354359Sroberto 254182007Sroberto regvalue = 0; /* More esoteric stuff to do... */ 255182007Sroberto if( ioctl( fd_vme, WCR0, ®value ) ) 256182007Sroberto msyslog(LOG_ERR, "vme_start: WCR0 failed %m"); 257182007Sroberto break; 258182007Sroberto } 25954359Sroberto } 26054359Sroberto 26154359Sroberto /* 26254359Sroberto * Allocate unit structure 26354359Sroberto */ 264290001Sglebius vme = emalloc_zero(sizeof(struct vmeunit)); 26554359Sroberto 26654359Sroberto 26754359Sroberto /* 26854359Sroberto * Set up the structures 26954359Sroberto */ 27054359Sroberto pp = peer->procptr; 271290001Sglebius pp->unitptr = vme; 27254359Sroberto pp->timestarted = current_time; 27354359Sroberto 27454359Sroberto pp->io.clock_recv = vme_receive; 275290001Sglebius pp->io.srcclock = peer; 27654359Sroberto pp->io.datalen = 0; 27754359Sroberto pp->io.fd = fd_vme; 278290001Sglebius /* shouldn't there be an io_addclock() call? */ 27954359Sroberto 28054359Sroberto /* 28154359Sroberto * All done. Initialize a few random peer variables, then 28254359Sroberto * return success. Note that root delay and root dispersion are 28354359Sroberto * always zero for this clock. 28454359Sroberto */ 28554359Sroberto peer->precision = VMEPRECISION; 28682498Sroberto memcpy(&pp->refid, USNOREFID,4); 28754359Sroberto return (1); 28854359Sroberto} 28954359Sroberto 29054359Sroberto 29154359Sroberto/* 29254359Sroberto * vme_shutdown - shut down a VME clock 29354359Sroberto */ 29454359Srobertostatic void 29554359Srobertovme_shutdown( 29654359Sroberto int unit, 29754359Sroberto struct peer *peer 29854359Sroberto ) 29954359Sroberto{ 30054359Sroberto register struct vmeunit *vme; 30154359Sroberto struct refclockproc *pp; 30254359Sroberto 30354359Sroberto /* 30454359Sroberto * Tell the I/O module to turn us off. We're history. 30554359Sroberto */ 30682498Sroberto pp = peer->procptr; 307290001Sglebius vme = pp->unitptr; 30854359Sroberto io_closeclock(&pp->io); 30954359Sroberto pp->unitptr = NULL; 310290001Sglebius if (NULL != vme) 311290001Sglebius free(vme); 312290001Sglebius if (tfp_type == 2) 313290001Sglebius bcStopPci(stfp_handle); 31454359Sroberto} 31554359Sroberto 31654359Sroberto 31754359Sroberto/* 31854359Sroberto * vme_receive - receive data from the VME device. 31954359Sroberto * 32054359Sroberto * Note: This interface would be interrupt-driven. We don't use that 32154359Sroberto * now, but include a dummy routine for possible future adventures. 32254359Sroberto */ 32354359Srobertostatic void 32454359Srobertovme_receive( 32554359Sroberto struct recvbuf *rbufp 32654359Sroberto ) 32754359Sroberto{ 32854359Sroberto} 32954359Sroberto 33054359Sroberto 33154359Sroberto/* 33254359Sroberto * vme_poll - called by the transmit procedure 33354359Sroberto */ 33454359Srobertostatic void 33554359Srobertovme_poll( 33654359Sroberto int unit, 33754359Sroberto struct peer *peer 33854359Sroberto ) 33954359Sroberto{ 34054359Sroberto struct vmedate *tptr; 34154359Sroberto struct vmeunit *vme; 34254359Sroberto struct refclockproc *pp; 34354359Sroberto time_t tloc; 34454359Sroberto struct tm *tadr; 34554359Sroberto 34654359Sroberto pp = peer->procptr; 347290001Sglebius vme = pp->unitptr; /* Here is the structure */ 34854359Sroberto 34954359Sroberto tptr = &vme->vmedata; 35054359Sroberto if ((tptr = get_datumtime(tptr)) == NULL ) { 35154359Sroberto refclock_report(peer, CEVNT_BADREPLY); 35254359Sroberto return; 35354359Sroberto } 35454359Sroberto 35554359Sroberto get_systime(&pp->lastrec); 35654359Sroberto pp->polls++; 35754359Sroberto vme->lasttime = current_time; 35854359Sroberto 35954359Sroberto /* 36054359Sroberto * Get VME time and convert to timestamp format. 36154359Sroberto * The year must come from the system clock. 36254359Sroberto */ 36354359Sroberto 36454359Sroberto time(&tloc); 36554359Sroberto tadr = gmtime(&tloc); 36654359Sroberto tptr->year = (unsigned short)(tadr->tm_year + 1900); 36754359Sroberto 368290001Sglebius snprintf(pp->a_lastcode, 369290001Sglebius sizeof(pp->a_lastcode), 370290001Sglebius "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d", 371290001Sglebius tptr->day, 372290001Sglebius tptr->hr, 373290001Sglebius tptr->mn, 374290001Sglebius tptr->sec, 375290001Sglebius tptr->frac, 376290001Sglebius tptr->status); 37754359Sroberto 37854359Sroberto pp->lencode = (u_short) strlen(pp->a_lastcode); 37954359Sroberto 38054359Sroberto pp->day = tptr->day; 38154359Sroberto pp->hour = tptr->hr; 38254359Sroberto pp->minute = tptr->mn; 38354359Sroberto pp->second = tptr->sec; 384182007Sroberto pp->nsec = tptr->frac; 38554359Sroberto 38654359Sroberto#ifdef DEBUG 38754359Sroberto if (debug) 38854359Sroberto printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n", 38954359Sroberto pp->day, pp->hour, pp->minute, pp->second, 390182007Sroberto pp->nsec, tptr->status); 39154359Sroberto#endif 39254359Sroberto if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ 39354359Sroberto refclock_report(peer, CEVNT_BADREPLY); 39454359Sroberto return; 39554359Sroberto } 39654359Sroberto 39754359Sroberto /* 39854359Sroberto * Now, compute the reference time value. Use the heavy 39954359Sroberto * machinery for the seconds and the millisecond field for the 40054359Sroberto * fraction when present. If an error in conversion to internal 40154359Sroberto * format is found, the program declares bad data and exits. 40254359Sroberto * Note that this code does not yet know how to do the years and 40354359Sroberto * relies on the clock-calendar chip for sanity. 40454359Sroberto */ 40554359Sroberto if (!refclock_process(pp)) { 40654359Sroberto refclock_report(peer, CEVNT_BADTIME); 40754359Sroberto return; 40854359Sroberto } 409132451Sroberto pp->lastref = pp->lastrec; 410132451Sroberto refclock_receive(peer); 41154359Sroberto record_clock_stats(&peer->srcadr, pp->a_lastcode); 41254359Sroberto} 41354359Sroberto 41454359Srobertostruct vmedate * 41554359Srobertoget_datumtime(struct vmedate *time_vme) 41654359Sroberto{ 41754359Sroberto char cbuf[7]; 41854359Sroberto struct btfp_time vts; 419182007Sroberto uint32_t btm[2]; 420182007Sroberto uint8_t dmy; 421290001Sglebius struct stfp_time stfpm; 42254359Sroberto 423290001Sglebius if (time_vme == NULL) 424290001Sglebius time_vme = emalloc(sizeof(*time_vme)); 42554359Sroberto 426182007Sroberto switch (tfp_type) { 427182007Sroberto case 1: /* BSD, PCI, 2 32bit time words */ 428182007Sroberto if (ioctl(fd_vme, READTIME, &btm)) { 429182007Sroberto msyslog(LOG_ERR, "get_bc63x error: %m"); 430182007Sroberto return(NULL); 431182007Sroberto } 432182007Sroberto tvme_fill(time_vme, btm); 433182007Sroberto break; 43454359Sroberto 435182007Sroberto case 2: /* Linux/Windows, PCI, 2 32bit time words */ 436182007Sroberto if (bcReadBinTime(stfp_handle, &btm[1], &btm[0], &dmy) == 0) { 437182007Sroberto msyslog(LOG_ERR, "get_datumtime error: %m"); 438182007Sroberto return(NULL); 439182007Sroberto } 440182007Sroberto tvme_fill(time_vme, btm); 441182007Sroberto break; 442290001Sglebius 443290001Sglebius case 3: /** solaris **/ 444290001Sglebius memset(&stfpm,0,sizeof(stfpm)); 445290001Sglebius 446290001Sglebius /* we need the time in decimal format */ 447290001Sglebius /* Here we rudely assume that we are the only user of the driver. 448290001Sglebius * Other programs will have to set their own time format before reading 449290001Sglebius * the time. 450290001Sglebius */ 451290001Sglebius if(ioctl (fd_vme, SELTIMEFORMAT, TIME_DECIMAL)){ 452290001Sglebius msyslog(LOG_ERR, "Could not set time format"); 453290001Sglebius return (NULL); 454290001Sglebius } 455290001Sglebius /* read the time */ 456290001Sglebius if (ioctl(fd_vme, READTIME, &stfpm)) { 457290001Sglebius msyslog(LOG_ERR, "ioctl error: %m"); 458290001Sglebius return(NULL); 459290001Sglebius } 460290001Sglebius stfp_time2tvme(time_vme, &stfpm); 461290001Sglebius break; 46254359Sroberto 463182007Sroberto default: /* legacy bancomm card */ 46454359Sroberto 465182007Sroberto if (ioctl(fd_vme, READTIME, &vts)) { 466290001Sglebius msyslog(LOG_ERR, 467290001Sglebius "get_datumtime error: %m"); 468182007Sroberto return(NULL); 469182007Sroberto } 470182007Sroberto /* Get day */ 471290001Sglebius snprintf(cbuf, sizeof(cbuf), "%3.3x", 472290001Sglebius ((vts.btfp_time[ 0 ] & 0x000f) << 8) + 473290001Sglebius ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); 474182007Sroberto time_vme->day = (unsigned short)atoi(cbuf); 47554359Sroberto 476182007Sroberto /* Get hour */ 477290001Sglebius snprintf(cbuf, sizeof(cbuf), "%2.2x", 478290001Sglebius vts.btfp_time[ 1 ] & 0x00ff); 479182007Sroberto time_vme->hr = (unsigned short)atoi(cbuf); 48054359Sroberto 481182007Sroberto /* Get minutes */ 482290001Sglebius snprintf(cbuf, sizeof(cbuf), "%2.2x", 483290001Sglebius (vts.btfp_time[ 2 ] & 0xff00) >> 8); 484182007Sroberto time_vme->mn = (unsigned short)atoi(cbuf); 48554359Sroberto 486182007Sroberto /* Get seconds */ 487290001Sglebius snprintf(cbuf, sizeof(cbuf), "%2.2x", 488290001Sglebius vts.btfp_time[ 2 ] & 0x00ff); 489182007Sroberto time_vme->sec = (unsigned short)atoi(cbuf); 49054359Sroberto 491182007Sroberto /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so 492182007Sroberto we can use the TVTOTSF function later on...*/ 49354359Sroberto 494290001Sglebius snprintf(cbuf, sizeof(cbuf), "%4.4x%2.2x", 495290001Sglebius vts.btfp_time[ 3 ], 496290001Sglebius vts.btfp_time[ 4 ] >> 8); 497182007Sroberto time_vme->frac = (u_long) atoi(cbuf); 49854359Sroberto 499182007Sroberto /* Get status bit */ 500290001Sglebius time_vme->status = (vts.btfp_time[0] & 0x0010) >> 4; 50154359Sroberto 502182007Sroberto break; 503182007Sroberto } 50454359Sroberto 505182007Sroberto if (time_vme->status) 50654359Sroberto return ((void *)NULL); 50754359Sroberto else 50854359Sroberto return (time_vme); 50954359Sroberto} 510182007Sroberto/* Assign values to time_vme struct. Mostly for readability */ 511182007Srobertovoid 512182007Srobertotvme_fill(struct vmedate *time_vme, uint32_t btm[2]) 513182007Sroberto{ 514182007Sroberto struct tm maj; 515182007Sroberto uint32_t dmaj, dmin; 51654359Sroberto 517182007Sroberto dmaj = btm[1]; /* syntax sugar */ 518182007Sroberto dmin = btm[0]; 519182007Sroberto 520182007Sroberto gmtime_r(&dmaj, &maj); 521182007Sroberto time_vme->day = maj.tm_yday+1; 522182007Sroberto time_vme->hr = maj.tm_hour; 523182007Sroberto time_vme->mn = maj.tm_min; 524182007Sroberto time_vme->sec = maj.tm_sec; 525182007Sroberto time_vme->frac = (dmin & 0x000fffff) * 1000; 526182007Sroberto time_vme->frac += ((dmin & 0x00f00000) >> 20) * 100; 527182007Sroberto time_vme->status = (dmin & 0x01000000) >> 24; 528182007Sroberto return; 529182007Sroberto} 530182007Sroberto 531290001Sglebius 532290001Sglebius/* Assign values to time_vme struct. Mostly for readability */ 533290001Sglebiusvoid 534290001Sglebiusstfp_time2tvme(struct vmedate *time_vme, struct stfp_time *stfp) 535290001Sglebius{ 536290001Sglebius 537290001Sglebius time_vme->day = stfp->tm.tm_yday+1; 538290001Sglebius time_vme->hr = stfp->tm.tm_hour; 539290001Sglebius time_vme->mn = stfp->tm.tm_min; 540290001Sglebius time_vme->sec = stfp->tm.tm_sec; 541290001Sglebius time_vme->frac = stfp->usec*1000; 542290001Sglebius time_vme->frac += stfp->hnsec * 100; 543290001Sglebius time_vme->status = stfp->status; 544290001Sglebius return; 545290001Sglebius} 54654359Sroberto#else 54754359Srobertoint refclock_bancomm_bs; 54854359Sroberto#endif /* REFCLOCK */ 549