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