xref: /freebsd/contrib/ntp/ntpd/refclock_bancomm.c (revision c0b746e5e8d9479f05b3749cbf1f73b8928719bd)
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 #include <stdio.h>
36c0b746e5SOllivier Robert #include <syslog.h>
37c0b746e5SOllivier Robert #include <ctype.h>
38c0b746e5SOllivier Robert #include <string.h>
39c0b746e5SOllivier Robert #include <strings.h>
40c0b746e5SOllivier Robert #include <sys/time.h>
41c0b746e5SOllivier Robert 
42c0b746e5SOllivier Robert #include "ntpd.h"
43c0b746e5SOllivier Robert #include "ntp_io.h"
44c0b746e5SOllivier Robert #include "ntp_refclock.h"
45c0b746e5SOllivier Robert #include "ntp_unixtime.h"
46c0b746e5SOllivier Robert #include "ntp_stdlib.h"
47c0b746e5SOllivier Robert 
48c0b746e5SOllivier Robert /*  STUFF BY RES */
49c0b746e5SOllivier Robert struct btfp_time                /* Structure for reading 5 time words   */
50c0b746e5SOllivier Robert                                 /* in one ioctl(2) operation.           */
51c0b746e5SOllivier Robert {
52c0b746e5SOllivier Robert 	unsigned short btfp_time[5];  /* Time words 0,1,2,3, and 4. (16bit)*/
53c0b746e5SOllivier Robert };
54c0b746e5SOllivier Robert 
55c0b746e5SOllivier Robert /* SunOS5 ioctl commands definitions.*/
56c0b746e5SOllivier Robert #define BTFPIOC            ( 'b'<< 8 )
57c0b746e5SOllivier Robert #define IOCIO( l, n )      ( BTFPIOC | n )
58c0b746e5SOllivier Robert #define IOCIOR( l, n, s )  ( BTFPIOC | n )
59c0b746e5SOllivier Robert #define IOCIORN( l, n, s ) ( BTFPIOC | n )
60c0b746e5SOllivier Robert #define IOCIOWN( l, n, s ) ( BTFPIOC | n )
61c0b746e5SOllivier Robert 
62c0b746e5SOllivier Robert /***** Simple ioctl commands *****/
63c0b746e5SOllivier Robert #define RUNLOCK     	IOCIOR(b, 19, int )  /* Release Capture Lockout */
64c0b746e5SOllivier Robert #define RCR0      	IOCIOR(b, 22, int )  /* Read control register zero.*/
65c0b746e5SOllivier Robert #define	WCR0		IOCIOWN(b, 23, int)	     /* Write control register zero*/
66c0b746e5SOllivier Robert 
67c0b746e5SOllivier Robert /***** Compound ioctl commands *****/
68c0b746e5SOllivier Robert 
69c0b746e5SOllivier Robert /* Read all 5 time words in one call.   */
70c0b746e5SOllivier Robert #define READTIME	IOCIORN(b, 32, sizeof( struct btfp_time ))
71c0b746e5SOllivier Robert #define VMEFD "/dev/btfp0"
72c0b746e5SOllivier Robert 
73c0b746e5SOllivier Robert struct vmedate {               /* structure returned by get_vmetime.c */
74c0b746e5SOllivier Robert 	unsigned short year;
75c0b746e5SOllivier Robert 	unsigned short day;
76c0b746e5SOllivier Robert 	unsigned short hr;
77c0b746e5SOllivier Robert 	unsigned short mn;
78c0b746e5SOllivier Robert 	unsigned short sec;
79c0b746e5SOllivier Robert 	unsigned long frac;
80c0b746e5SOllivier Robert 	unsigned short status;
81c0b746e5SOllivier Robert };
82c0b746e5SOllivier Robert 
83c0b746e5SOllivier Robert /* END OF STUFF FROM RES */
84c0b746e5SOllivier Robert 
85c0b746e5SOllivier Robert /*
86c0b746e5SOllivier Robert  * Definitions
87c0b746e5SOllivier Robert  */
88c0b746e5SOllivier Robert #define MAXUNITS 2              /* max number of VME units */
89c0b746e5SOllivier Robert 
90c0b746e5SOllivier Robert /*
91c0b746e5SOllivier Robert  * VME interface parameters.
92c0b746e5SOllivier Robert  */
93c0b746e5SOllivier Robert #define VMEPRECISION    (-21)   /* precision assumed (1 us) */
94c0b746e5SOllivier Robert #define USNOREFID       "BTFP"  /* or whatever */
95c0b746e5SOllivier Robert #define VMEREFID        "BTFP"  /* reference id */
96c0b746e5SOllivier Robert #define VMEDESCRIPTION  "Bancomm bc635 TFP" /* who we are */
97c0b746e5SOllivier Robert #define VMEHSREFID      0x7f7f1000 /* 127.127.16.00 refid hi strata */
98c0b746e5SOllivier Robert /* clock type 16 is used here  */
99c0b746e5SOllivier Robert #define GMT           	0       /* hour offset from Greenwich */
100c0b746e5SOllivier Robert 
101c0b746e5SOllivier Robert /*
102c0b746e5SOllivier Robert  * Imported from ntp_timer module
103c0b746e5SOllivier Robert  */
104c0b746e5SOllivier Robert extern u_long current_time;     /* current time(s) */
105c0b746e5SOllivier Robert 
106c0b746e5SOllivier Robert /*
107c0b746e5SOllivier Robert  * Imported from ntpd module
108c0b746e5SOllivier Robert  */
109c0b746e5SOllivier Robert extern int debug;               /* global debug flag */
110c0b746e5SOllivier Robert 
111c0b746e5SOllivier Robert /*
112c0b746e5SOllivier Robert  * VME unit control structure.
113c0b746e5SOllivier Robert  * Changes made to vmeunit structure. Most members are now available in the
114c0b746e5SOllivier Robert  * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan
115c0b746e5SOllivier Robert  */
116c0b746e5SOllivier Robert struct vmeunit {
117c0b746e5SOllivier Robert 	struct vmedate vmedata; /* data returned from vme read */
118c0b746e5SOllivier Robert 	u_long lasttime;        /* last time clock heard from */
119c0b746e5SOllivier Robert };
120c0b746e5SOllivier Robert 
121c0b746e5SOllivier Robert /*
122c0b746e5SOllivier Robert  * Keep the fudge factors separately so they can be set even
123c0b746e5SOllivier Robert  * when no clock is configured.
124c0b746e5SOllivier Robert  */
125c0b746e5SOllivier Robert static double fudgefactor[MAXUNITS];
126c0b746e5SOllivier Robert static u_char stratumtouse[MAXUNITS];
127c0b746e5SOllivier Robert static u_char sloppyclockflag[MAXUNITS];
128c0b746e5SOllivier Robert 
129c0b746e5SOllivier Robert /*
130c0b746e5SOllivier Robert  * Function prototypes
131c0b746e5SOllivier Robert  */
132c0b746e5SOllivier Robert static  void    vme_init        (void);
133c0b746e5SOllivier Robert static  int     vme_start       (int, struct peer *);
134c0b746e5SOllivier Robert static  void    vme_shutdown    (int, struct peer *);
135c0b746e5SOllivier Robert static  void    vme_receive     (struct recvbuf *);
136c0b746e5SOllivier Robert static  void    vme_poll        (int unit, struct peer *);
137c0b746e5SOllivier Robert struct vmedate *get_datumtime(struct vmedate *);
138c0b746e5SOllivier Robert 
139c0b746e5SOllivier Robert /*
140c0b746e5SOllivier Robert  * Transfer vector
141c0b746e5SOllivier Robert  */
142c0b746e5SOllivier Robert struct  refclock refclock_bancomm = {
143c0b746e5SOllivier Robert 	vme_start,
144c0b746e5SOllivier Robert 	vme_shutdown,
145c0b746e5SOllivier Robert 	vme_poll,
146c0b746e5SOllivier Robert 	noentry,       /* not used (old vme_control) */
147c0b746e5SOllivier Robert 	vme_init,
148c0b746e5SOllivier Robert 	noentry,       /* not used (old vme_buginfo) */
149c0b746e5SOllivier Robert 	NOFLAGS
150c0b746e5SOllivier Robert };
151c0b746e5SOllivier Robert 
152c0b746e5SOllivier Robert int fd_vme;  /* file descriptor for ioctls */
153c0b746e5SOllivier Robert int regvalue;
154c0b746e5SOllivier Robert 
155c0b746e5SOllivier Robert /*
156c0b746e5SOllivier Robert  * vme_init - initialize internal vme driver data
157c0b746e5SOllivier Robert  */
158c0b746e5SOllivier Robert static void
159c0b746e5SOllivier Robert vme_init(void)
160c0b746e5SOllivier Robert {
161c0b746e5SOllivier Robert 	register int i;
162c0b746e5SOllivier Robert 
163c0b746e5SOllivier Robert 	/*
164c0b746e5SOllivier Robert 	 * Initialize fudge factors to default.
165c0b746e5SOllivier Robert 	 */
166c0b746e5SOllivier Robert 	for (i = 0; i < MAXUNITS; i++) {
167c0b746e5SOllivier Robert 		fudgefactor[i]  = 0.0;
168c0b746e5SOllivier Robert 		stratumtouse[i] = 0;
169c0b746e5SOllivier Robert 		sloppyclockflag[i] = 0;
170c0b746e5SOllivier Robert 	}
171c0b746e5SOllivier Robert }
172c0b746e5SOllivier Robert 
173c0b746e5SOllivier Robert /*
174c0b746e5SOllivier Robert  * vme_start - open the VME device and initialize data for processing
175c0b746e5SOllivier Robert  */
176c0b746e5SOllivier Robert static int
177c0b746e5SOllivier Robert vme_start(
178c0b746e5SOllivier Robert 	int unit,
179c0b746e5SOllivier Robert 	struct peer *peer
180c0b746e5SOllivier Robert 	)
181c0b746e5SOllivier Robert {
182c0b746e5SOllivier Robert 	register struct vmeunit *vme;
183c0b746e5SOllivier Robert 	struct refclockproc *pp;
184c0b746e5SOllivier Robert 	int dummy;
185c0b746e5SOllivier Robert 	char vmedev[20];
186c0b746e5SOllivier Robert 
187c0b746e5SOllivier Robert 	/*
188c0b746e5SOllivier Robert 	 * Check configuration info.
189c0b746e5SOllivier Robert 	 */
190c0b746e5SOllivier Robert 	if (unit >= MAXUNITS) {
191c0b746e5SOllivier Robert 		msyslog(LOG_ERR, "vme_start: unit %d invalid", unit);
192c0b746e5SOllivier Robert 		return (0);
193c0b746e5SOllivier Robert 	}
194c0b746e5SOllivier Robert 
195c0b746e5SOllivier Robert 	/*
196c0b746e5SOllivier Robert 	 * Open VME device
197c0b746e5SOllivier Robert 	 */
198c0b746e5SOllivier Robert #ifdef DEBUG
199c0b746e5SOllivier Robert 
200c0b746e5SOllivier Robert 	printf("Opening DATUM VME DEVICE \n");
201c0b746e5SOllivier Robert #endif
202c0b746e5SOllivier Robert 	if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) {
203c0b746e5SOllivier Robert 		msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
204c0b746e5SOllivier Robert 		return (0);
205c0b746e5SOllivier Robert 	}
206c0b746e5SOllivier Robert 	else  { /* Release capture lockout in case it was set from before. */
207c0b746e5SOllivier Robert 		if( ioctl( fd_vme, RUNLOCK, &dummy ) )
208c0b746e5SOllivier Robert 		    msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m");
209c0b746e5SOllivier Robert 
210c0b746e5SOllivier Robert 		regvalue = 0; /* More esoteric stuff to do... */
211c0b746e5SOllivier Robert 		if( ioctl( fd_vme, WCR0, &regvalue ) )
212c0b746e5SOllivier Robert 		    msyslog(LOG_ERR, "vme_start: WCR0 failed %m");
213c0b746e5SOllivier Robert 	}
214c0b746e5SOllivier Robert 
215c0b746e5SOllivier Robert 	/*
216c0b746e5SOllivier Robert 	 * Allocate unit structure
217c0b746e5SOllivier Robert 	 */
218c0b746e5SOllivier Robert 	vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit));
219c0b746e5SOllivier Robert 	bzero((char *)vme, sizeof(struct vmeunit));
220c0b746e5SOllivier Robert 
221c0b746e5SOllivier Robert 
222c0b746e5SOllivier Robert 	/*
223c0b746e5SOllivier Robert 	 * Set up the structures
224c0b746e5SOllivier Robert 	 */
225c0b746e5SOllivier Robert 	pp = peer->procptr;
226c0b746e5SOllivier Robert 	pp->unitptr = (caddr_t) vme;
227c0b746e5SOllivier Robert 	pp->timestarted = current_time;
228c0b746e5SOllivier Robert 
229c0b746e5SOllivier Robert 	pp->io.clock_recv = vme_receive;
230c0b746e5SOllivier Robert 	pp->io.srcclock = (caddr_t)peer;
231c0b746e5SOllivier Robert 	pp->io.datalen = 0;
232c0b746e5SOllivier Robert 	pp->io.fd = fd_vme;
233c0b746e5SOllivier Robert 
234c0b746e5SOllivier Robert 	/*
235c0b746e5SOllivier Robert 	 * All done.  Initialize a few random peer variables, then
236c0b746e5SOllivier Robert  	 * return success. Note that root delay and root dispersion are
237c0b746e5SOllivier Robert 	 * always zero for this clock.
238c0b746e5SOllivier Robert 	 */
239c0b746e5SOllivier Robert 	pp->leap = LEAP_NOWARNING;
240c0b746e5SOllivier Robert 	peer->precision = VMEPRECISION;
241c0b746e5SOllivier Robert 	peer->stratum = stratumtouse[unit];
242c0b746e5SOllivier Robert 	memcpy( (char *)&peer->refid, USNOREFID,4);
243c0b746e5SOllivier Robert 
244c0b746e5SOllivier Robert 	peer->refid = htonl(VMEHSREFID);
245c0b746e5SOllivier Robert 
246c0b746e5SOllivier Robert 	return (1);
247c0b746e5SOllivier Robert }
248c0b746e5SOllivier Robert 
249c0b746e5SOllivier Robert 
250c0b746e5SOllivier Robert /*
251c0b746e5SOllivier Robert  * vme_shutdown - shut down a VME clock
252c0b746e5SOllivier Robert  */
253c0b746e5SOllivier Robert static void
254c0b746e5SOllivier Robert vme_shutdown(
255c0b746e5SOllivier Robert 	int unit,
256c0b746e5SOllivier Robert 	struct peer *peer
257c0b746e5SOllivier Robert 	)
258c0b746e5SOllivier Robert {
259c0b746e5SOllivier Robert 	register struct vmeunit *vme;
260c0b746e5SOllivier Robert 	struct refclockproc *pp;
261c0b746e5SOllivier Robert 
262c0b746e5SOllivier Robert 	pp = peer->procptr;
263c0b746e5SOllivier Robert 
264c0b746e5SOllivier Robert 	if (unit >= MAXUNITS) {
265c0b746e5SOllivier Robert 		msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit);
266c0b746e5SOllivier Robert 		return;
267c0b746e5SOllivier Robert 	}
268c0b746e5SOllivier Robert 
269c0b746e5SOllivier Robert 	/*
270c0b746e5SOllivier Robert 	 * Tell the I/O module to turn us off.  We're history.
271c0b746e5SOllivier Robert 	 */
272c0b746e5SOllivier Robert 	vme = (struct vmeunit *)pp->unitptr;
273c0b746e5SOllivier Robert 	io_closeclock(&pp->io);
274c0b746e5SOllivier Robert 	pp->unitptr = NULL;
275c0b746e5SOllivier Robert 	free(vme);
276c0b746e5SOllivier Robert }
277c0b746e5SOllivier Robert 
278c0b746e5SOllivier Robert 
279c0b746e5SOllivier Robert /*
280c0b746e5SOllivier Robert  * vme_receive - receive data from the VME device.
281c0b746e5SOllivier Robert  *
282c0b746e5SOllivier Robert  * Note: This interface would be interrupt-driven. We don't use that
283c0b746e5SOllivier Robert  * now, but include a dummy routine for possible future adventures.
284c0b746e5SOllivier Robert  */
285c0b746e5SOllivier Robert static void
286c0b746e5SOllivier Robert vme_receive(
287c0b746e5SOllivier Robert 	struct recvbuf *rbufp
288c0b746e5SOllivier Robert 	)
289c0b746e5SOllivier Robert {
290c0b746e5SOllivier Robert }
291c0b746e5SOllivier Robert 
292c0b746e5SOllivier Robert 
293c0b746e5SOllivier Robert /*
294c0b746e5SOllivier Robert  * vme_poll - called by the transmit procedure
295c0b746e5SOllivier Robert  */
296c0b746e5SOllivier Robert static void
297c0b746e5SOllivier Robert vme_poll(
298c0b746e5SOllivier Robert 	int unit,
299c0b746e5SOllivier Robert 	struct peer *peer
300c0b746e5SOllivier Robert 	)
301c0b746e5SOllivier Robert {
302c0b746e5SOllivier Robert 	struct vmedate *tptr;
303c0b746e5SOllivier Robert 	struct vmeunit *vme;
304c0b746e5SOllivier Robert 	struct refclockproc *pp;
305c0b746e5SOllivier Robert 	time_t tloc;
306c0b746e5SOllivier Robert 	struct tm *tadr;
307c0b746e5SOllivier Robert 
308c0b746e5SOllivier Robert 	pp = peer->procptr;
309c0b746e5SOllivier Robert 	vme = (struct vmeunit *)pp->unitptr;        /* Here is the structure */
310c0b746e5SOllivier Robert 
311c0b746e5SOllivier Robert 	tptr = &vme->vmedata;
312c0b746e5SOllivier Robert 	if ((tptr = get_datumtime(tptr)) == NULL ) {
313c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_BADREPLY);
314c0b746e5SOllivier Robert 		return;
315c0b746e5SOllivier Robert 	}
316c0b746e5SOllivier Robert 
317c0b746e5SOllivier Robert 	get_systime(&pp->lastrec);
318c0b746e5SOllivier Robert 	pp->polls++;
319c0b746e5SOllivier Robert 	vme->lasttime = current_time;
320c0b746e5SOllivier Robert 
321c0b746e5SOllivier Robert 	/*
322c0b746e5SOllivier Robert 	 * Get VME time and convert to timestamp format.
323c0b746e5SOllivier Robert 	 * The year must come from the system clock.
324c0b746e5SOllivier Robert 	 */
325c0b746e5SOllivier Robert 
326c0b746e5SOllivier Robert 	  time(&tloc);
327c0b746e5SOllivier Robert 	  tadr = gmtime(&tloc);
328c0b746e5SOllivier Robert 	  tptr->year = (unsigned short)(tadr->tm_year + 1900);
329c0b746e5SOllivier Robert 
330c0b746e5SOllivier Robert 
331c0b746e5SOllivier Robert 	sprintf(pp->a_lastcode,
332c0b746e5SOllivier Robert 		"%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d",
333c0b746e5SOllivier Robert 		tptr->day,
334c0b746e5SOllivier Robert 		tptr->hr,
335c0b746e5SOllivier Robert 		tptr->mn,
336c0b746e5SOllivier Robert 		tptr->sec,
337c0b746e5SOllivier Robert 		tptr->frac,
338c0b746e5SOllivier Robert 		tptr->status);
339c0b746e5SOllivier Robert 
340c0b746e5SOllivier Robert 	pp->lencode = (u_short) strlen(pp->a_lastcode);
341c0b746e5SOllivier Robert 
342c0b746e5SOllivier Robert 	pp->day =  tptr->day;
343c0b746e5SOllivier Robert 	pp->hour =   tptr->hr;
344c0b746e5SOllivier Robert 	pp->minute =  tptr->mn;
345c0b746e5SOllivier Robert 	pp->second =  tptr->sec;
346c0b746e5SOllivier Robert 	pp->usec =   tptr->frac;
347c0b746e5SOllivier Robert 
348c0b746e5SOllivier Robert #ifdef DEBUG
349c0b746e5SOllivier Robert 	if (debug)
350c0b746e5SOllivier Robert 	    printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n",
351c0b746e5SOllivier Robert 		   pp->day, pp->hour, pp->minute, pp->second,
352c0b746e5SOllivier Robert 		   pp->usec, tptr->status);
353c0b746e5SOllivier Robert #endif
354c0b746e5SOllivier Robert 	if (tptr->status ) {       /*  Status 0 is locked to ref., 1 is not */
355c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_BADREPLY);
356c0b746e5SOllivier Robert 		return;
357c0b746e5SOllivier Robert 	}
358c0b746e5SOllivier Robert 
359c0b746e5SOllivier Robert 	/*
360c0b746e5SOllivier Robert 	 * Now, compute the reference time value. Use the heavy
361c0b746e5SOllivier Robert 	 * machinery for the seconds and the millisecond field for the
362c0b746e5SOllivier Robert 	 * fraction when present. If an error in conversion to internal
363c0b746e5SOllivier Robert 	 * format is found, the program declares bad data and exits.
364c0b746e5SOllivier Robert 	 * Note that this code does not yet know how to do the years and
365c0b746e5SOllivier Robert 	 * relies on the clock-calendar chip for sanity.
366c0b746e5SOllivier Robert 	 */
367c0b746e5SOllivier Robert 	if (!refclock_process(pp)) {
368c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_BADTIME);
369c0b746e5SOllivier Robert 		return;
370c0b746e5SOllivier Robert 	}
371c0b746e5SOllivier Robert 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
372c0b746e5SOllivier Robert 	refclock_receive(peer);
373c0b746e5SOllivier Robert }
374c0b746e5SOllivier Robert 
375c0b746e5SOllivier Robert struct vmedate *
376c0b746e5SOllivier Robert get_datumtime(struct vmedate *time_vme)
377c0b746e5SOllivier Robert {
378c0b746e5SOllivier Robert 	unsigned short  status;
379c0b746e5SOllivier Robert 	char cbuf[7];
380c0b746e5SOllivier Robert 	struct btfp_time vts;
381c0b746e5SOllivier Robert 
382c0b746e5SOllivier Robert 	if ( time_vme == (struct vmedate *)NULL) {
383c0b746e5SOllivier Robert   	  time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
384c0b746e5SOllivier Robert 	}
385c0b746e5SOllivier Robert 
386c0b746e5SOllivier Robert 	if( ioctl(fd_vme, READTIME, &vts))
387c0b746e5SOllivier Robert 	    msyslog(LOG_ERR, "get_datumtime error: %m");
388c0b746e5SOllivier Robert 
389c0b746e5SOllivier Robert 	/* if you want to actually check the validity of these registers, do a
390c0b746e5SOllivier Robert 	   define of CHECK   above this.  I didn't find it necessary. - RES
391c0b746e5SOllivier Robert 	*/
392c0b746e5SOllivier Robert 
393c0b746e5SOllivier Robert #ifdef CHECK
394c0b746e5SOllivier Robert 
395c0b746e5SOllivier Robert 	/* Get day */
396c0b746e5SOllivier Robert 	sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
397c0b746e5SOllivier Robert 		((vts.btfp_time[ 1 ] & 0xff00) >> 8));
398c0b746e5SOllivier Robert 
399c0b746e5SOllivier Robert 	if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) )
400c0b746e5SOllivier Robert 	    time_vme->day = (unsigned short)atoi(cbuf);
401c0b746e5SOllivier Robert 	else
402c0b746e5SOllivier Robert 	    time_vme->day = (unsigned short) 0;
403c0b746e5SOllivier Robert 
404c0b746e5SOllivier Robert 	/* Get hour */
405c0b746e5SOllivier Robert 	sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff);
406c0b746e5SOllivier Robert 
407c0b746e5SOllivier Robert 	if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
408c0b746e5SOllivier Robert 	    time_vme->hr = (unsigned short)atoi(cbuf);
409c0b746e5SOllivier Robert 	else
410c0b746e5SOllivier Robert 	    time_vme->hr = (unsigned short) 0;
411c0b746e5SOllivier Robert 
412c0b746e5SOllivier Robert 	/* Get minutes */
413c0b746e5SOllivier Robert 	sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8);
414c0b746e5SOllivier Robert 	if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
415c0b746e5SOllivier Robert 	    time_vme->mn = (unsigned short)atoi(cbuf);
416c0b746e5SOllivier Robert 	else
417c0b746e5SOllivier Robert 	    time_vme->mn = (unsigned short) 0;
418c0b746e5SOllivier Robert 
419c0b746e5SOllivier Robert 	/* Get seconds */
420c0b746e5SOllivier Robert 	sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff);
421c0b746e5SOllivier Robert 
422c0b746e5SOllivier Robert 	if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
423c0b746e5SOllivier Robert 	    time_vme->sec = (unsigned short)atoi(cbuf);
424c0b746e5SOllivier Robert 	else
425c0b746e5SOllivier Robert 	    time_vme->sec = (unsigned short) 0;
426c0b746e5SOllivier Robert 
427c0b746e5SOllivier Robert 	/* Get microseconds.  Yes, we ignore the 0.1 microsecond digit so we can
428c0b746e5SOllivier Robert 	   use the TVTOTSF function  later on...*/
429c0b746e5SOllivier Robert 
430c0b746e5SOllivier Robert 	sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ],
431c0b746e5SOllivier Robert 		vts.btfp_time[ 4 ]>>8);
432c0b746e5SOllivier Robert 
433c0b746e5SOllivier Robert 	if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2])
434c0b746e5SOllivier Robert 	    && isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5]))
435c0b746e5SOllivier Robert 	    time_vme->frac = (u_long) atoi(cbuf);
436c0b746e5SOllivier Robert 	else
437c0b746e5SOllivier Robert 	    time_vme->frac = (u_long) 0;
438c0b746e5SOllivier Robert #else
439c0b746e5SOllivier Robert 
440c0b746e5SOllivier Robert 	/* DONT CHECK  just trust the card */
441c0b746e5SOllivier Robert 
442c0b746e5SOllivier Robert 	/* Get day */
443c0b746e5SOllivier Robert 	sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
444c0b746e5SOllivier Robert 		((vts.btfp_time[ 1 ] & 0xff00) >> 8));
445c0b746e5SOllivier Robert 	time_vme->day = (unsigned short)atoi(cbuf);
446c0b746e5SOllivier Robert 
447c0b746e5SOllivier Robert 	/* Get hour */
448c0b746e5SOllivier Robert 	sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff);
449c0b746e5SOllivier Robert 
450c0b746e5SOllivier Robert 	time_vme->hr = (unsigned short)atoi(cbuf);
451c0b746e5SOllivier Robert 
452c0b746e5SOllivier Robert 	/* Get minutes */
453c0b746e5SOllivier Robert 	sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8);
454c0b746e5SOllivier Robert 	time_vme->mn = (unsigned short)atoi(cbuf);
455c0b746e5SOllivier Robert 
456c0b746e5SOllivier Robert 	/* Get seconds */
457c0b746e5SOllivier Robert 	sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff);
458c0b746e5SOllivier Robert 	time_vme->sec = (unsigned short)atoi(cbuf);
459c0b746e5SOllivier Robert 
460c0b746e5SOllivier Robert 	/* Get microseconds.  Yes, we ignore the 0.1 microsecond digit so we can
461c0b746e5SOllivier Robert 	   use the TVTOTSF function  later on...*/
462c0b746e5SOllivier Robert 
463c0b746e5SOllivier Robert 	sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ],
464c0b746e5SOllivier Robert 		vts.btfp_time[ 4 ]>>8);
465c0b746e5SOllivier Robert 
466c0b746e5SOllivier Robert 	time_vme->frac = (u_long) atoi(cbuf);
467c0b746e5SOllivier Robert 
468c0b746e5SOllivier Robert #endif /* CHECK */
469c0b746e5SOllivier Robert 
470c0b746e5SOllivier Robert 	/* Get status bit */
471c0b746e5SOllivier Robert 	status = (vts.btfp_time[0] & 0x0010) >>4;
472c0b746e5SOllivier Robert 	time_vme->status = status;  /* Status=0 if locked to ref. */
473c0b746e5SOllivier Robert 	/* Status=1 if flywheeling */
474c0b746e5SOllivier Robert 	if (status) {        /* lost lock ? */
475c0b746e5SOllivier Robert 		return ((void *)NULL);
476c0b746e5SOllivier Robert 	}
477c0b746e5SOllivier Robert 	else
478c0b746e5SOllivier Robert 	    return (time_vme);
479c0b746e5SOllivier Robert }
480c0b746e5SOllivier Robert 
481c0b746e5SOllivier Robert #else
482c0b746e5SOllivier Robert int refclock_bancomm_bs;
483c0b746e5SOllivier Robert #endif /* REFCLOCK */
484