[ntp:questions] Windows Refclock Driver

David Kuechenmeister kplus13 at yahoo.com
Wed Oct 29 19:50:05 UTC 2003


I'm writing a driver to access a ISA bus clock card. The card accepts
various inputs and the time & date are then available as four BCD
words on the ISA bus. I don't have an interrupt to drive the The
driver reads the bus memory when polled by the  transmit function.
Currently, I just use the system defaults.

After I read the memory, I put the binary time values into the
peer->procptr structure. Then I call the refclock_process and
refclock_receive functions. What I get back is an enormous amount of
drift and jitter. I'd appreciate some pointers to get back on track.
Following are excerpts from the driver code.

Thanks,
David Kuechenmeister


/*
 * This driver supports the Brandywine Communications ISA-SyncClock16
Time sync
 * board. Installation of the io.dll file in the system32 directory is
required.
 * io.dll provides some library calls that allow the ISA bus memory to
be read
 * in a windows operating system. The files iodll.c and iodll.h
provide an
 * interface to those functions.
 *
 * BCD values are read from the I/O memory, mapped in at a base
address of 0x300.
 * Status is also checked to determine if the board is synch'ed to a
time source.
 * This must also use the syncClock16 library and header files.
 */


/*
 * Imported from the timer module
 */
extern u_long current_time;

/*
 * Imported from ntp_proto
 */
extern s_char sys_precision;

/*
 * Definitions
 */
#define MAXUNITS 1              /* max number of SyncClock units */
#define	PRECISION	(-13)	/* precision assumed (about 100 us) */
#define	REFID		"IRIG"	/* reference ID */
#define	DESCRIPTION	"Brandywine Syncclock16"

static u_char unitinuse[MAXUNITS];


[prototypes and struct declarations omitted]
/*
 * syncclock_start - initialize the data and the board.
 */

static int syncclock_start(int unit, struct peer *peer)
{
	struct refclockproc *pp;
	register struct syncclock_unit *up;

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

	if(unitinuse[unit])
	{
		msyslog(LOG_ERR, "syncclock_start: unit %d in use", unit);
		return (0);
	}

	/*
	 * Allocate and initialize unit structure
	 */
	up = (struct syncclock_unit *)emalloc(sizeof(struct syncclock_unit));
	if(up == NULL)
	{
		msyslog(LOG_ERR, "syncclock_start: Couldn't allocate memory for unit
%d",unit);
		return (0);
	}
	memset((char *)up, 0, sizeof(struct syncclock_unit));

	/*
	 * Set up the structures
	 */
	up->peer = peer;
	up->unit = (u_short)unit;
	up->timestarted = current_time;

	up->io.clock_recv = syncclock_receive;
	up->io.srcclock = (caddr_t)up;
	up->io.datalen = 0;
	up->io.fd = 0;

	pp = peer->procptr;
	pp->unitptr = (caddr_t)up;
	pp->io.clock_recv = syncclock_receive;
	pp->io.srcclock = (caddr_t)peer;
	pp->io.datalen = 0;
	pp->io.fd = 0;
#if 0
	if (!io_addclock(&pp->io)) {
		msyslog(LOG_ERR, "syncclock_start: io_addclock failed for unit
%d",unit);
		free(up);
		return (0);
	}
#endif
	/*
	 * Initialize miscellaneous variables
	 */
	peer->precision = PRECISION;
	pp->clockdesc = DESCRIPTION;
	memcpy((char *)&pp->refid, REFID, 4);
	//peer->burst = MAXSTAGE;
	peer->sstclktype = CTL_SST_TS_UHF;

	up->unit = unit;

	unitinuse[unit] = 1;
	return 1;
}

/*
 * syncclock_shutdown - shut down the board.
 */
static void syncclock_shutdown(int unit, struct peer *peer)
{
	register struct syncclock_unit *sc;
	struct refclockproc *pp;

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

	if(!unitinuse[unit])
	{
		msyslog(LOG_ERR, "syncclock_shutdown: unit %d not in use", unit);
		return;
	}

	/*
	 * Tell the I/O module to turn us off.  We're history.
	 */
	pp = peer->procptr;
	sc = (struct syncclock_unit *)pp->unitptr;
	io_closeclock(&pp->io);
	pp->unitptr = NULL;
	free(sc);
	unitinuse[unit] = 0;

	return;
}
/*
 * syncclock_poll - called by the transmit function
 */
static void syncclock_poll(int unit, struct peer *peer)
{
	struct refclockproc *pp;
	struct syncclock_unit *up;
	struct scdate *tptr;
	time_t tloc;
	struct tm *tadr;

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

	if(!unitinuse[unit])
	{
		msyslog(LOG_ERR, "syncclock_poll: unit %d not in use", unit);
		return;
	}

	pp = peer->procptr;
	up = (struct syncclock_unit *)pp->unitptr;
	// get the time
	tptr = (struct scdate *)&up->scdata;
	
	if( (tptr = get_sctime()) == NULL)
	{
		// report event
		refclock_report(peer, CEVNT_BADREPLY);
		msyslog(LOG_ERR, "syncclock_poll: get_sctime failed for unit
%d",unit);
		return;
	}

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


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

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

	pp->day =  tptr->doy;
	pp->hour =   tptr->hr;
	pp->minute =  tptr->mn;
	pp->second =  tptr->sec;
	pp->nsec =   tptr->frac * 1000;	

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

	/*
	 * Now, compute the reference time value. 
	 */
	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	
	return;
}

/*
 * syncclock_receive - collect the bcd data
 * this should be interrupt driven,but that isn't 
 * done now. The stub is here for future adventures.
 * The main business is done in the receive function.
 */
static void syncclock_receive(struct recvbuf * recvbuf)
{
	return;
}



More information about the questions mailing list