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