1 /* $NetBSD: refclock_hopfpci.c,v 1.6 2024/08/18 20:47:18 christos 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
hopfpci_start(int unit,struct peer * peer)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 = emalloc_zero(sizeof(*up));
130
131 #ifndef SYS_WINNT
132
133 fd = open(DEVICE,O_RDWR); /* try to open hopf clock device */
134
135 #else
136 if (!OpenHopfDevice()) {
137 msyslog(LOG_ERR, "Start: %s unit: %d failed!", DEVICE, unit);
138 free(up);
139 return (0);
140 }
141 #endif
142
143 pp = peer->procptr;
144 pp->io.clock_recv = noentry;
145 pp->io.srcclock = peer;
146 pp->io.datalen = 0;
147 pp->io.fd = INVALID_SOCKET;
148 pp->unitptr = up;
149
150 get_systime(&pp->lastrec);
151
152 /*
153 * Initialize miscellaneous peer variables
154 */
155 memcpy((char *)&pp->refid, REFID, 4);
156 peer->precision = PRECISION;
157 pp->clockdesc = DESCRIPTION;
158 up->leap_status = 0;
159 up->unit = (short) unit;
160 return (1);
161 }
162
163
164 /*
165 * hopfpci_shutdown - shut down the clock
166 */
167 static void
hopfpci_shutdown(int unit,struct peer * peer)168 hopfpci_shutdown(
169 int unit,
170 struct peer *peer
171 )
172 {
173
174 #ifndef SYS_WINNT
175 close(fd);
176 #else
177 CloseHopfDevice();
178 #endif
179 if (NULL != peer->procptr->unitptr)
180 free(peer->procptr->unitptr);
181 }
182
183
184 /*
185 * hopfpci_poll - called by the transmit procedure
186 */
187 static void
hopfpci_poll(int unit,struct peer * peer)188 hopfpci_poll(
189 int unit,
190 struct peer *peer
191 )
192 {
193 struct refclockproc *pp;
194 HOPFTIME m_time;
195
196 pp = peer->procptr;
197
198 #ifndef SYS_WINNT
199 if (ioctl(fd, HOPF_CLOCK_GET_UTC, &m_time) < 0)
200 msyslog(LOG_ERR, "HOPF_P(%d): HOPF_CLOCK_GET_UTC: %m",
201 unit);
202 #else
203 GetHopfSystemTime(&m_time);
204 #endif
205 pp->polls++;
206
207 pp->day = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay);
208 pp->hour = m_time.wHour;
209 pp->minute = m_time.wMinute;
210 pp->second = m_time.wSecond;
211 pp->nsec = m_time.wMilliseconds * 1000000;
212 if (m_time.wStatus & LEWAPWAR)
213 pp->leap = LEAP_ADDSECOND;
214 else
215 pp->leap = LEAP_NOWARNING;
216
217 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
218 "ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d",
219 m_time.wStatus, pp->hour, pp->minute, pp->second,
220 pp->nsec / 1000000, m_time.wDay, m_time.wMonth,
221 m_time.wYear);
222 pp->lencode = (u_short)strlen(pp->a_lastcode);
223
224 get_systime(&pp->lastrec);
225
226 /*
227 * If clock has no valid status then report error and exit
228 */
229 if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) { /* time ok? */
230 refclock_report(peer, CEVNT_BADTIME);
231 pp->leap = LEAP_NOTINSYNC;
232 return;
233 }
234
235 /*
236 * Test if time is running on internal quarz
237 * if CLK_FLAG1 is set, sychronize even if no radio operation
238 */
239
240 if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){
241 if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
242 refclock_report(peer, CEVNT_BADTIME);
243 pp->leap = LEAP_NOTINSYNC;
244 return;
245 }
246 }
247
248 if (!refclock_process(pp)) {
249 refclock_report(peer, CEVNT_BADTIME);
250 return;
251 }
252 pp->lastref = pp->lastrec;
253 refclock_receive(peer);
254 record_clock_stats(&peer->srcadr, pp->a_lastcode);
255 return;
256 }
257
258 #else
259 NONEMPTY_TRANSLATION_UNIT
260 #endif /* REFCLOCK */
261