xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_hopfpci.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: refclock_hopfpci.c,v 1.1.1.1 2009/12/13 16:55:48 kardel Exp $	*/
2 
3 /*
4  * refclock_hopfpci.c
5  *
6  * - clock driver for hopf 6039 PCI board (GPS or DCF77)
7  * Bernd Altmeier altmeier@atlsoft.de
8  *
9  * latest source and further information can be found at:
10  * http://www.ATLSoft.de/ntp
11  *
12  * In order to run this driver you have to install and test
13  * the PCI-board driver for your system first.
14  *
15  * On Linux/UNIX
16  *
17  * The driver attempts to open the device /dev/hopf6039 .
18  * The device entry will be made by the installation process of
19  * the kernel module for the PCI-bus board. The driver sources
20  * belongs to the delivery equipment of the PCI-board.
21  *
22  * On Windows NT/2000
23  *
24  * The driver attempts to open the device by calling the function
25  * "OpenHopfDevice()". This function will be installed by the
26  * Device Driver for the PCI-bus board. The driver belongs to the
27  * delivery equipment of the PCI-board.
28  *
29  *
30  * Start   21.03.2000 Revision: 01.20
31  * changes 22.12.2000 Revision: 01.40 flag1 = 1 sync even if Quarz
32  *
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 # include <config.h>
37 #endif
38 
39 #if defined(REFCLOCK) && defined(CLOCK_HOPF_PCI)
40 
41 #include "ntpd.h"
42 #include "ntp_io.h"
43 #include "ntp_refclock.h"
44 #include "ntp_unixtime.h"
45 #include "ntp_stdlib.h"
46 
47 #undef fileno
48 #include <ctype.h>
49 #undef fileno
50 
51 #ifndef SYS_WINNT
52 # include <sys/ipc.h>
53 # include <sys/ioctl.h>
54 # include <assert.h>
55 # include <unistd.h>
56 # include <stdio.h>
57 # include "hopf6039.h"
58 #else
59 # include "hopf_PCI_io.h"
60 #endif
61 
62 /*
63  * hopfpci interface definitions
64  */
65 #define PRECISION       (-10)    /* precision assumed (1 ms) */
66 #define REFID           "hopf"   /* reference ID */
67 #define DESCRIPTION     "hopf Elektronik PCI radio board"
68 
69 #define NSAMPLES        3       /* stages of median filter */
70 #ifndef SYS_WINNT
71 # define	DEVICE	"/dev/hopf6039" 	/* device name inode*/
72 #else
73 # define	DEVICE	"hopf6039" 	/* device name WinNT  */
74 #endif
75 
76 #define LEWAPWAR	0x20	/* leap second warning bit */
77 
78 #define	HOPF_OPMODE	0xC0	/* operation mode mask */
79 #define HOPF_INVALID	0x00	/* no time code available */
80 #define HOPF_INTERNAL	0x40	/* internal clock */
81 #define HOPF_RADIO	0x80	/* radio clock */
82 #define HOPF_RADIOHP	0xC0	/* high precision radio clock */
83 
84 
85 /*
86  * hopfclock unit control structure.
87  */
88 struct hopfclock_unit {
89 	short	unit;		/* NTP refclock unit number */
90 	char	leap_status;	/* leap second flag */
91 };
92 int	fd;			/* file descr. */
93 
94 /*
95  * Function prototypes
96  */
97 static  int     hopfpci_start       (int, struct peer *);
98 static  void    hopfpci_shutdown    (int, struct peer *);
99 static  void    hopfpci_poll        (int unit, struct peer *);
100 
101 /*
102  * Transfer vector
103  */
104 struct  refclock refclock_hopfpci = {
105 	hopfpci_start,          /* start up driver */
106 	hopfpci_shutdown,       /* shut down driver */
107 	hopfpci_poll,           /* transmit poll message */
108 	noentry,                /* not used */
109 	noentry,                /* initialize driver (not used) */
110 	noentry,                /* not used */
111 	NOFLAGS                 /* not used */
112 };
113 
114 /*
115  * hopfpci_start - attach to hopf PCI board 6039
116  */
117 static int
118 hopfpci_start(
119 	int unit,
120 	struct peer *peer
121 	)
122 {
123 	struct refclockproc *pp;
124 	struct hopfclock_unit *up;
125 
126 	/*
127 	 * Allocate and initialize unit structure
128 	 */
129 	up = (struct hopfclock_unit *) emalloc(sizeof(struct hopfclock_unit));
130 
131 	if (!(up)) {
132                 msyslog(LOG_ERR, "hopfPCIClock(%d) emalloc: %m",unit);
133 #ifdef DEBUG
134                 printf("hopfPCIClock(%d) emalloc\n",unit);
135 #endif
136 		return (0);
137 	}
138 	memset((char *)up, 0, sizeof(struct hopfclock_unit));
139 
140 #ifndef SYS_WINNT
141 
142  	fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */
143 
144 #else
145 	if (!OpenHopfDevice()){
146 		msyslog(LOG_ERR,"Start: %s unit: %d failed!",DEVICE,unit);
147 		return (0);
148 	}
149 #endif
150 
151 	pp = peer->procptr;
152 	pp->io.clock_recv = noentry;
153 	pp->io.srcclock = (caddr_t)peer;
154 	pp->io.datalen = 0;
155 	pp->io.fd = INVALID_SOCKET;
156 	pp->unitptr = (caddr_t)up;
157 
158 	get_systime(&pp->lastrec);
159 
160 	/*
161 	 * Initialize miscellaneous peer variables
162 	 */
163 	if (pp->unitptr!=0) {
164 		memcpy((char *)&pp->refid, REFID, 4);
165 		peer->precision = PRECISION;
166 		pp->clockdesc = DESCRIPTION;
167 		up->leap_status = 0;
168 		up->unit = (short) unit;
169 		return (1);
170 	}
171 	else {
172 		return 0;
173 	}
174 }
175 
176 
177 /*
178  * hopfpci_shutdown - shut down the clock
179  */
180 static void
181 hopfpci_shutdown(
182 	int unit,
183 	struct peer *peer
184 	)
185 {
186 
187 #ifndef SYS_WINNT
188 	close(fd);
189 #else
190 	CloseHopfDevice();
191 #endif
192 }
193 
194 
195 /*
196  * hopfpci_poll - called by the transmit procedure
197  */
198 static void
199 hopfpci_poll(
200 	int unit,
201 	struct peer *peer
202 	)
203 {
204 	struct refclockproc *pp;
205 	HOPFTIME m_time;
206 
207 	pp = peer->procptr;
208 
209 #ifndef SYS_WINNT
210 	ioctl(fd,HOPF_CLOCK_GET_UTC,&m_time);
211 #else
212 	GetHopfSystemTime(&m_time);
213 #endif
214 	pp->polls++;
215 
216 	pp->day    = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay);
217 	pp->hour   = m_time.wHour;
218 	pp->minute = m_time.wMinute;
219 	pp->second = m_time.wSecond;
220 	pp->nsec   = m_time.wMilliseconds * 1000000;
221 	if (m_time.wStatus & LEWAPWAR)
222 		pp->leap = LEAP_ADDSECOND;
223 	else
224 		pp->leap = LEAP_NOWARNING;
225 
226 	sprintf(pp->a_lastcode,"ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d",
227 		m_time.wStatus, pp->hour, pp->minute, pp->second,
228 		pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear);
229 	pp->lencode = (u_short)strlen(pp->a_lastcode);
230 
231 	get_systime(&pp->lastrec);
232 
233 	/*
234 	 * If clock has no valid status then report error and exit
235 	 */
236 	if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) {  /* time ok? */
237 		refclock_report(peer, CEVNT_BADTIME);
238 		pp->leap = LEAP_NOTINSYNC;
239 		return;
240 	}
241 
242 	/*
243 	 * Test if time is running on internal quarz
244 	 * if CLK_FLAG1 is set, sychronize even if no radio operation
245 	 */
246 
247 	if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){
248 		if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
249 			refclock_report(peer, CEVNT_BADTIME);
250 			pp->leap = LEAP_NOTINSYNC;
251 			return;
252 		}
253 	}
254 
255 	if (!refclock_process(pp)) {
256 		refclock_report(peer, CEVNT_BADTIME);
257 		return;
258 	}
259 	pp->lastref = pp->lastrec;
260 	refclock_receive(peer);
261 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
262 	return;
263 }
264 
265 #else
266 int refclock_hopfpci_bs;
267 #endif /* REFCLOCK */
268