1c0b746e5SOllivier Robert /* refclock_bancomm.c - clock driver for the Datum/Bancomm bc635VME 2c0b746e5SOllivier Robert * Time and Frequency Processor. It requires the BANCOMM bc635VME/ 3c0b746e5SOllivier Robert * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x 4c0b746e5SOllivier Robert * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc 5c0b746e5SOllivier Robert * IIi-cEngine running Solaris 2.6. 6c0b746e5SOllivier Robert * 7c0b746e5SOllivier Robert * Author(s): Ganesh Ramasivan & Gary Cliff, Computing Devices Canada, 8c0b746e5SOllivier Robert * Ottawa, Canada 9c0b746e5SOllivier Robert * 10c0b746e5SOllivier Robert * Date: July 1999 11c0b746e5SOllivier Robert * 12c0b746e5SOllivier Robert * Note(s): The refclock type has been defined as 16. 13c0b746e5SOllivier Robert * 14c0b746e5SOllivier Robert * This program has been modelled after the Bancomm driver 15c0b746e5SOllivier Robert * originally written by R. Schmidt of Time Service, U.S. 16c0b746e5SOllivier Robert * Naval Observatory for a HP-UX machine. Since the original 17c0b746e5SOllivier Robert * authors no longer plan to maintain this code, all 18c0b746e5SOllivier Robert * references to the HP-UX vme2 driver subsystem bave been 19c0b746e5SOllivier Robert * removed. Functions vme_report_event(), vme_receive(), 20c0b746e5SOllivier Robert * vme_control() and vme_buginfo() have been deleted because 21c0b746e5SOllivier Robert * they are no longer being used. 22c0b746e5SOllivier Robert * 23c0b746e5SOllivier Robert * The time on the bc635 TFP must be set to GMT due to the 24c0b746e5SOllivier Robert * fact that NTP makes use of GMT for all its calculations. 25c0b746e5SOllivier Robert * 26c0b746e5SOllivier Robert * Installation of the Datum/Bancomm driver creates the 27c0b746e5SOllivier Robert * device file /dev/btfp0 28c0b746e5SOllivier Robert */ 29c0b746e5SOllivier Robert 30c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 31c0b746e5SOllivier Robert #include <config.h> 32c0b746e5SOllivier Robert #endif 33c0b746e5SOllivier Robert 34c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_BANC) 35c0b746e5SOllivier Robert 36c0b746e5SOllivier Robert #include "ntpd.h" 37c0b746e5SOllivier Robert #include "ntp_io.h" 38c0b746e5SOllivier Robert #include "ntp_refclock.h" 39c0b746e5SOllivier Robert #include "ntp_unixtime.h" 40c0b746e5SOllivier Robert #include "ntp_stdlib.h" 41c0b746e5SOllivier Robert 42224ba2bdSOllivier Robert #include <stdio.h> 43224ba2bdSOllivier Robert #include <syslog.h> 44224ba2bdSOllivier Robert #include <ctype.h> 45224ba2bdSOllivier Robert 46c0b746e5SOllivier Robert /* STUFF BY RES */ 47c0b746e5SOllivier Robert struct btfp_time /* Structure for reading 5 time words */ 48c0b746e5SOllivier Robert /* in one ioctl(2) operation. */ 49c0b746e5SOllivier Robert { 50c0b746e5SOllivier Robert unsigned short btfp_time[5]; /* Time words 0,1,2,3, and 4. (16bit)*/ 51c0b746e5SOllivier Robert }; 52c0b746e5SOllivier Robert 53c0b746e5SOllivier Robert /* SunOS5 ioctl commands definitions.*/ 54c0b746e5SOllivier Robert #define BTFPIOC ( 'b'<< 8 ) 55c0b746e5SOllivier Robert #define IOCIO( l, n ) ( BTFPIOC | n ) 56c0b746e5SOllivier Robert #define IOCIOR( l, n, s ) ( BTFPIOC | n ) 57c0b746e5SOllivier Robert #define IOCIORN( l, n, s ) ( BTFPIOC | n ) 58c0b746e5SOllivier Robert #define IOCIOWN( l, n, s ) ( BTFPIOC | n ) 59c0b746e5SOllivier Robert 60c0b746e5SOllivier Robert /***** Simple ioctl commands *****/ 61c0b746e5SOllivier Robert #define RUNLOCK IOCIOR(b, 19, int ) /* Release Capture Lockout */ 62c0b746e5SOllivier Robert #define RCR0 IOCIOR(b, 22, int ) /* Read control register zero.*/ 63c0b746e5SOllivier Robert #define WCR0 IOCIOWN(b, 23, int) /* Write control register zero*/ 64c0b746e5SOllivier Robert 65c0b746e5SOllivier Robert /***** Compound ioctl commands *****/ 66c0b746e5SOllivier Robert 67c0b746e5SOllivier Robert /* Read all 5 time words in one call. */ 68c0b746e5SOllivier Robert #define READTIME IOCIORN(b, 32, sizeof( struct btfp_time )) 69c0b746e5SOllivier Robert #define VMEFD "/dev/btfp0" 70c0b746e5SOllivier Robert 71c0b746e5SOllivier Robert struct vmedate { /* structure returned by get_vmetime.c */ 72c0b746e5SOllivier Robert unsigned short year; 73c0b746e5SOllivier Robert unsigned short day; 74c0b746e5SOllivier Robert unsigned short hr; 75c0b746e5SOllivier Robert unsigned short mn; 76c0b746e5SOllivier Robert unsigned short sec; 77c0b746e5SOllivier Robert unsigned long frac; 78c0b746e5SOllivier Robert unsigned short status; 79c0b746e5SOllivier Robert }; 80c0b746e5SOllivier Robert 81c0b746e5SOllivier Robert /* END OF STUFF FROM RES */ 82c0b746e5SOllivier Robert 83c0b746e5SOllivier Robert /* 84c0b746e5SOllivier Robert * VME interface parameters. 85c0b746e5SOllivier Robert */ 86c0b746e5SOllivier Robert #define VMEPRECISION (-21) /* precision assumed (1 us) */ 87c0b746e5SOllivier Robert #define USNOREFID "BTFP" /* or whatever */ 88c0b746e5SOllivier Robert #define VMEREFID "BTFP" /* reference id */ 89c0b746e5SOllivier Robert #define VMEDESCRIPTION "Bancomm bc635 TFP" /* who we are */ 90c0b746e5SOllivier Robert #define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */ 91c0b746e5SOllivier Robert /* clock type 16 is used here */ 92c0b746e5SOllivier Robert #define GMT 0 /* hour offset from Greenwich */ 93c0b746e5SOllivier Robert 94c0b746e5SOllivier Robert /* 95c0b746e5SOllivier Robert * Imported from ntp_timer module 96c0b746e5SOllivier Robert */ 97c0b746e5SOllivier Robert extern u_long current_time; /* current time(s) */ 98c0b746e5SOllivier Robert 99c0b746e5SOllivier Robert /* 100c0b746e5SOllivier Robert * Imported from ntpd module 101c0b746e5SOllivier Robert */ 102c0b746e5SOllivier Robert extern int debug; /* global debug flag */ 103c0b746e5SOllivier Robert 104c0b746e5SOllivier Robert /* 105c0b746e5SOllivier Robert * VME unit control structure. 106c0b746e5SOllivier Robert * Changes made to vmeunit structure. Most members are now available in the 107c0b746e5SOllivier Robert * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan 108c0b746e5SOllivier Robert */ 109c0b746e5SOllivier Robert struct vmeunit { 110c0b746e5SOllivier Robert struct vmedate vmedata; /* data returned from vme read */ 111c0b746e5SOllivier Robert u_long lasttime; /* last time clock heard from */ 112c0b746e5SOllivier Robert }; 113c0b746e5SOllivier Robert 114c0b746e5SOllivier Robert /* 115c0b746e5SOllivier Robert * Function prototypes 116c0b746e5SOllivier Robert */ 117c0b746e5SOllivier Robert static void vme_init (void); 118c0b746e5SOllivier Robert static int vme_start (int, struct peer *); 119c0b746e5SOllivier Robert static void vme_shutdown (int, struct peer *); 120c0b746e5SOllivier Robert static void vme_receive (struct recvbuf *); 121c0b746e5SOllivier Robert static void vme_poll (int unit, struct peer *); 122c0b746e5SOllivier Robert struct vmedate *get_datumtime(struct vmedate *); 123c0b746e5SOllivier Robert 124c0b746e5SOllivier Robert /* 125c0b746e5SOllivier Robert * Transfer vector 126c0b746e5SOllivier Robert */ 127c0b746e5SOllivier Robert struct refclock refclock_bancomm = { 128224ba2bdSOllivier Robert vme_start, /* start up driver */ 129224ba2bdSOllivier Robert vme_shutdown, /* shut down driver */ 130224ba2bdSOllivier Robert vme_poll, /* transmit poll message */ 131c0b746e5SOllivier Robert noentry, /* not used (old vme_control) */ 132224ba2bdSOllivier Robert noentry, /* initialize driver */ 133c0b746e5SOllivier Robert noentry, /* not used (old vme_buginfo) */ 134224ba2bdSOllivier Robert NOFLAGS /* not used */ 135c0b746e5SOllivier Robert }; 136c0b746e5SOllivier Robert 137c0b746e5SOllivier Robert int fd_vme; /* file descriptor for ioctls */ 138c0b746e5SOllivier Robert int regvalue; 139c0b746e5SOllivier Robert 140c0b746e5SOllivier Robert 141c0b746e5SOllivier Robert /* 142c0b746e5SOllivier Robert * vme_start - open the VME device and initialize data for processing 143c0b746e5SOllivier Robert */ 144c0b746e5SOllivier Robert static int 145c0b746e5SOllivier Robert vme_start( 146c0b746e5SOllivier Robert int unit, 147c0b746e5SOllivier Robert struct peer *peer 148c0b746e5SOllivier Robert ) 149c0b746e5SOllivier Robert { 150c0b746e5SOllivier Robert register struct vmeunit *vme; 151c0b746e5SOllivier Robert struct refclockproc *pp; 152c0b746e5SOllivier Robert int dummy; 153c0b746e5SOllivier Robert char vmedev[20]; 154c0b746e5SOllivier Robert 155c0b746e5SOllivier Robert /* 156c0b746e5SOllivier Robert * Open VME device 157c0b746e5SOllivier Robert */ 158c0b746e5SOllivier Robert #ifdef DEBUG 159c0b746e5SOllivier Robert 160c0b746e5SOllivier Robert printf("Opening DATUM VME DEVICE \n"); 161c0b746e5SOllivier Robert #endif 162c0b746e5SOllivier Robert if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) { 163c0b746e5SOllivier Robert msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev); 164c0b746e5SOllivier Robert return (0); 165c0b746e5SOllivier Robert } 166c0b746e5SOllivier Robert else { /* Release capture lockout in case it was set from before. */ 167c0b746e5SOllivier Robert if( ioctl( fd_vme, RUNLOCK, &dummy ) ) 168c0b746e5SOllivier Robert msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m"); 169c0b746e5SOllivier Robert 170c0b746e5SOllivier Robert regvalue = 0; /* More esoteric stuff to do... */ 171c0b746e5SOllivier Robert if( ioctl( fd_vme, WCR0, ®value ) ) 172c0b746e5SOllivier Robert msyslog(LOG_ERR, "vme_start: WCR0 failed %m"); 173c0b746e5SOllivier Robert } 174c0b746e5SOllivier Robert 175c0b746e5SOllivier Robert /* 176c0b746e5SOllivier Robert * Allocate unit structure 177c0b746e5SOllivier Robert */ 178c0b746e5SOllivier Robert vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit)); 179c0b746e5SOllivier Robert bzero((char *)vme, sizeof(struct vmeunit)); 180c0b746e5SOllivier Robert 181c0b746e5SOllivier Robert 182c0b746e5SOllivier Robert /* 183c0b746e5SOllivier Robert * Set up the structures 184c0b746e5SOllivier Robert */ 185c0b746e5SOllivier Robert pp = peer->procptr; 186c0b746e5SOllivier Robert pp->unitptr = (caddr_t) vme; 187c0b746e5SOllivier Robert pp->timestarted = current_time; 188c0b746e5SOllivier Robert 189c0b746e5SOllivier Robert pp->io.clock_recv = vme_receive; 190c0b746e5SOllivier Robert pp->io.srcclock = (caddr_t)peer; 191c0b746e5SOllivier Robert pp->io.datalen = 0; 192c0b746e5SOllivier Robert pp->io.fd = fd_vme; 193c0b746e5SOllivier Robert 194c0b746e5SOllivier Robert /* 195c0b746e5SOllivier Robert * All done. Initialize a few random peer variables, then 196c0b746e5SOllivier Robert * return success. Note that root delay and root dispersion are 197c0b746e5SOllivier Robert * always zero for this clock. 198c0b746e5SOllivier Robert */ 199c0b746e5SOllivier Robert peer->precision = VMEPRECISION; 200224ba2bdSOllivier Robert memcpy(&pp->refid, USNOREFID,4); 201c0b746e5SOllivier Robert return (1); 202c0b746e5SOllivier Robert } 203c0b746e5SOllivier Robert 204c0b746e5SOllivier Robert 205c0b746e5SOllivier Robert /* 206c0b746e5SOllivier Robert * vme_shutdown - shut down a VME clock 207c0b746e5SOllivier Robert */ 208c0b746e5SOllivier Robert static void 209c0b746e5SOllivier Robert vme_shutdown( 210c0b746e5SOllivier Robert int unit, 211c0b746e5SOllivier Robert struct peer *peer 212c0b746e5SOllivier Robert ) 213c0b746e5SOllivier Robert { 214c0b746e5SOllivier Robert register struct vmeunit *vme; 215c0b746e5SOllivier Robert struct refclockproc *pp; 216c0b746e5SOllivier Robert 217c0b746e5SOllivier Robert /* 218c0b746e5SOllivier Robert * Tell the I/O module to turn us off. We're history. 219c0b746e5SOllivier Robert */ 220224ba2bdSOllivier Robert pp = peer->procptr; 221c0b746e5SOllivier Robert vme = (struct vmeunit *)pp->unitptr; 222c0b746e5SOllivier Robert io_closeclock(&pp->io); 223c0b746e5SOllivier Robert pp->unitptr = NULL; 224c0b746e5SOllivier Robert free(vme); 225c0b746e5SOllivier Robert } 226c0b746e5SOllivier Robert 227c0b746e5SOllivier Robert 228c0b746e5SOllivier Robert /* 229c0b746e5SOllivier Robert * vme_receive - receive data from the VME device. 230c0b746e5SOllivier Robert * 231c0b746e5SOllivier Robert * Note: This interface would be interrupt-driven. We don't use that 232c0b746e5SOllivier Robert * now, but include a dummy routine for possible future adventures. 233c0b746e5SOllivier Robert */ 234c0b746e5SOllivier Robert static void 235c0b746e5SOllivier Robert vme_receive( 236c0b746e5SOllivier Robert struct recvbuf *rbufp 237c0b746e5SOllivier Robert ) 238c0b746e5SOllivier Robert { 239c0b746e5SOllivier Robert } 240c0b746e5SOllivier Robert 241c0b746e5SOllivier Robert 242c0b746e5SOllivier Robert /* 243c0b746e5SOllivier Robert * vme_poll - called by the transmit procedure 244c0b746e5SOllivier Robert */ 245c0b746e5SOllivier Robert static void 246c0b746e5SOllivier Robert vme_poll( 247c0b746e5SOllivier Robert int unit, 248c0b746e5SOllivier Robert struct peer *peer 249c0b746e5SOllivier Robert ) 250c0b746e5SOllivier Robert { 251c0b746e5SOllivier Robert struct vmedate *tptr; 252c0b746e5SOllivier Robert struct vmeunit *vme; 253c0b746e5SOllivier Robert struct refclockproc *pp; 254c0b746e5SOllivier Robert time_t tloc; 255c0b746e5SOllivier Robert struct tm *tadr; 256c0b746e5SOllivier Robert 257c0b746e5SOllivier Robert pp = peer->procptr; 258c0b746e5SOllivier Robert vme = (struct vmeunit *)pp->unitptr; /* Here is the structure */ 259c0b746e5SOllivier Robert 260c0b746e5SOllivier Robert tptr = &vme->vmedata; 261c0b746e5SOllivier Robert if ((tptr = get_datumtime(tptr)) == NULL ) { 262c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 263c0b746e5SOllivier Robert return; 264c0b746e5SOllivier Robert } 265c0b746e5SOllivier Robert 266c0b746e5SOllivier Robert get_systime(&pp->lastrec); 267c0b746e5SOllivier Robert pp->polls++; 268c0b746e5SOllivier Robert vme->lasttime = current_time; 269c0b746e5SOllivier Robert 270c0b746e5SOllivier Robert /* 271c0b746e5SOllivier Robert * Get VME time and convert to timestamp format. 272c0b746e5SOllivier Robert * The year must come from the system clock. 273c0b746e5SOllivier Robert */ 274c0b746e5SOllivier Robert 275c0b746e5SOllivier Robert time(&tloc); 276c0b746e5SOllivier Robert tadr = gmtime(&tloc); 277c0b746e5SOllivier Robert tptr->year = (unsigned short)(tadr->tm_year + 1900); 278c0b746e5SOllivier Robert 279c0b746e5SOllivier Robert 280c0b746e5SOllivier Robert sprintf(pp->a_lastcode, 281c0b746e5SOllivier Robert "%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d", 282c0b746e5SOllivier Robert tptr->day, 283c0b746e5SOllivier Robert tptr->hr, 284c0b746e5SOllivier Robert tptr->mn, 285c0b746e5SOllivier Robert tptr->sec, 286c0b746e5SOllivier Robert tptr->frac, 287c0b746e5SOllivier Robert tptr->status); 288c0b746e5SOllivier Robert 289c0b746e5SOllivier Robert pp->lencode = (u_short) strlen(pp->a_lastcode); 290c0b746e5SOllivier Robert 291c0b746e5SOllivier Robert pp->day = tptr->day; 292c0b746e5SOllivier Robert pp->hour = tptr->hr; 293c0b746e5SOllivier Robert pp->minute = tptr->mn; 294c0b746e5SOllivier Robert pp->second = tptr->sec; 295c0b746e5SOllivier Robert pp->usec = tptr->frac; 296c0b746e5SOllivier Robert 297c0b746e5SOllivier Robert #ifdef DEBUG 298c0b746e5SOllivier Robert if (debug) 299c0b746e5SOllivier Robert printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n", 300c0b746e5SOllivier Robert pp->day, pp->hour, pp->minute, pp->second, 301c0b746e5SOllivier Robert pp->usec, tptr->status); 302c0b746e5SOllivier Robert #endif 303c0b746e5SOllivier Robert if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */ 304c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADREPLY); 305c0b746e5SOllivier Robert return; 306c0b746e5SOllivier Robert } 307c0b746e5SOllivier Robert 308c0b746e5SOllivier Robert /* 309c0b746e5SOllivier Robert * Now, compute the reference time value. Use the heavy 310c0b746e5SOllivier Robert * machinery for the seconds and the millisecond field for the 311c0b746e5SOllivier Robert * fraction when present. If an error in conversion to internal 312c0b746e5SOllivier Robert * format is found, the program declares bad data and exits. 313c0b746e5SOllivier Robert * Note that this code does not yet know how to do the years and 314c0b746e5SOllivier Robert * relies on the clock-calendar chip for sanity. 315c0b746e5SOllivier Robert */ 316c0b746e5SOllivier Robert if (!refclock_process(pp)) { 317c0b746e5SOllivier Robert refclock_report(peer, CEVNT_BADTIME); 318c0b746e5SOllivier Robert return; 319c0b746e5SOllivier Robert } 320c0b746e5SOllivier Robert record_clock_stats(&peer->srcadr, pp->a_lastcode); 321c0b746e5SOllivier Robert refclock_receive(peer); 322c0b746e5SOllivier Robert } 323c0b746e5SOllivier Robert 324c0b746e5SOllivier Robert struct vmedate * 325c0b746e5SOllivier Robert get_datumtime(struct vmedate *time_vme) 326c0b746e5SOllivier Robert { 327c0b746e5SOllivier Robert unsigned short status; 328c0b746e5SOllivier Robert char cbuf[7]; 329c0b746e5SOllivier Robert struct btfp_time vts; 330c0b746e5SOllivier Robert 331c0b746e5SOllivier Robert if ( time_vme == (struct vmedate *)NULL) { 332c0b746e5SOllivier Robert time_vme = (struct vmedate *)malloc(sizeof(struct vmedate )); 333c0b746e5SOllivier Robert } 334c0b746e5SOllivier Robert 335c0b746e5SOllivier Robert if( ioctl(fd_vme, READTIME, &vts)) 336c0b746e5SOllivier Robert msyslog(LOG_ERR, "get_datumtime error: %m"); 337c0b746e5SOllivier Robert 338c0b746e5SOllivier Robert /* if you want to actually check the validity of these registers, do a 339c0b746e5SOllivier Robert define of CHECK above this. I didn't find it necessary. - RES 340c0b746e5SOllivier Robert */ 341c0b746e5SOllivier Robert 342c0b746e5SOllivier Robert #ifdef CHECK 343c0b746e5SOllivier Robert 344c0b746e5SOllivier Robert /* Get day */ 345c0b746e5SOllivier Robert sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + 346c0b746e5SOllivier Robert ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); 347c0b746e5SOllivier Robert 348c0b746e5SOllivier Robert if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) ) 349c0b746e5SOllivier Robert time_vme->day = (unsigned short)atoi(cbuf); 350c0b746e5SOllivier Robert else 351c0b746e5SOllivier Robert time_vme->day = (unsigned short) 0; 352c0b746e5SOllivier Robert 353c0b746e5SOllivier Robert /* Get hour */ 354c0b746e5SOllivier Robert sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff); 355c0b746e5SOllivier Robert 356c0b746e5SOllivier Robert if (isdigit(cbuf[0]) && isdigit(cbuf[1])) 357c0b746e5SOllivier Robert time_vme->hr = (unsigned short)atoi(cbuf); 358c0b746e5SOllivier Robert else 359c0b746e5SOllivier Robert time_vme->hr = (unsigned short) 0; 360c0b746e5SOllivier Robert 361c0b746e5SOllivier Robert /* Get minutes */ 362c0b746e5SOllivier Robert sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8); 363c0b746e5SOllivier Robert if (isdigit(cbuf[0]) && isdigit(cbuf[1])) 364c0b746e5SOllivier Robert time_vme->mn = (unsigned short)atoi(cbuf); 365c0b746e5SOllivier Robert else 366c0b746e5SOllivier Robert time_vme->mn = (unsigned short) 0; 367c0b746e5SOllivier Robert 368c0b746e5SOllivier Robert /* Get seconds */ 369c0b746e5SOllivier Robert sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff); 370c0b746e5SOllivier Robert 371c0b746e5SOllivier Robert if (isdigit(cbuf[0]) && isdigit(cbuf[1])) 372c0b746e5SOllivier Robert time_vme->sec = (unsigned short)atoi(cbuf); 373c0b746e5SOllivier Robert else 374c0b746e5SOllivier Robert time_vme->sec = (unsigned short) 0; 375c0b746e5SOllivier Robert 376c0b746e5SOllivier Robert /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can 377c0b746e5SOllivier Robert use the TVTOTSF function later on...*/ 378c0b746e5SOllivier Robert 379c0b746e5SOllivier Robert sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ], 380c0b746e5SOllivier Robert vts.btfp_time[ 4 ]>>8); 381c0b746e5SOllivier Robert 382c0b746e5SOllivier Robert if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) 383c0b746e5SOllivier Robert && isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5])) 384c0b746e5SOllivier Robert time_vme->frac = (u_long) atoi(cbuf); 385c0b746e5SOllivier Robert else 386c0b746e5SOllivier Robert time_vme->frac = (u_long) 0; 387c0b746e5SOllivier Robert #else 388c0b746e5SOllivier Robert 389c0b746e5SOllivier Robert /* DONT CHECK just trust the card */ 390c0b746e5SOllivier Robert 391c0b746e5SOllivier Robert /* Get day */ 392c0b746e5SOllivier Robert sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) + 393c0b746e5SOllivier Robert ((vts.btfp_time[ 1 ] & 0xff00) >> 8)); 394c0b746e5SOllivier Robert time_vme->day = (unsigned short)atoi(cbuf); 395c0b746e5SOllivier Robert 396c0b746e5SOllivier Robert /* Get hour */ 397c0b746e5SOllivier Robert sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff); 398c0b746e5SOllivier Robert 399c0b746e5SOllivier Robert time_vme->hr = (unsigned short)atoi(cbuf); 400c0b746e5SOllivier Robert 401c0b746e5SOllivier Robert /* Get minutes */ 402c0b746e5SOllivier Robert sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8); 403c0b746e5SOllivier Robert time_vme->mn = (unsigned short)atoi(cbuf); 404c0b746e5SOllivier Robert 405c0b746e5SOllivier Robert /* Get seconds */ 406c0b746e5SOllivier Robert sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff); 407c0b746e5SOllivier Robert time_vme->sec = (unsigned short)atoi(cbuf); 408c0b746e5SOllivier Robert 409c0b746e5SOllivier Robert /* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can 410c0b746e5SOllivier Robert use the TVTOTSF function later on...*/ 411c0b746e5SOllivier Robert 412c0b746e5SOllivier Robert sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ], 413c0b746e5SOllivier Robert vts.btfp_time[ 4 ]>>8); 414c0b746e5SOllivier Robert 415c0b746e5SOllivier Robert time_vme->frac = (u_long) atoi(cbuf); 416c0b746e5SOllivier Robert 417c0b746e5SOllivier Robert #endif /* CHECK */ 418c0b746e5SOllivier Robert 419c0b746e5SOllivier Robert /* Get status bit */ 420c0b746e5SOllivier Robert status = (vts.btfp_time[0] & 0x0010) >>4; 421c0b746e5SOllivier Robert time_vme->status = status; /* Status=0 if locked to ref. */ 422c0b746e5SOllivier Robert /* Status=1 if flywheeling */ 423c0b746e5SOllivier Robert if (status) { /* lost lock ? */ 424c0b746e5SOllivier Robert return ((void *)NULL); 425c0b746e5SOllivier Robert } 426c0b746e5SOllivier Robert else 427c0b746e5SOllivier Robert return (time_vme); 428c0b746e5SOllivier Robert } 429c0b746e5SOllivier Robert 430c0b746e5SOllivier Robert #else 431c0b746e5SOllivier Robert int refclock_bancomm_bs; 432c0b746e5SOllivier Robert #endif /* REFCLOCK */ 433