xref: /freebsd/contrib/ntp/ntpd/refclock_bancomm.c (revision 224ba2bd37e182b64f7d78defef8a6cacaad3415)
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, &regvalue ) )
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