turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / ntp / ntpd / refclock_dumbclock.c
blob2788649ac3a7872e242e3f2eb415adf0a7ac8233
1 /*
2 * refclock_dumbclock - clock driver for a unknown time distribution system
3 * that only provides hh:mm:ss (in local time, yet!).
4 */
6 /*
7 * Must interpolate back to local time. Very annoying.
8 */
9 #define GET_LOCALTIME
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
15 #if defined(SYS_WINNT)
16 #undef close
17 #define close closesocket
18 #endif
20 #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK)
22 #include "ntpd.h"
23 #include "ntp_io.h"
24 #include "ntp_refclock.h"
25 #include "ntp_calendar.h"
26 #include "ntp_stdlib.h"
28 #include <stdio.h>
29 #include <ctype.h>
32 * This driver supports a generic dumb clock that only outputs hh:mm:ss,
33 * in local time, no less.
35 * Input format:
37 * hh:mm:ss <cr>
39 * hh:mm:ss -- what you'd expect, with a 24 hour clock. (Heck, that's the only
40 * way it could get stupider.) We take time on the <cr>.
42 * The original source of this module was the WWVB module.
46 * Interface definitions
48 #define DEVICE "/dev/dumbclock%d" /* device name and unit */
49 #define SPEED232 B9600 /* uart speed (9600 baud) */
50 #define PRECISION (-13) /* precision assumed (about 100 us) */
51 #define REFID "dumbclock" /* reference ID */
52 #define DESCRIPTION "Dumb clock" /* WRU */
56 * Insanity check. Since the time is local, we need to make sure that during midnight
57 * transitions, we can convert back to Unix time. If the conversion results in some number
58 * worse than this number of seconds away, assume the next day and retry.
60 #define INSANE_SECONDS 3600
63 * Dumb clock control structure
65 struct dumbclock_unit {
66 u_char tcswitch; /* timecode switch */
67 l_fp laststamp; /* last receive timestamp */
68 u_char lasthour; /* last hour (for monitor) */
69 u_char linect; /* count ignored lines (for monitor */
70 struct tm ymd; /* struct tm for y/m/d only */
74 * Function prototypes
76 static int dumbclock_start P((int, struct peer *));
77 static void dumbclock_shutdown P((int, struct peer *));
78 static void dumbclock_receive P((struct recvbuf *));
79 #if 0
80 static void dumbclock_poll P((int, struct peer *));
81 #endif
84 * Transfer vector
86 struct refclock refclock_dumbclock = {
87 dumbclock_start, /* start up driver */
88 dumbclock_shutdown, /* shut down driver */
89 noentry, /* poll the driver -- a nice fabrication */
90 noentry, /* not used */
91 noentry, /* not used */
92 noentry, /* not used */
93 NOFLAGS /* not used */
98 * dumbclock_start - open the devices and initialize data for processing
100 static int
101 dumbclock_start(
102 int unit,
103 struct peer *peer
106 register struct dumbclock_unit *up;
107 struct refclockproc *pp;
108 int fd;
109 char device[20];
110 struct tm *tm_time_p;
111 time_t now;
114 * Open serial port. Don't bother with CLK line discipline, since
115 * it's not available.
117 (void)sprintf(device, DEVICE, unit);
118 #ifdef DEBUG
119 if (debug)
120 printf ("starting Dumbclock with device %s\n",device);
121 #endif
122 fd = refclock_open(device, SPEED232, 0);
123 if (fd < 0)
124 return (0);
127 * Allocate and initialize unit structure
129 up = (struct dumbclock_unit *)emalloc(sizeof(struct dumbclock_unit));
130 if (up == NULL) {
131 (void) close(fd);
132 return (0);
134 memset((char *)up, 0, sizeof(struct dumbclock_unit));
135 pp = peer->procptr;
136 pp->unitptr = (caddr_t)up;
137 pp->io.clock_recv = dumbclock_receive;
138 pp->io.srcclock = (caddr_t)peer;
139 pp->io.datalen = 0;
140 pp->io.fd = fd;
141 if (!io_addclock(&pp->io)) {
142 (void) close(fd);
143 free(up);
144 return (0);
148 time(&now);
149 #ifdef GET_LOCALTIME
150 tm_time_p = localtime(&now);
151 #else
152 tm_time_p = gmtime(&now);
153 #endif
154 if (tm_time_p)
156 up->ymd = *tm_time_p;
158 else
160 return 0;
164 * Initialize miscellaneous variables
166 peer->precision = PRECISION;
167 pp->clockdesc = DESCRIPTION;
168 memcpy((char *)&pp->refid, REFID, 4);
169 return (1);
174 * dumbclock_shutdown - shut down the clock
176 static void
177 dumbclock_shutdown(
178 int unit,
179 struct peer *peer
182 register struct dumbclock_unit *up;
183 struct refclockproc *pp;
185 pp = peer->procptr;
186 up = (struct dumbclock_unit *)pp->unitptr;
187 io_closeclock(&pp->io);
188 free(up);
193 * dumbclock_receive - receive data from the serial interface
195 static void
196 dumbclock_receive(
197 struct recvbuf *rbufp
200 struct dumbclock_unit *up;
201 struct refclockproc *pp;
202 struct peer *peer;
204 l_fp trtmp; /* arrival timestamp */
205 int hours; /* hour-of-day */
206 int minutes; /* minutes-past-the-hour */
207 int seconds; /* seconds */
208 int temp; /* int temp */
209 int got_good; /* got a good time flag */
212 * Initialize pointers and read the timecode and timestamp
214 peer = (struct peer *)rbufp->recv_srcclock;
215 pp = peer->procptr;
216 up = (struct dumbclock_unit *)pp->unitptr;
217 temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
219 if (temp == 0) {
220 if (up->tcswitch == 0) {
221 up->tcswitch = 1;
222 up->laststamp = trtmp;
223 } else
224 up->tcswitch = 0;
225 return;
227 pp->lencode = (u_short)temp;
228 pp->lastrec = up->laststamp;
229 up->laststamp = trtmp;
230 up->tcswitch = 1;
232 #ifdef DEBUG
233 if (debug)
234 printf("dumbclock: timecode %d %s\n",
235 pp->lencode, pp->a_lastcode);
236 #endif
239 * We get down to business. Check the timecode format...
241 got_good=0;
242 if (sscanf(pp->a_lastcode,"%02d:%02d:%02d",
243 &hours,&minutes,&seconds) == 3)
245 struct tm *gmtp;
246 struct tm *lt_p;
247 time_t asserted_time; /* the SPM time based on the composite time+date */
248 struct tm asserted_tm; /* the struct tm of the same */
249 int adjyear;
250 int adjmon;
251 int reality_delta;
252 time_t now;
256 * Convert to GMT for sites that distribute localtime. This
257 * means we have to figure out what day it is. Easier said
258 * than done...
261 asserted_tm.tm_year = up->ymd.tm_year;
262 asserted_tm.tm_mon = up->ymd.tm_mon;
263 asserted_tm.tm_mday = up->ymd.tm_mday;
264 asserted_tm.tm_hour = hours;
265 asserted_tm.tm_min = minutes;
266 asserted_tm.tm_sec = seconds;
267 asserted_tm.tm_isdst = -1;
269 #ifdef GET_LOCALTIME
270 asserted_time = mktime (&asserted_tm);
271 time(&now);
272 #else
273 #include "GMT unsupported for dumbclock!"
274 #endif
275 reality_delta = asserted_time - now;
278 * We assume that if the time is grossly wrong, it's because we got the
279 * year/month/day wrong.
281 if (reality_delta > INSANE_SECONDS)
283 asserted_time -= SECSPERDAY; /* local clock behind real time */
285 else if (-reality_delta > INSANE_SECONDS)
287 asserted_time += SECSPERDAY; /* local clock ahead of real time */
289 lt_p = localtime(&asserted_time);
290 if (lt_p)
292 up->ymd = *lt_p;
294 else
296 refclock_report (peer, CEVNT_FAULT);
297 return;
300 if ((gmtp = gmtime (&asserted_time)) == NULL)
302 refclock_report (peer, CEVNT_FAULT);
303 return;
305 adjyear = gmtp->tm_year+1900;
306 adjmon = gmtp->tm_mon+1;
307 pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
308 pp->hour = gmtp->tm_hour;
309 pp->minute = gmtp->tm_min;
310 pp->second = gmtp->tm_sec;
311 #ifdef DEBUG
312 if (debug)
313 printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
314 adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
315 pp->second);
316 #endif
318 got_good=1;
321 if (!got_good)
323 if (up->linect > 0)
324 up->linect--;
325 else
326 refclock_report(peer, CEVNT_BADREPLY);
327 return;
331 * Process the new sample in the median filter and determine the
332 * timecode timestamp.
334 if (!refclock_process(pp)) {
335 refclock_report(peer, CEVNT_BADTIME);
336 return;
338 pp->lastref = pp->lastrec;
339 refclock_receive(peer);
340 record_clock_stats(&peer->srcadr, pp->a_lastcode);
341 up->lasthour = (u_char)pp->hour;
344 #if 0
346 * dumbclock_poll - called by the transmit procedure
348 static void
349 dumbclock_poll(
350 int unit,
351 struct peer *peer
354 register struct dumbclock_unit *up;
355 struct refclockproc *pp;
356 char pollchar;
359 * Time to poll the clock. The Chrono-log clock is supposed to
360 * respond to a 'T' by returning a timecode in the format(s)
361 * specified above. Ours does (can?) not, but this seems to be
362 * an installation-specific problem. This code is dyked out,
363 * but may be re-enabled if anyone ever finds a Chrono-log that
364 * actually listens to this command.
366 #if 0
367 pp = peer->procptr;
368 up = (struct dumbclock_unit *)pp->unitptr;
369 if (peer->reach == 0)
370 refclock_report(peer, CEVNT_TIMEOUT);
371 if (up->linect > 0)
372 pollchar = 'R';
373 else
374 pollchar = 'T';
375 if (write(pp->io.fd, &pollchar, 1) != 1)
376 refclock_report(peer, CEVNT_FAULT);
377 else
378 pp->polls++;
379 #endif
381 #endif
383 #else
384 int refclock_dumbclock_bs;
385 #endif /* REFCLOCK */