182498Sroberto/*
282498Sroberto * refclock_hopfpci.c
382498Sroberto *
482498Sroberto * - clock driver for hopf 6039 PCI board (GPS or DCF77)
582498Sroberto * Bernd Altmeier altmeier@atlsoft.de
682498Sroberto *
782498Sroberto * latest source and further information can be found at:
882498Sroberto * http://www.ATLSoft.de/ntp
982498Sroberto *
1082498Sroberto * In order to run this driver you have to install and test
1182498Sroberto * the PCI-board driver for your system first.
1282498Sroberto *
1382498Sroberto * On Linux/UNIX
1482498Sroberto *
1582498Sroberto * The driver attempts to open the device /dev/hopf6039 .
1682498Sroberto * The device entry will be made by the installation process of
1782498Sroberto * the kernel module for the PCI-bus board. The driver sources
1882498Sroberto * belongs to the delivery equipment of the PCI-board.
1982498Sroberto *
2082498Sroberto * On Windows NT/2000
2182498Sroberto *
2282498Sroberto * The driver attempts to open the device by calling the function
2382498Sroberto * "OpenHopfDevice()". This function will be installed by the
2482498Sroberto * Device Driver for the PCI-bus board. The driver belongs to the
2582498Sroberto * delivery equipment of the PCI-board.
2682498Sroberto *
2782498Sroberto *
2882498Sroberto * Start   21.03.2000 Revision: 01.20
2982498Sroberto * changes 22.12.2000 Revision: 01.40 flag1 = 1 sync even if Quarz
3082498Sroberto *
3182498Sroberto */
3282498Sroberto
3382498Sroberto#ifdef HAVE_CONFIG_H
3482498Sroberto# include <config.h>
3582498Sroberto#endif
3682498Sroberto
3782498Sroberto#if defined(REFCLOCK) && defined(CLOCK_HOPF_PCI)
3882498Sroberto
3982498Sroberto#include "ntpd.h"
4082498Sroberto#include "ntp_io.h"
4182498Sroberto#include "ntp_refclock.h"
4282498Sroberto#include "ntp_unixtime.h"
4382498Sroberto#include "ntp_stdlib.h"
4482498Sroberto
4582498Sroberto#undef fileno
4682498Sroberto#include <ctype.h>
4782498Sroberto#undef fileno
4882498Sroberto
4982498Sroberto#ifndef SYS_WINNT
5082498Sroberto# include <sys/ipc.h>
51132451Sroberto# include <sys/ioctl.h>
5282498Sroberto# include <assert.h>
5382498Sroberto# include <unistd.h>
5482498Sroberto# include <stdio.h>
5582498Sroberto# include "hopf6039.h"
5682498Sroberto#else
5782498Sroberto# include "hopf_PCI_io.h"
5882498Sroberto#endif
5982498Sroberto
6082498Sroberto/*
6182498Sroberto * hopfpci interface definitions
6282498Sroberto */
6382498Sroberto#define PRECISION       (-10)    /* precision assumed (1 ms) */
6482498Sroberto#define REFID           "hopf"   /* reference ID */
6582498Sroberto#define DESCRIPTION     "hopf Elektronik PCI radio board"
6682498Sroberto
6782498Sroberto#define NSAMPLES        3       /* stages of median filter */
6882498Sroberto#ifndef SYS_WINNT
6982498Sroberto# define	DEVICE	"/dev/hopf6039" 	/* device name inode*/
7082498Sroberto#else
7182498Sroberto# define	DEVICE	"hopf6039" 	/* device name WinNT  */
7282498Sroberto#endif
7382498Sroberto
7482498Sroberto#define LEWAPWAR	0x20	/* leap second warning bit */
7582498Sroberto
7682498Sroberto#define	HOPF_OPMODE	0xC0	/* operation mode mask */
7782498Sroberto#define HOPF_INVALID	0x00	/* no time code available */
7882498Sroberto#define HOPF_INTERNAL	0x40	/* internal clock */
7982498Sroberto#define HOPF_RADIO	0x80	/* radio clock */
8082498Sroberto#define HOPF_RADIOHP	0xC0	/* high precision radio clock */
8182498Sroberto
8282498Sroberto
8382498Sroberto/*
8482498Sroberto * hopfclock unit control structure.
8582498Sroberto */
8682498Srobertostruct hopfclock_unit {
8782498Sroberto	short	unit;		/* NTP refclock unit number */
8882498Sroberto	char	leap_status;	/* leap second flag */
8982498Sroberto};
9082498Srobertoint	fd;			/* file descr. */
9182498Sroberto
9282498Sroberto/*
9382498Sroberto * Function prototypes
9482498Sroberto */
9582498Srobertostatic  int     hopfpci_start       (int, struct peer *);
9682498Srobertostatic  void    hopfpci_shutdown    (int, struct peer *);
9782498Srobertostatic  void    hopfpci_poll        (int unit, struct peer *);
9882498Sroberto
9982498Sroberto/*
10082498Sroberto * Transfer vector
10182498Sroberto */
10282498Srobertostruct  refclock refclock_hopfpci = {
10382498Sroberto	hopfpci_start,          /* start up driver */
10482498Sroberto	hopfpci_shutdown,       /* shut down driver */
10582498Sroberto	hopfpci_poll,           /* transmit poll message */
10682498Sroberto	noentry,                /* not used */
10782498Sroberto	noentry,                /* initialize driver (not used) */
10882498Sroberto	noentry,                /* not used */
10982498Sroberto	NOFLAGS                 /* not used */
11082498Sroberto};
11182498Sroberto
11282498Sroberto/*
11382498Sroberto * hopfpci_start - attach to hopf PCI board 6039
11482498Sroberto */
11582498Srobertostatic int
11682498Srobertohopfpci_start(
11782498Sroberto	int unit,
11882498Sroberto	struct peer *peer
11982498Sroberto	)
12082498Sroberto{
12182498Sroberto	struct refclockproc *pp;
12282498Sroberto	struct hopfclock_unit *up;
12382498Sroberto
12482498Sroberto	/*
12582498Sroberto	 * Allocate and initialize unit structure
12682498Sroberto	 */
12782498Sroberto	up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
12882498Sroberto
12982498Sroberto	if (!(up)) {
13082498Sroberto                msyslog(LOG_ERR, "hopfPCIClock(%d) emalloc: %m",unit);
13182498Sroberto#ifdef DEBUG
13282498Sroberto                printf("hopfPCIClock(%d) emalloc\n",unit);
13382498Sroberto#endif
13482498Sroberto		return (0);
13582498Sroberto	}
13682498Sroberto	memset((char *)up, 0, sizeof(struct hopfclock_unit));
13782498Sroberto
13882498Sroberto#ifndef SYS_WINNT
13982498Sroberto
14082498Sroberto 	fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */
14182498Sroberto
14282498Sroberto#else
14382498Sroberto	if (!OpenHopfDevice()){
14482498Sroberto		msyslog(LOG_ERR,"Start: %s unit: %d failed!",DEVICE,unit);
14582498Sroberto		return (0);
14682498Sroberto	}
14782498Sroberto#endif
14882498Sroberto
14982498Sroberto	pp = peer->procptr;
15082498Sroberto	pp->io.clock_recv = noentry;
15182498Sroberto	pp->io.srcclock = (caddr_t)peer;
15282498Sroberto	pp->io.datalen = 0;
153132451Sroberto	pp->io.fd = INVALID_SOCKET;
15482498Sroberto	pp->unitptr = (caddr_t)up;
15582498Sroberto
15682498Sroberto	get_systime(&pp->lastrec);
15782498Sroberto
15882498Sroberto	/*
15982498Sroberto	 * Initialize miscellaneous peer variables
16082498Sroberto	 */
16182498Sroberto	if (pp->unitptr!=0) {
16282498Sroberto		memcpy((char *)&pp->refid, REFID, 4);
16382498Sroberto		peer->precision = PRECISION;
16482498Sroberto		pp->clockdesc = DESCRIPTION;
16582498Sroberto		up->leap_status = 0;
16682498Sroberto		up->unit = (short) unit;
16782498Sroberto		return (1);
16882498Sroberto	}
16982498Sroberto	else {
17082498Sroberto		return 0;
17182498Sroberto	}
17282498Sroberto}
17382498Sroberto
17482498Sroberto
17582498Sroberto/*
17682498Sroberto * hopfpci_shutdown - shut down the clock
17782498Sroberto */
17882498Srobertostatic void
17982498Srobertohopfpci_shutdown(
18082498Sroberto	int unit,
18182498Sroberto	struct peer *peer
18282498Sroberto	)
18382498Sroberto{
18482498Sroberto
18582498Sroberto#ifndef SYS_WINNT
18682498Sroberto	close(fd);
18782498Sroberto#else
18882498Sroberto	CloseHopfDevice();
18982498Sroberto#endif
19082498Sroberto}
19182498Sroberto
19282498Sroberto
19382498Sroberto/*
19482498Sroberto * hopfpci_poll - called by the transmit procedure
19582498Sroberto */
19682498Srobertostatic void
19782498Srobertohopfpci_poll(
19882498Sroberto	int unit,
19982498Sroberto	struct peer *peer
20082498Sroberto	)
20182498Sroberto{
20282498Sroberto	struct refclockproc *pp;
20382498Sroberto	HOPFTIME m_time;
20482498Sroberto
20582498Sroberto	pp = peer->procptr;
20682498Sroberto
20782498Sroberto#ifndef SYS_WINNT
208132451Sroberto	ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time);
20982498Sroberto#else
21082498Sroberto	GetHopfSystemTime(&m_time);
21182498Sroberto#endif
21282498Sroberto	pp->polls++;
21382498Sroberto
21482498Sroberto	pp->day    = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay);
21582498Sroberto	pp->hour   = m_time.wHour;
21682498Sroberto	pp->minute = m_time.wMinute;
21782498Sroberto	pp->second = m_time.wSecond;
218132451Sroberto	pp->nsec   = m_time.wMilliseconds * 1000000;
21982498Sroberto	if (m_time.wStatus & LEWAPWAR)
22082498Sroberto		pp->leap = LEAP_ADDSECOND;
22182498Sroberto	else
22282498Sroberto		pp->leap = LEAP_NOWARNING;
22382498Sroberto
224132451Sroberto	sprintf(pp->a_lastcode,"ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d",
225132451Sroberto		m_time.wStatus, pp->hour, pp->minute, pp->second,
226132451Sroberto		pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear);
227132451Sroberto	pp->lencode = (u_short)strlen(pp->a_lastcode);
22882498Sroberto
22982498Sroberto	get_systime(&pp->lastrec);
23082498Sroberto
23182498Sroberto	/*
23282498Sroberto	 * If clock has no valid status then report error and exit
23382498Sroberto	 */
23482498Sroberto	if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) {  /* time ok? */
23582498Sroberto		refclock_report(peer, CEVNT_BADTIME);
23682498Sroberto		pp->leap = LEAP_NOTINSYNC;
23782498Sroberto		return;
23882498Sroberto	}
23982498Sroberto
24082498Sroberto	/*
24182498Sroberto	 * Test if time is running on internal quarz
24282498Sroberto	 * if CLK_FLAG1 is set, sychronize even if no radio operation
24382498Sroberto	 */
24482498Sroberto
24582498Sroberto	if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){
24682498Sroberto		if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
24782498Sroberto			refclock_report(peer, CEVNT_BADTIME);
24882498Sroberto			pp->leap = LEAP_NOTINSYNC;
24982498Sroberto			return;
25082498Sroberto		}
25182498Sroberto	}
25282498Sroberto
25382498Sroberto	if (!refclock_process(pp)) {
25482498Sroberto		refclock_report(peer, CEVNT_BADTIME);
25582498Sroberto		return;
25682498Sroberto	}
257132451Sroberto	pp->lastref = pp->lastrec;
25882498Sroberto	refclock_receive(peer);
25982498Sroberto	record_clock_stats(&peer->srcadr, pp->a_lastcode);
26082498Sroberto	return;
26182498Sroberto}
26282498Sroberto
26382498Sroberto#else
26482498Srobertoint refclock_hopfpci_bs;
26582498Sroberto#endif /* REFCLOCK */
266