summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/refclock_bancomm.c
blob: 95c211b15fc25e407b3db5c7c19768d668daed14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
/* refclock_bancomm.c - clock driver for the  Datum/Bancomm bc635VME 
 * Time and Frequency Processor. It requires the BANCOMM bc635VME/
 * bc350VXI Time and Frequency Processor Module Driver for SunOS4.x 
 * and SunOS5.x UNIX Systems. It has been tested on a UltraSparc 
 * IIi-cEngine running Solaris 2.6.
 * 
 * Author(s): 	Ganesh Ramasivan & Gary Cliff, Computing Devices Canada,
 *		Ottawa, Canada
 *
 * Date: 	July 1999
 *
 * Note(s):	The refclock type has been defined as 16.
 *
 *		This program has been modelled after the Bancomm driver
 *		originally written by R. Schmidt of Time Service, U.S. 
 *		Naval Observatory for a HP-UX machine. Since the original
 *		authors no longer plan to maintain this code, all 
 *		references to the HP-UX vme2 driver subsystem bave been
 *		removed. Functions vme_report_event(), vme_receive(), 
 *		vme_control() and vme_buginfo() have been deleted because
 *		they are no longer being used.
 *
 *		The time on the bc635 TFP must be set to GMT due to the 
 *		fact that NTP makes use of GMT for all its calculations.
 *
 *		Installation of the Datum/Bancomm driver creates the 
 *		device file /dev/btfp0 
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#if defined(REFCLOCK) && defined(CLOCK_BANC) 
#include <stdio.h>
#include <syslog.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>

#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"

/*  STUFF BY RES */
struct btfp_time                /* Structure for reading 5 time words   */
                                /* in one ioctl(2) operation.           */
{
	unsigned short btfp_time[5];  /* Time words 0,1,2,3, and 4. (16bit)*/
};

/* SunOS5 ioctl commands definitions.*/
#define BTFPIOC            ( 'b'<< 8 )
#define IOCIO( l, n )      ( BTFPIOC | n )
#define IOCIOR( l, n, s )  ( BTFPIOC | n )
#define IOCIORN( l, n, s ) ( BTFPIOC | n )
#define IOCIOWN( l, n, s ) ( BTFPIOC | n )

/***** Simple ioctl commands *****/
#define RUNLOCK     	IOCIOR(b, 19, int )  /* Release Capture Lockout */
#define RCR0      	IOCIOR(b, 22, int )  /* Read control register zero.*/
#define	WCR0		IOCIOWN(b, 23, int)	     /* Write control register zero*/

/***** Compound ioctl commands *****/

/* Read all 5 time words in one call.   */
#define READTIME	IOCIORN(b, 32, sizeof( struct btfp_time ))
#define VMEFD "/dev/btfp0"

struct vmedate {               /* structure returned by get_vmetime.c */
	unsigned short year;
	unsigned short day;
	unsigned short hr;
	unsigned short mn;
	unsigned short sec;
	unsigned long frac;
	unsigned short status;
};

/* END OF STUFF FROM RES */

/*
 * Definitions
 */
#define MAXUNITS 2              /* max number of VME units */

/*
 * VME interface parameters. 
 */
#define VMEPRECISION    (-21)   /* precision assumed (1 us) */
#define USNOREFID       "BTFP"  /* or whatever */
#define VMEREFID        "BTFP"  /* reference id */
#define VMEDESCRIPTION  "Bancomm bc635 TFP" /* who we are */
#define VMEHSREFID      0x7f7f1000 /* 127.127.16.00 refid hi strata */
/* clock type 16 is used here  */
#define GMT           	0       /* hour offset from Greenwich */

/*
 * Imported from ntp_timer module
 */
extern u_long current_time;     /* current time(s) */

/*
 * Imported from ntpd module
 */
extern int debug;               /* global debug flag */

/*
 * VME unit control structure.
 * Changes made to vmeunit structure. Most members are now available in the 
 * new refclockproc structure in ntp_refclock.h - 07/99 - Ganesh Ramasivan
 */
struct vmeunit {
	struct vmedate vmedata; /* data returned from vme read */
	u_long lasttime;        /* last time clock heard from */
};

/*
 * Keep the fudge factors separately so they can be set even
 * when no clock is configured.
 */
static double fudgefactor[MAXUNITS];
static u_char stratumtouse[MAXUNITS];
static u_char sloppyclockflag[MAXUNITS];

/*
 * Function prototypes
 */
static  void    vme_init        (void);
static  int     vme_start       (int, struct peer *);
static  void    vme_shutdown    (int, struct peer *);
static  void    vme_receive     (struct recvbuf *);
static  void    vme_poll        (int unit, struct peer *);
struct vmedate *get_datumtime(struct vmedate *);

/*
 * Transfer vector
 */
struct  refclock refclock_bancomm = {
	vme_start, 
	vme_shutdown, 
	vme_poll,
	noentry,       /* not used (old vme_control) */   
	vme_init, 
	noentry,       /* not used (old vme_buginfo) */ 
	NOFLAGS
};

int fd_vme;  /* file descriptor for ioctls */
int regvalue;

/*
 * vme_init - initialize internal vme driver data
 */
static void
vme_init(void)
{
	register int i;

	/*
	 * Initialize fudge factors to default.
	 */
	for (i = 0; i < MAXUNITS; i++) {
		fudgefactor[i]  = 0.0;
		stratumtouse[i] = 0;
		sloppyclockflag[i] = 0;
	}
}

/*
 * vme_start - open the VME device and initialize data for processing
 */
static int
vme_start(
	int unit,
	struct peer *peer
	)
{
	register struct vmeunit *vme;
	struct refclockproc *pp;
	int dummy;
	char vmedev[20];

	/*
	 * Check configuration info.
	 */
	if (unit >= MAXUNITS) {
		msyslog(LOG_ERR, "vme_start: unit %d invalid", unit);
		return (0);
	}

	/*
	 * Open VME device
	 */
#ifdef DEBUG

	printf("Opening DATUM VME DEVICE \n");
#endif
	if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) {
		msyslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
		return (0);
	}
	else  { /* Release capture lockout in case it was set from before. */
		if( ioctl( fd_vme, RUNLOCK, &dummy ) )
		    msyslog(LOG_ERR, "vme_start: RUNLOCK failed %m");

		regvalue = 0; /* More esoteric stuff to do... */
		if( ioctl( fd_vme, WCR0, &regvalue ) )
		    msyslog(LOG_ERR, "vme_start: WCR0 failed %m");
	}

	/*
	 * Allocate unit structure
	 */
	vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit));
	bzero((char *)vme, sizeof(struct vmeunit));


	/*
	 * Set up the structures
	 */
	pp = peer->procptr;
	pp->unitptr = (caddr_t) vme;
	pp->timestarted = current_time;

	pp->io.clock_recv = vme_receive;
	pp->io.srcclock = (caddr_t)peer;
	pp->io.datalen = 0;
	pp->io.fd = fd_vme;

	/*
	 * All done.  Initialize a few random peer variables, then
 	 * return success. Note that root delay and root dispersion are
	 * always zero for this clock.
	 */
	pp->leap = LEAP_NOWARNING;
	peer->precision = VMEPRECISION;
	peer->stratum = stratumtouse[unit];
	memcpy( (char *)&peer->refid, USNOREFID,4);

	peer->refid = htonl(VMEHSREFID);

	return (1);
}


/*
 * vme_shutdown - shut down a VME clock
 */
static void
vme_shutdown(
	int unit, 
	struct peer *peer
	)
{
	register struct vmeunit *vme;
	struct refclockproc *pp;
	
	pp = peer->procptr;

	if (unit >= MAXUNITS) {
		msyslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit);
		return;
	}

	/*
	 * Tell the I/O module to turn us off.  We're history.
	 */
	vme = (struct vmeunit *)pp->unitptr;
	io_closeclock(&pp->io);
	pp->unitptr = NULL;
	free(vme);
}


/*
 * vme_receive - receive data from the VME device.
 *
 * Note: This interface would be interrupt-driven. We don't use that
 * now, but include a dummy routine for possible future adventures.
 */
static void
vme_receive(
	struct recvbuf *rbufp
	)
{
}


/*
 * vme_poll - called by the transmit procedure
 */
static void
vme_poll(
	int unit,
	struct peer *peer
	)
{
	struct vmedate *tptr; 
	struct vmeunit *vme;
	struct refclockproc *pp;
	time_t tloc;
	struct tm *tadr;
        
	pp = peer->procptr;	 
	vme = (struct vmeunit *)pp->unitptr;        /* Here is the structure */

	tptr = &vme->vmedata; 
	if ((tptr = get_datumtime(tptr)) == NULL ) {
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	get_systime(&pp->lastrec);
	pp->polls++;
	vme->lasttime = current_time;

	/*
	 * Get VME time and convert to timestamp format. 
	 * The year must come from the system clock.
	 */
	
	  time(&tloc);
	  tadr = gmtime(&tloc);
	  tptr->year = (unsigned short)(tadr->tm_year + 1900);
	

	sprintf(pp->a_lastcode, 
		"%3.3d %2.2d:%2.2d:%2.2d.%.6ld %1d",
		tptr->day, 
		tptr->hr, 
		tptr->mn,
		tptr->sec, 
		tptr->frac, 
		tptr->status);

	pp->lencode = (u_short) strlen(pp->a_lastcode);

	pp->day =  tptr->day;
	pp->hour =   tptr->hr;
	pp->minute =  tptr->mn;
	pp->second =  tptr->sec;
	pp->usec =   tptr->frac;	

#ifdef DEBUG
	if (debug)
	    printf("pp: %3d %02d:%02d:%02d.%06ld %1x\n",
		   pp->day, pp->hour, pp->minute, pp->second,
		   pp->usec, tptr->status);
#endif
	if (tptr->status ) {       /*  Status 0 is locked to ref., 1 is not */
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	/*
	 * Now, compute the reference time value. Use the heavy
	 * machinery for the seconds and the millisecond field for the
	 * fraction when present. If an error in conversion to internal
	 * format is found, the program declares bad data and exits.
	 * Note that this code does not yet know how to do the years and
	 * relies on the clock-calendar chip for sanity.
	 */
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	refclock_receive(peer);
}

struct vmedate *
get_datumtime(struct vmedate *time_vme)
{
	unsigned short  status;
	char cbuf[7];
	struct btfp_time vts;
	
	if ( time_vme == (struct vmedate *)NULL) {
  	  time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
	}

	if( ioctl(fd_vme, READTIME, &vts))
	    msyslog(LOG_ERR, "get_datumtime error: %m");

	/* if you want to actually check the validity of these registers, do a 
	   define of CHECK   above this.  I didn't find it necessary. - RES
	*/

#ifdef CHECK            

	/* Get day */
	sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
		((vts.btfp_time[ 1 ] & 0xff00) >> 8));  

	if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) )
	    time_vme->day = (unsigned short)atoi(cbuf);
	else
	    time_vme->day = (unsigned short) 0;

	/* Get hour */
	sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff);

	if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
	    time_vme->hr = (unsigned short)atoi(cbuf);
	else
	    time_vme->hr = (unsigned short) 0;

	/* Get minutes */
	sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8);
	if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
	    time_vme->mn = (unsigned short)atoi(cbuf);
	else
	    time_vme->mn = (unsigned short) 0;

	/* Get seconds */
	sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff);

	if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
	    time_vme->sec = (unsigned short)atoi(cbuf);
	else
	    time_vme->sec = (unsigned short) 0;

	/* Get microseconds.  Yes, we ignore the 0.1 microsecond digit so we can
	   use the TVTOTSF function  later on...*/

	sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ],
		vts.btfp_time[ 4 ]>>8);

	if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2])
	    && isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5]))
	    time_vme->frac = (u_long) atoi(cbuf);
	else
	    time_vme->frac = (u_long) 0;
#else

	/* DONT CHECK  just trust the card */

	/* Get day */
	sprintf(cbuf,"%3.3x", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
		((vts.btfp_time[ 1 ] & 0xff00) >> 8));  
	time_vme->day = (unsigned short)atoi(cbuf);

	/* Get hour */
	sprintf(cbuf,"%2.2x", vts.btfp_time[ 1 ] & 0x00ff);

	time_vme->hr = (unsigned short)atoi(cbuf);

	/* Get minutes */
	sprintf(cbuf,"%2.2x", (vts.btfp_time[ 2 ] & 0xff00) >>8);
	time_vme->mn = (unsigned short)atoi(cbuf);

	/* Get seconds */
	sprintf(cbuf,"%2.2x", vts.btfp_time[ 2 ] & 0x00ff);
	time_vme->sec = (unsigned short)atoi(cbuf);

	/* Get microseconds.  Yes, we ignore the 0.1 microsecond digit so we can
	   use the TVTOTSF function  later on...*/

	sprintf(cbuf,"%4.4x%2.2x", vts.btfp_time[ 3 ],
		vts.btfp_time[ 4 ]>>8);

	time_vme->frac = (u_long) atoi(cbuf);

#endif /* CHECK */

	/* Get status bit */
	status = (vts.btfp_time[0] & 0x0010) >>4;
	time_vme->status = status;  /* Status=0 if locked to ref. */
	/* Status=1 if flywheeling */
	if (status) {        /* lost lock ? */
		return ((void *)NULL);
	}
	else
	    return (time_vme);
}

#else
int refclock_bancomm_bs;
#endif /* REFCLOCK */
OpenPOWER on IntegriCloud