xref: /freebsd/contrib/ntp/ntpd/refclock_dumbclock.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * refclock_dumbclock - clock driver for a unknown time distribution system
3c0b746e5SOllivier Robert  * that only provides hh:mm:ss (in local time, yet!).
4c0b746e5SOllivier Robert  */
5c0b746e5SOllivier Robert 
6c0b746e5SOllivier Robert /*
7c0b746e5SOllivier Robert  * Must interpolate back to local time.  Very annoying.
8c0b746e5SOllivier Robert  */
9c0b746e5SOllivier Robert #define GET_LOCALTIME
10c0b746e5SOllivier Robert 
11c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
12c0b746e5SOllivier Robert #include <config.h>
13c0b746e5SOllivier Robert #endif
14c0b746e5SOllivier Robert 
15c0b746e5SOllivier Robert #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK)
16c0b746e5SOllivier Robert 
17c0b746e5SOllivier Robert #include "ntpd.h"
18c0b746e5SOllivier Robert #include "ntp_io.h"
19c0b746e5SOllivier Robert #include "ntp_refclock.h"
20c0b746e5SOllivier Robert #include "ntp_calendar.h"
21c0b746e5SOllivier Robert #include "ntp_stdlib.h"
22c0b746e5SOllivier Robert 
23224ba2bdSOllivier Robert #include <stdio.h>
24224ba2bdSOllivier Robert #include <ctype.h>
25224ba2bdSOllivier Robert 
26c0b746e5SOllivier Robert /*
27c0b746e5SOllivier Robert  * This driver supports a generic dumb clock that only outputs hh:mm:ss,
28c0b746e5SOllivier Robert  * in local time, no less.
29c0b746e5SOllivier Robert  *
30c0b746e5SOllivier Robert  * Input format:
31c0b746e5SOllivier Robert  *
32c0b746e5SOllivier Robert  *	hh:mm:ss   <cr>
33c0b746e5SOllivier Robert  *
34c0b746e5SOllivier Robert  * hh:mm:ss -- what you'd expect, with a 24 hour clock.  (Heck, that's the only
35c0b746e5SOllivier Robert  * way it could get stupider.)  We take time on the <cr>.
36c0b746e5SOllivier Robert  *
37c0b746e5SOllivier Robert  * The original source of this module was the WWVB module.
38c0b746e5SOllivier Robert  */
39c0b746e5SOllivier Robert 
40c0b746e5SOllivier Robert /*
41c0b746e5SOllivier Robert  * Interface definitions
42c0b746e5SOllivier Robert  */
43c0b746e5SOllivier Robert #define	DEVICE		"/dev/dumbclock%d" /* device name and unit */
44c0b746e5SOllivier Robert #define	SPEED232	B9600	/* uart speed (9600 baud) */
45c0b746e5SOllivier Robert #define	PRECISION	(-13)	/* precision assumed (about 100 us) */
46c0b746e5SOllivier Robert #define	REFID		"dumbclock"	/* reference ID */
47c0b746e5SOllivier Robert #define	DESCRIPTION	"Dumb clock" /* WRU */
48c0b746e5SOllivier Robert 
49c0b746e5SOllivier Robert 
50c0b746e5SOllivier Robert /*
51c0b746e5SOllivier Robert  * Insanity check.  Since the time is local, we need to make sure that during midnight
52c0b746e5SOllivier Robert  * transitions, we can convert back to Unix time.  If the conversion results in some number
53c0b746e5SOllivier Robert  * worse than this number of seconds away, assume the next day and retry.
54c0b746e5SOllivier Robert  */
55c0b746e5SOllivier Robert #define INSANE_SECONDS 3600
56c0b746e5SOllivier Robert 
57c0b746e5SOllivier Robert /*
58c0b746e5SOllivier Robert  * Dumb clock control structure
59c0b746e5SOllivier Robert  */
60c0b746e5SOllivier Robert struct dumbclock_unit {
61c0b746e5SOllivier Robert 	u_char	  tcswitch;	/* timecode switch */
62c0b746e5SOllivier Robert 	l_fp	  laststamp;	/* last receive timestamp */
63c0b746e5SOllivier Robert 	u_char	  lasthour;	/* last hour (for monitor) */
64c0b746e5SOllivier Robert 	u_char	  linect;	/* count ignored lines (for monitor */
65c0b746e5SOllivier Robert 	struct tm ymd;		/* struct tm for y/m/d only */
66c0b746e5SOllivier Robert };
67c0b746e5SOllivier Robert 
68c0b746e5SOllivier Robert /*
69c0b746e5SOllivier Robert  * Function prototypes
70c0b746e5SOllivier Robert  */
712b15cb3dSCy Schubert static	int	dumbclock_start		(int, struct peer *);
722b15cb3dSCy Schubert static	void	dumbclock_shutdown	(int, struct peer *);
732b15cb3dSCy Schubert static	void	dumbclock_receive	(struct recvbuf *);
74c0b746e5SOllivier Robert #if 0
752b15cb3dSCy Schubert static	void	dumbclock_poll		(int, struct peer *);
76c0b746e5SOllivier Robert #endif
77c0b746e5SOllivier Robert 
78c0b746e5SOllivier Robert /*
79c0b746e5SOllivier Robert  * Transfer vector
80c0b746e5SOllivier Robert  */
81c0b746e5SOllivier Robert struct	refclock refclock_dumbclock = {
82c0b746e5SOllivier Robert 	dumbclock_start,		     /* start up driver */
83c0b746e5SOllivier Robert 	dumbclock_shutdown,		     /* shut down driver */
84c0b746e5SOllivier Robert 	noentry,			     /* poll the driver -- a nice fabrication */
85c0b746e5SOllivier Robert 	noentry,			     /* not used */
86c0b746e5SOllivier Robert 	noentry,			     /* not used */
87c0b746e5SOllivier Robert 	noentry,			     /* not used */
88c0b746e5SOllivier Robert 	NOFLAGS				     /* not used */
89c0b746e5SOllivier Robert };
90c0b746e5SOllivier Robert 
91c0b746e5SOllivier Robert 
92c0b746e5SOllivier Robert /*
93c0b746e5SOllivier Robert  * dumbclock_start - open the devices and initialize data for processing
94c0b746e5SOllivier Robert  */
95c0b746e5SOllivier Robert static int
96c0b746e5SOllivier Robert dumbclock_start(
97c0b746e5SOllivier Robert 	int unit,
98c0b746e5SOllivier Robert 	struct peer *peer
99c0b746e5SOllivier Robert 	)
100c0b746e5SOllivier Robert {
101c0b746e5SOllivier Robert 	register struct dumbclock_unit *up;
102c0b746e5SOllivier Robert 	struct refclockproc *pp;
103c0b746e5SOllivier Robert 	int fd;
104c0b746e5SOllivier Robert 	char device[20];
105c0b746e5SOllivier Robert 	struct tm *tm_time_p;
106c0b746e5SOllivier Robert 	time_t     now;
107c0b746e5SOllivier Robert 
108c0b746e5SOllivier Robert 	/*
109c0b746e5SOllivier Robert 	 * Open serial port. Don't bother with CLK line discipline, since
110c0b746e5SOllivier Robert 	 * it's not available.
111c0b746e5SOllivier Robert 	 */
1122b15cb3dSCy Schubert 	snprintf(device, sizeof(device), DEVICE, unit);
113c0b746e5SOllivier Robert #ifdef DEBUG
114c0b746e5SOllivier Robert 	if (debug)
115c0b746e5SOllivier Robert 		printf ("starting Dumbclock with device %s\n",device);
116c0b746e5SOllivier Robert #endif
117a466cc55SCy Schubert 	fd = refclock_open(&peer->srcadr, device, SPEED232, 0);
1182b15cb3dSCy Schubert 	if (fd <= 0)
119c0b746e5SOllivier Robert 		return (0);
120c0b746e5SOllivier Robert 
121c0b746e5SOllivier Robert 	/*
122c0b746e5SOllivier Robert 	 * Allocate and initialize unit structure
123c0b746e5SOllivier Robert 	 */
1242b15cb3dSCy Schubert 	up = emalloc_zero(sizeof(*up));
125c0b746e5SOllivier Robert 	pp = peer->procptr;
1262b15cb3dSCy Schubert 	pp->unitptr = up;
127c0b746e5SOllivier Robert 	pp->io.clock_recv = dumbclock_receive;
1282b15cb3dSCy Schubert 	pp->io.srcclock = peer;
129c0b746e5SOllivier Robert 	pp->io.datalen = 0;
130c0b746e5SOllivier Robert 	pp->io.fd = fd;
131c0b746e5SOllivier Robert 	if (!io_addclock(&pp->io)) {
1322b15cb3dSCy Schubert 		close(fd);
1332b15cb3dSCy Schubert 		pp->io.fd = -1;
134c0b746e5SOllivier Robert 		free(up);
1352b15cb3dSCy Schubert 		pp->unitptr = NULL;
136c0b746e5SOllivier Robert 		return (0);
137c0b746e5SOllivier Robert 	}
138c0b746e5SOllivier Robert 
139c0b746e5SOllivier Robert 
140c0b746e5SOllivier Robert 	time(&now);
141c0b746e5SOllivier Robert #ifdef GET_LOCALTIME
142c0b746e5SOllivier Robert 	tm_time_p = localtime(&now);
143c0b746e5SOllivier Robert #else
144c0b746e5SOllivier Robert 	tm_time_p = gmtime(&now);
145c0b746e5SOllivier Robert #endif
146c0b746e5SOllivier Robert 	if (tm_time_p)
147c0b746e5SOllivier Robert 		up->ymd = *tm_time_p;
148c0b746e5SOllivier Robert 	else
149c0b746e5SOllivier Robert 		return 0;
150c0b746e5SOllivier Robert 
151c0b746e5SOllivier Robert 	/*
152c0b746e5SOllivier Robert 	 * Initialize miscellaneous variables
153c0b746e5SOllivier Robert 	 */
154c0b746e5SOllivier Robert 	peer->precision = PRECISION;
155c0b746e5SOllivier Robert 	pp->clockdesc = DESCRIPTION;
156c0b746e5SOllivier Robert 	memcpy((char *)&pp->refid, REFID, 4);
157c0b746e5SOllivier Robert 	return (1);
158c0b746e5SOllivier Robert }
159c0b746e5SOllivier Robert 
160c0b746e5SOllivier Robert 
161c0b746e5SOllivier Robert /*
162c0b746e5SOllivier Robert  * dumbclock_shutdown - shut down the clock
163c0b746e5SOllivier Robert  */
164c0b746e5SOllivier Robert static void
165c0b746e5SOllivier Robert dumbclock_shutdown(
166c0b746e5SOllivier Robert 	int unit,
167c0b746e5SOllivier Robert 	struct peer *peer
168c0b746e5SOllivier Robert 	)
169c0b746e5SOllivier Robert {
170c0b746e5SOllivier Robert 	register struct dumbclock_unit *up;
171c0b746e5SOllivier Robert 	struct refclockproc *pp;
172c0b746e5SOllivier Robert 
173c0b746e5SOllivier Robert 	pp = peer->procptr;
1742b15cb3dSCy Schubert 	up = pp->unitptr;
1752b15cb3dSCy Schubert 	if (-1 != pp->io.fd)
176c0b746e5SOllivier Robert 		io_closeclock(&pp->io);
1772b15cb3dSCy Schubert 	if (NULL != up)
178c0b746e5SOllivier Robert 		free(up);
179c0b746e5SOllivier Robert }
180c0b746e5SOllivier Robert 
181c0b746e5SOllivier Robert 
182c0b746e5SOllivier Robert /*
183c0b746e5SOllivier Robert  * dumbclock_receive - receive data from the serial interface
184c0b746e5SOllivier Robert  */
185c0b746e5SOllivier Robert static void
186c0b746e5SOllivier Robert dumbclock_receive(
187c0b746e5SOllivier Robert 	struct recvbuf *rbufp
188c0b746e5SOllivier Robert 	)
189c0b746e5SOllivier Robert {
190c0b746e5SOllivier Robert 	struct dumbclock_unit *up;
191c0b746e5SOllivier Robert 	struct refclockproc *pp;
192c0b746e5SOllivier Robert 	struct peer *peer;
193c0b746e5SOllivier Robert 
194c0b746e5SOllivier Robert 	l_fp	trtmp;		/* arrival timestamp */
195c0b746e5SOllivier Robert 	int	hours;		/* hour-of-day */
196c0b746e5SOllivier Robert 	int	minutes;	/* minutes-past-the-hour */
197c0b746e5SOllivier Robert 	int	seconds;	/* seconds */
198c0b746e5SOllivier Robert 	int	temp;		/* int temp */
199c0b746e5SOllivier Robert 	int	got_good;	/* got a good time flag */
200c0b746e5SOllivier Robert 
201c0b746e5SOllivier Robert 	/*
202c0b746e5SOllivier Robert 	 * Initialize pointers and read the timecode and timestamp
203c0b746e5SOllivier Robert 	 */
2042b15cb3dSCy Schubert 	peer = rbufp->recv_peer;
205c0b746e5SOllivier Robert 	pp = peer->procptr;
2062b15cb3dSCy Schubert 	up = pp->unitptr;
207c0b746e5SOllivier Robert 	temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
208c0b746e5SOllivier Robert 
209c0b746e5SOllivier Robert 	if (temp == 0) {
210c0b746e5SOllivier Robert 		if (up->tcswitch == 0) {
211c0b746e5SOllivier Robert 			up->tcswitch = 1;
212c0b746e5SOllivier Robert 			up->laststamp = trtmp;
213c0b746e5SOllivier Robert 		} else
214c0b746e5SOllivier Robert 			up->tcswitch = 0;
215c0b746e5SOllivier Robert 		return;
216c0b746e5SOllivier Robert 	}
2179c2daa00SOllivier Robert 	pp->lencode = (u_short)temp;
218c0b746e5SOllivier Robert 	pp->lastrec = up->laststamp;
219c0b746e5SOllivier Robert 	up->laststamp = trtmp;
220c0b746e5SOllivier Robert 	up->tcswitch = 1;
221c0b746e5SOllivier Robert 
222c0b746e5SOllivier Robert #ifdef DEBUG
223c0b746e5SOllivier Robert 	if (debug)
224c0b746e5SOllivier Robert 		printf("dumbclock: timecode %d %s\n",
225c0b746e5SOllivier Robert 		       pp->lencode, pp->a_lastcode);
226c0b746e5SOllivier Robert #endif
227c0b746e5SOllivier Robert 
228c0b746e5SOllivier Robert 	/*
229c0b746e5SOllivier Robert 	 * We get down to business. Check the timecode format...
230c0b746e5SOllivier Robert 	 */
231c0b746e5SOllivier Robert 	got_good=0;
232c0b746e5SOllivier Robert 	if (sscanf(pp->a_lastcode,"%02d:%02d:%02d",
233c0b746e5SOllivier Robert 		   &hours,&minutes,&seconds) == 3)
234c0b746e5SOllivier Robert 	{
235c0b746e5SOllivier Robert 	    struct tm *gmtp;
236c0b746e5SOllivier Robert 	    struct tm *lt_p;
237c0b746e5SOllivier Robert 	    time_t     asserted_time;	     /* the SPM time based on the composite time+date */
238c0b746e5SOllivier Robert 	    struct tm  asserted_tm;	     /* the struct tm of the same */
239c0b746e5SOllivier Robert 	    int        adjyear;
240c0b746e5SOllivier Robert 	    int        adjmon;
2412b15cb3dSCy Schubert 	    time_t     reality_delta;
242c0b746e5SOllivier Robert 	    time_t     now;
243c0b746e5SOllivier Robert 
244c0b746e5SOllivier Robert 
245c0b746e5SOllivier Robert 	    /*
246c0b746e5SOllivier Robert 	     * Convert to GMT for sites that distribute localtime.  This
247c0b746e5SOllivier Robert 	     * means we have to figure out what day it is.  Easier said
248c0b746e5SOllivier Robert 	     * than done...
249c0b746e5SOllivier Robert 	     */
250c0b746e5SOllivier Robert 
2512b15cb3dSCy Schubert 	    memset(&asserted_tm, 0, sizeof(asserted_tm));
2522b15cb3dSCy Schubert 
253c0b746e5SOllivier Robert 	    asserted_tm.tm_year  = up->ymd.tm_year;
254c0b746e5SOllivier Robert 	    asserted_tm.tm_mon   = up->ymd.tm_mon;
255c0b746e5SOllivier Robert 	    asserted_tm.tm_mday  = up->ymd.tm_mday;
256c0b746e5SOllivier Robert 	    asserted_tm.tm_hour  = hours;
257c0b746e5SOllivier Robert 	    asserted_tm.tm_min   = minutes;
258c0b746e5SOllivier Robert 	    asserted_tm.tm_sec   = seconds;
259c0b746e5SOllivier Robert 	    asserted_tm.tm_isdst = -1;
260c0b746e5SOllivier Robert 
261c0b746e5SOllivier Robert #ifdef GET_LOCALTIME
262c0b746e5SOllivier Robert 	    asserted_time = mktime (&asserted_tm);
263c0b746e5SOllivier Robert 	    time(&now);
264c0b746e5SOllivier Robert #else
265c0b746e5SOllivier Robert #include "GMT unsupported for dumbclock!"
266c0b746e5SOllivier Robert #endif
267c0b746e5SOllivier Robert 	    reality_delta = asserted_time - now;
268c0b746e5SOllivier Robert 
269c0b746e5SOllivier Robert 	    /*
270c0b746e5SOllivier Robert 	     * We assume that if the time is grossly wrong, it's because we got the
271c0b746e5SOllivier Robert 	     * year/month/day wrong.
272c0b746e5SOllivier Robert 	     */
273c0b746e5SOllivier Robert 	    if (reality_delta > INSANE_SECONDS)
274c0b746e5SOllivier Robert 	    {
275c0b746e5SOllivier Robert 		asserted_time -= SECSPERDAY; /* local clock behind real time */
276c0b746e5SOllivier Robert 	    }
277c0b746e5SOllivier Robert 	    else if (-reality_delta > INSANE_SECONDS)
278c0b746e5SOllivier Robert 	    {
279c0b746e5SOllivier Robert 		asserted_time += SECSPERDAY; /* local clock ahead of real time */
280c0b746e5SOllivier Robert 	    }
281c0b746e5SOllivier Robert 	    lt_p = localtime(&asserted_time);
282c0b746e5SOllivier Robert 	    if (lt_p)
283c0b746e5SOllivier Robert 	    {
284c0b746e5SOllivier Robert 		up->ymd = *lt_p;
285c0b746e5SOllivier Robert 	    }
286c0b746e5SOllivier Robert 	    else
287c0b746e5SOllivier Robert 	    {
288c0b746e5SOllivier Robert 		refclock_report (peer, CEVNT_FAULT);
289c0b746e5SOllivier Robert 		return;
290c0b746e5SOllivier Robert 	    }
291c0b746e5SOllivier Robert 
292c0b746e5SOllivier Robert 	    if ((gmtp = gmtime (&asserted_time)) == NULL)
293c0b746e5SOllivier Robert 	    {
294c0b746e5SOllivier Robert 		refclock_report (peer, CEVNT_FAULT);
295c0b746e5SOllivier Robert 		return;
296c0b746e5SOllivier Robert 	    }
297c0b746e5SOllivier Robert 	    adjyear = gmtp->tm_year+1900;
298c0b746e5SOllivier Robert 	    adjmon  = gmtp->tm_mon+1;
299c0b746e5SOllivier Robert 	    pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
300c0b746e5SOllivier Robert 	    pp->hour   = gmtp->tm_hour;
301c0b746e5SOllivier Robert 	    pp->minute = gmtp->tm_min;
302c0b746e5SOllivier Robert 	    pp->second = gmtp->tm_sec;
303c0b746e5SOllivier Robert #ifdef DEBUG
304c0b746e5SOllivier Robert 	    if (debug)
305c0b746e5SOllivier Robert 		printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
306c0b746e5SOllivier Robert 			adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
307c0b746e5SOllivier Robert 			pp->second);
308c0b746e5SOllivier Robert #endif
309c0b746e5SOllivier Robert 
310c0b746e5SOllivier Robert 	    got_good=1;
311c0b746e5SOllivier Robert 	}
312c0b746e5SOllivier Robert 
313c0b746e5SOllivier Robert 	if (!got_good)
314c0b746e5SOllivier Robert 	{
315c0b746e5SOllivier Robert 	    if (up->linect > 0)
316c0b746e5SOllivier Robert 	    	up->linect--;
317c0b746e5SOllivier Robert 	    else
318c0b746e5SOllivier Robert 	    	refclock_report(peer, CEVNT_BADREPLY);
319c0b746e5SOllivier Robert 	    return;
320c0b746e5SOllivier Robert 	}
321c0b746e5SOllivier Robert 
322c0b746e5SOllivier Robert 	/*
323c0b746e5SOllivier Robert 	 * Process the new sample in the median filter and determine the
324c0b746e5SOllivier Robert 	 * timecode timestamp.
325c0b746e5SOllivier Robert 	 */
326c0b746e5SOllivier Robert 	if (!refclock_process(pp)) {
327c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_BADTIME);
328c0b746e5SOllivier Robert 		return;
329c0b746e5SOllivier Robert 	}
3309c2daa00SOllivier Robert 	pp->lastref = pp->lastrec;
331c0b746e5SOllivier Robert 	refclock_receive(peer);
3329c2daa00SOllivier Robert 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
3339c2daa00SOllivier Robert 	up->lasthour = (u_char)pp->hour;
334c0b746e5SOllivier Robert }
335c0b746e5SOllivier Robert 
336c0b746e5SOllivier Robert #if 0
337c0b746e5SOllivier Robert /*
338c0b746e5SOllivier Robert  * dumbclock_poll - called by the transmit procedure
339c0b746e5SOllivier Robert  */
340c0b746e5SOllivier Robert static void
341c0b746e5SOllivier Robert dumbclock_poll(
342c0b746e5SOllivier Robert 	int unit,
343c0b746e5SOllivier Robert 	struct peer *peer
344c0b746e5SOllivier Robert 	)
345c0b746e5SOllivier Robert {
346c0b746e5SOllivier Robert 	register struct dumbclock_unit *up;
347c0b746e5SOllivier Robert 	struct refclockproc *pp;
348c0b746e5SOllivier Robert 	char pollchar;
349c0b746e5SOllivier Robert 
350c0b746e5SOllivier Robert 	/*
351c0b746e5SOllivier Robert 	 * Time to poll the clock. The Chrono-log clock is supposed to
352c0b746e5SOllivier Robert 	 * respond to a 'T' by returning a timecode in the format(s)
353c0b746e5SOllivier Robert 	 * specified above.  Ours does (can?) not, but this seems to be
354c0b746e5SOllivier Robert 	 * an installation-specific problem.  This code is dyked out,
355c0b746e5SOllivier Robert 	 * but may be re-enabled if anyone ever finds a Chrono-log that
356c0b746e5SOllivier Robert 	 * actually listens to this command.
357c0b746e5SOllivier Robert 	 */
358c0b746e5SOllivier Robert #if 0
359c0b746e5SOllivier Robert 	pp = peer->procptr;
3602b15cb3dSCy Schubert 	up = pp->unitptr;
361c0b746e5SOllivier Robert 	if (peer->reach == 0)
362c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_TIMEOUT);
363c0b746e5SOllivier Robert 	if (up->linect > 0)
364c0b746e5SOllivier Robert 		pollchar = 'R';
365c0b746e5SOllivier Robert 	else
366c0b746e5SOllivier Robert 		pollchar = 'T';
367a466cc55SCy Schubert 	if (refclock_fdwrite(peer, pp->io.fd, &pollchar, 1) != 1)
368c0b746e5SOllivier Robert 		refclock_report(peer, CEVNT_FAULT);
369c0b746e5SOllivier Robert 	else
370c0b746e5SOllivier Robert 		pp->polls++;
371c0b746e5SOllivier Robert #endif
372c0b746e5SOllivier Robert }
373c0b746e5SOllivier Robert #endif
374c0b746e5SOllivier Robert 
375c0b746e5SOllivier Robert #else
376*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT
3772b15cb3dSCy Schubert #endif	/* defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) */
378