Annotation of embedaddon/ntp/ntpd/refclock_chronolog.c, revision 1.1.1.1
1.1 misho 1: /*
2: * refclock_chronolog - clock driver for Chronolog K-series WWVB receiver.
3: */
4:
5: /*
6: * Must interpolate back to local time. Very annoying.
7: */
8: #define GET_LOCALTIME
9:
10: #ifdef HAVE_CONFIG_H
11: #include <config.h>
12: #endif
13:
14: #if defined(REFCLOCK) && defined(CLOCK_CHRONOLOG)
15:
16: #include "ntpd.h"
17: #include "ntp_io.h"
18: #include "ntp_refclock.h"
19: #include "ntp_calendar.h"
20: #include "ntp_stdlib.h"
21:
22: #include <stdio.h>
23: #include <ctype.h>
24:
25: /*
26: * This driver supports the Chronolog K-series WWVB receiver.
27: *
28: * Input format:
29: *
30: * Y YY/MM/DD<cr><lf>
31: * Z hh:mm:ss<cr><lf>
32: *
33: * YY/MM/DD -- what you'd expect. This arrives a few seconds before the
34: * timestamp.
35: * hh:mm:ss -- what you'd expect. We take time on the <cr>.
36: *
37: * Our Chronolog writes time out at 2400 bps 8/N/1, but it can be configured
38: * otherwise. The clock seems to appear every 60 seconds, which doesn't make
39: * for good statistics collection.
40: *
41: * The original source of this module was the WWVB module.
42: */
43:
44: /*
45: * Interface definitions
46: */
47: #define DEVICE "/dev/chronolog%d" /* device name and unit */
48: #define SPEED232 B2400 /* uart speed (2400 baud) */
49: #define PRECISION (-13) /* precision assumed (about 100 us) */
50: #define REFID "chronolog" /* reference ID */
51: #define DESCRIPTION "Chrono-log K" /* WRU */
52:
53: #define MONLIN 15 /* number of monitoring lines */
54:
55: /*
56: * Chrono-log unit control structure
57: */
58: struct chronolog_unit {
59: u_char tcswitch; /* timecode switch */
60: l_fp laststamp; /* last receive timestamp */
61: u_char lasthour; /* last hour (for monitor) */
62: int year; /* Y2K-adjusted year */
63: int day; /* day-of-month */
64: int month; /* month-of-year */
65: };
66:
67: /*
68: * Function prototypes
69: */
70: static int chronolog_start (int, struct peer *);
71: static void chronolog_shutdown (int, struct peer *);
72: static void chronolog_receive (struct recvbuf *);
73: static void chronolog_poll (int, struct peer *);
74:
75: /*
76: * Transfer vector
77: */
78: struct refclock refclock_chronolog = {
79: chronolog_start, /* start up driver */
80: chronolog_shutdown, /* shut down driver */
81: chronolog_poll, /* poll the driver -- a nice fabrication */
82: noentry, /* not used */
83: noentry, /* not used */
84: noentry, /* not used */
85: NOFLAGS /* not used */
86: };
87:
88:
89: /*
90: * chronolog_start - open the devices and initialize data for processing
91: */
92: static int
93: chronolog_start(
94: int unit,
95: struct peer *peer
96: )
97: {
98: register struct chronolog_unit *up;
99: struct refclockproc *pp;
100: int fd;
101: char device[20];
102:
103: /*
104: * Open serial port. Don't bother with CLK line discipline, since
105: * it's not available.
106: */
107: snprintf(device, sizeof(device), DEVICE, unit);
108: #ifdef DEBUG
109: if (debug)
110: printf ("starting Chronolog with device %s\n",device);
111: #endif
112: if (!(fd = refclock_open(device, SPEED232, 0)))
113: return (0);
114:
115: /*
116: * Allocate and initialize unit structure
117: */
118: up = emalloc(sizeof(*up));
119: memset(up, 0, sizeof(*up));
120: pp = peer->procptr;
121: pp->unitptr = (caddr_t)up;
122: pp->io.clock_recv = chronolog_receive;
123: pp->io.srcclock = (caddr_t)peer;
124: pp->io.datalen = 0;
125: pp->io.fd = fd;
126: if (!io_addclock(&pp->io)) {
127: close(fd);
128: pp->io.fd = -1;
129: free(up);
130: pp->unitptr = NULL;
131: return (0);
132: }
133:
134: /*
135: * Initialize miscellaneous variables
136: */
137: peer->precision = PRECISION;
138: pp->clockdesc = DESCRIPTION;
139: memcpy((char *)&pp->refid, REFID, 4);
140: return (1);
141: }
142:
143:
144: /*
145: * chronolog_shutdown - shut down the clock
146: */
147: static void
148: chronolog_shutdown(
149: int unit,
150: struct peer *peer
151: )
152: {
153: register struct chronolog_unit *up;
154: struct refclockproc *pp;
155:
156: pp = peer->procptr;
157: up = (struct chronolog_unit *)pp->unitptr;
158: if (-1 != pp->io.fd)
159: io_closeclock(&pp->io);
160: if (NULL != up)
161: free(up);
162: }
163:
164:
165: /*
166: * chronolog_receive - receive data from the serial interface
167: */
168: static void
169: chronolog_receive(
170: struct recvbuf *rbufp
171: )
172: {
173: struct chronolog_unit *up;
174: struct refclockproc *pp;
175: struct peer *peer;
176:
177: l_fp trtmp; /* arrival timestamp */
178: int hours; /* hour-of-day */
179: int minutes; /* minutes-past-the-hour */
180: int seconds; /* seconds */
181: int temp; /* int temp */
182: int got_good; /* got a good time flag */
183:
184: /*
185: * Initialize pointers and read the timecode and timestamp
186: */
187: peer = (struct peer *)rbufp->recv_srcclock;
188: pp = peer->procptr;
189: up = (struct chronolog_unit *)pp->unitptr;
190: temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
191:
192: if (temp == 0) {
193: if (up->tcswitch == 0) {
194: up->tcswitch = 1;
195: up->laststamp = trtmp;
196: } else
197: up->tcswitch = 0;
198: return;
199: }
200: pp->lencode = temp;
201: pp->lastrec = up->laststamp;
202: up->laststamp = trtmp;
203: up->tcswitch = 1;
204:
205: #ifdef DEBUG
206: if (debug)
207: printf("chronolog: timecode %d %s\n", pp->lencode,
208: pp->a_lastcode);
209: #endif
210:
211: /*
212: * We get down to business. Check the timecode format and decode
213: * its contents. This code uses the first character to see whether
214: * we're looking at a date or a time. We store data data across
215: * calls since it is transmitted a few seconds ahead of the
216: * timestamp.
217: */
218: got_good=0;
219: if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day))
220: {
221: /*
222: * Y2K convert the 2-digit year
223: */
224: up->year = up->year >= 69 ? up->year : up->year + 100;
225: return;
226: }
227: if (sscanf(pp->a_lastcode,"Z %02d:%02d:%02d",
228: &hours,&minutes,&seconds) == 3)
229: {
230: #ifdef GET_LOCALTIME
231: struct tm local;
232: struct tm *gmtp;
233: time_t unixtime;
234: int adjyear;
235: int adjmon;
236:
237: /*
238: * Convert to GMT for sites that distribute localtime. This
239: * means we have to do Y2K conversion on the 2-digit year;
240: * otherwise, we get the time wrong.
241: */
242:
243: memset(&local, 0, sizeof(local));
244:
245: local.tm_year = up->year;
246: local.tm_mon = up->month-1;
247: local.tm_mday = up->day;
248: local.tm_hour = hours;
249: local.tm_min = minutes;
250: local.tm_sec = seconds;
251: local.tm_isdst = -1;
252:
253: unixtime = mktime (&local);
254: if ((gmtp = gmtime (&unixtime)) == NULL)
255: {
256: refclock_report (peer, CEVNT_FAULT);
257: return;
258: }
259: adjyear = gmtp->tm_year+1900;
260: adjmon = gmtp->tm_mon+1;
261: pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
262: pp->hour = gmtp->tm_hour;
263: pp->minute = gmtp->tm_min;
264: pp->second = gmtp->tm_sec;
265: #ifdef DEBUG
266: if (debug)
267: printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
268: adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
269: pp->second);
270: #endif
271:
272: #else
273: /*
274: * For more rational sites distributing UTC
275: */
276: pp->day = ymd2yd(year+1900,month,day);
277: pp->hour = hours;
278: pp->minute = minutes;
279: pp->second = seconds;
280:
281: #endif
282: got_good=1;
283: }
284:
285: if (!got_good)
286: return;
287:
288:
289: /*
290: * Process the new sample in the median filter and determine the
291: * timecode timestamp.
292: */
293: if (!refclock_process(pp)) {
294: refclock_report(peer, CEVNT_BADTIME);
295: return;
296: }
297: pp->lastref = pp->lastrec;
298: refclock_receive(peer);
299: record_clock_stats(&peer->srcadr, pp->a_lastcode);
300: up->lasthour = pp->hour;
301: }
302:
303:
304: /*
305: * chronolog_poll - called by the transmit procedure
306: */
307: static void
308: chronolog_poll(
309: int unit,
310: struct peer *peer
311: )
312: {
313: /*
314: * Time to poll the clock. The Chrono-log clock is supposed to
315: * respond to a 'T' by returning a timecode in the format(s)
316: * specified above. Ours does (can?) not, but this seems to be
317: * an installation-specific problem. This code is dyked out,
318: * but may be re-enabled if anyone ever finds a Chrono-log that
319: * actually listens to this command.
320: */
321: #if 0
322: register struct chronolog_unit *up;
323: struct refclockproc *pp;
324: char pollchar;
325:
326: pp = peer->procptr;
327: up = (struct chronolog_unit *)pp->unitptr;
328: if (peer->burst == 0 && peer->reach == 0)
329: refclock_report(peer, CEVNT_TIMEOUT);
330: if (up->linect > 0)
331: pollchar = 'R';
332: else
333: pollchar = 'T';
334: if (write(pp->io.fd, &pollchar, 1) != 1)
335: refclock_report(peer, CEVNT_FAULT);
336: else
337: pp->polls++;
338: #endif
339: }
340:
341: #else
342: int refclock_chronolog_bs;
343: #endif /* REFCLOCK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>