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