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