Annotation of embedaddon/ntp/parseutil/testdcf.c, revision 1.1.1.1
1.1 misho 1: /*
2: * /src/NTP/ntp4-dev/parseutil/testdcf.c,v 4.10 2005/08/06 14:18:43 kardel RELEASE_20050806_A
3: *
4: * testdcf.c,v 4.10 2005/08/06 14:18:43 kardel RELEASE_20050806_A
5: *
6: * simple DCF77 100/200ms pulse test program (via 50Baud serial line)
7: *
8: * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
9: * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. Neither the name of the author nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: *
35: */
36:
37: #include "ntp_stdlib.h"
38:
39: #include <sys/ioctl.h>
40: #include <unistd.h>
41: #include <stdio.h>
42: #include <fcntl.h>
43: #include <termios.h>
44:
45: /*
46: * state flags
47: */
48: #define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */
49: #define DCFB_DST 0x0002 /* DST in effect */
50: #define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurrence) */
51: #define DCFB_ALTERNATE 0x0008 /* alternate antenna used */
52:
53: struct clocktime /* clock time broken up from time code */
54: {
55: long wday;
56: long day;
57: long month;
58: long year;
59: long hour;
60: long minute;
61: long second;
62: long usecond;
63: long utcoffset; /* in minutes */
64: long flags; /* current clock status */
65: };
66:
67: typedef struct clocktime clocktime_t;
68:
69: static char type(unsigned int);
70:
71: #define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1))
72:
73: /*
74: * parser related return/error codes
75: */
76: #define CVT_MASK 0x0000000F /* conversion exit code */
77: #define CVT_NONE 0x00000001 /* format not applicable */
78: #define CVT_FAIL 0x00000002 /* conversion failed - error code returned */
79: #define CVT_OK 0x00000004 /* conversion succeeded */
80: #define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */
81:
82: /*
83: * DCF77 raw time code
84: *
85: * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
86: * und Berlin, Maerz 1989
87: *
88: * Timecode transmission:
89: * AM:
90: * time marks are send every second except for the second before the
91: * next minute mark
92: * time marks consist of a reduction of transmitter power to 25%
93: * of the nominal level
94: * the falling edge is the time indication (on time)
95: * time marks of a 100ms duration constitute a logical 0
96: * time marks of a 200ms duration constitute a logical 1
97: * FM:
98: * see the spec. (basically a (non-)inverted psuedo random phase shift)
99: *
100: * Encoding:
101: * Second Contents
102: * 0 - 10 AM: free, FM: 0
103: * 11 - 14 free
104: * 15 R - alternate antenna
105: * 16 A1 - expect zone change (1 hour before)
106: * 17 - 18 Z1,Z2 - time zone
107: * 0 0 illegal
108: * 0 1 MEZ (MET)
109: * 1 0 MESZ (MED, MET DST)
110: * 1 1 illegal
111: * 19 A2 - expect leap insertion/deletion (1 hour before)
112: * 20 S - start of time code (1)
113: * 21 - 24 M1 - BCD (lsb first) Minutes
114: * 25 - 27 M10 - BCD (lsb first) 10 Minutes
115: * 28 P1 - Minute Parity (even)
116: * 29 - 32 H1 - BCD (lsb first) Hours
117: * 33 - 34 H10 - BCD (lsb first) 10 Hours
118: * 35 P2 - Hour Parity (even)
119: * 36 - 39 D1 - BCD (lsb first) Days
120: * 40 - 41 D10 - BCD (lsb first) 10 Days
121: * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday)
122: * 45 - 49 MO - BCD (lsb first) Month
123: * 50 MO0 - 10 Months
124: * 51 - 53 Y1 - BCD (lsb first) Years
125: * 54 - 57 Y10 - BCD (lsb first) 10 Years
126: * 58 P3 - Date Parity (even)
127: * 59 - usually missing (minute indication), except for leap insertion
128: */
129:
130: static char revision[] = "4.10";
131:
132: static struct rawdcfcode
133: {
134: char offset; /* start bit */
135: } rawdcfcode[] =
136: {
137: { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 },
138: { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 }
139: };
140:
141: #define DCF_M 0
142: #define DCF_R 1
143: #define DCF_A1 2
144: #define DCF_Z 3
145: #define DCF_A2 4
146: #define DCF_S 5
147: #define DCF_M1 6
148: #define DCF_M10 7
149: #define DCF_P1 8
150: #define DCF_H1 9
151: #define DCF_H10 10
152: #define DCF_P2 11
153: #define DCF_D1 12
154: #define DCF_D10 13
155: #define DCF_DW 14
156: #define DCF_MO 15
157: #define DCF_MO0 16
158: #define DCF_Y1 17
159: #define DCF_Y10 18
160: #define DCF_P3 19
161:
162: static struct partab
163: {
164: char offset; /* start bit of parity field */
165: } partab[] =
166: {
167: { 21 }, { 29 }, { 36 }, { 59 }
168: };
169:
170: #define DCF_P_P1 0
171: #define DCF_P_P2 1
172: #define DCF_P_P3 2
173:
174: #define DCF_Z_MET 0x2
175: #define DCF_Z_MED 0x1
176:
177: static unsigned long
178: ext_bf(
179: register unsigned char *buf,
180: register int idx
181: )
182: {
183: register unsigned long sum = 0;
184: register int i, first;
185:
186: first = rawdcfcode[idx].offset;
187:
188: for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--)
189: {
190: sum <<= 1;
191: sum |= (buf[i] != '-');
192: }
193: return sum;
194: }
195:
196: static unsigned
197: pcheck(
198: register unsigned char *buf,
199: register int idx
200: )
201: {
202: register int i,last;
203: register unsigned psum = 1;
204:
205: last = partab[idx+1].offset;
206:
207: for (i = partab[idx].offset; i < last; i++)
208: psum ^= (buf[i] != '-');
209:
210: return psum;
211: }
212:
213: static unsigned long
214: convert_rawdcf(
215: register unsigned char *buffer,
216: register int size,
217: register clocktime_t *clock_time
218: )
219: {
220: if (size < 57)
221: {
222: printf("%-30s", "*** INCOMPLETE");
223: return CVT_NONE;
224: }
225:
226: /*
227: * check Start and Parity bits
228: */
229: if ((ext_bf(buffer, DCF_S) == 1) &&
230: pcheck(buffer, DCF_P_P1) &&
231: pcheck(buffer, DCF_P_P2) &&
232: pcheck(buffer, DCF_P_P3))
233: {
234: /*
235: * buffer OK
236: */
237:
238: clock_time->flags = 0;
239: clock_time->usecond= 0;
240: clock_time->second = 0;
241: clock_time->minute = ext_bf(buffer, DCF_M10);
242: clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1);
243: clock_time->hour = ext_bf(buffer, DCF_H10);
244: clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1);
245: clock_time->day = ext_bf(buffer, DCF_D10);
246: clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1);
247: clock_time->month = ext_bf(buffer, DCF_MO0);
248: clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO);
249: clock_time->year = ext_bf(buffer, DCF_Y10);
250: clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1);
251: clock_time->wday = ext_bf(buffer, DCF_DW);
252:
253: switch (ext_bf(buffer, DCF_Z))
254: {
255: case DCF_Z_MET:
256: clock_time->utcoffset = -60;
257: break;
258:
259: case DCF_Z_MED:
260: clock_time->flags |= DCFB_DST;
261: clock_time->utcoffset = -120;
262: break;
263:
264: default:
265: printf("%-30s", "*** BAD TIME ZONE");
266: return CVT_FAIL|CVT_BADFMT;
267: }
268:
269: if (ext_bf(buffer, DCF_A1))
270: clock_time->flags |= DCFB_ANNOUNCE;
271:
272: if (ext_bf(buffer, DCF_A2))
273: clock_time->flags |= DCFB_LEAP;
274:
275: if (ext_bf(buffer, DCF_R))
276: clock_time->flags |= DCFB_ALTERNATE;
277:
278: return CVT_OK;
279: }
280: else
281: {
282: /*
283: * bad format - not for us
284: */
285: printf("%-30s", "*** BAD FORMAT (invalid/parity)");
286: return CVT_FAIL|CVT_BADFMT;
287: }
288: }
289:
290: static char
291: type(
292: unsigned int c
293: )
294: {
295: c ^= 0xFF;
296: return (c >= 0xF);
297: }
298:
299: static const char *wday[8] =
300: {
301: "??",
302: "Mo",
303: "Tu",
304: "We",
305: "Th",
306: "Fr",
307: "Sa",
308: "Su"
309: };
310:
311: static char pat[] = "-\\|/";
312:
313: #define LINES (24-2) /* error lines after which the two headlines are repeated */
314:
315: int
316: main(
317: int argc,
318: char *argv[]
319: )
320: {
321: if ((argc != 2) && (argc != 3))
322: {
323: fprintf(stderr, "usage: %s [-f|-t|-ft|-tf] <device>\n", argv[0]);
324: exit(1);
325: }
326: else
327: {
328: unsigned char c;
329: char *file;
330: int fd;
331: int offset = 15;
332: int trace = 0;
333: int errs = LINES+1;
334:
335: /*
336: * SIMPLE(!) argument "parser"
337: */
338: if (argc == 3)
339: {
340: if (strcmp(argv[1], "-f") == 0)
341: offset = 0;
342: if (strcmp(argv[1], "-t") == 0)
343: trace = 1;
344: if ((strcmp(argv[1], "-ft") == 0) ||
345: (strcmp(argv[1], "-tf") == 0))
346: {
347: offset = 0;
348: trace = 1;
349: }
350: file = argv[2];
351: }
352: else
353: {
354: file = argv[1];
355: }
356:
357: fd = open(file, O_RDONLY);
358: if (fd == -1)
359: {
360: perror(file);
361: exit(1);
362: }
363: else
364: {
365: int i;
366: #ifdef TIOCM_RTS
367: int on = TIOCM_RTS;
368: #endif
369: struct timeval t, tt, tlast;
370: char buf[61];
371: clocktime_t clock_time;
372: struct termios term;
373: int rtc = CVT_NONE;
374:
375: if (tcgetattr(fd, &term) == -1)
376: {
377: perror("tcgetattr");
378: exit(1);
379: }
380:
381: memset(term.c_cc, 0, sizeof(term.c_cc));
382: term.c_cc[VMIN] = 1;
383: #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined (SYS_IRIX5) */
384: /* somehow doesn't grok PARENB & IGNPAR (mj) */
385: term.c_cflag = CS8|CREAD|CLOCAL;
386: #else
387: term.c_cflag = CS8|CREAD|CLOCAL|PARENB;
388: #endif
389: term.c_iflag = IGNPAR;
390: term.c_oflag = 0;
391: term.c_lflag = 0;
392:
393: cfsetispeed(&term, B50);
394: cfsetospeed(&term, B50);
395:
396: if (tcsetattr(fd, TCSANOW, &term) == -1)
397: {
398: perror("tcsetattr");
399: exit(1);
400: }
401:
402: #ifdef I_POP
403: while (ioctl(fd, I_POP, 0) == 0)
404: ;
405: #endif
406: #if defined(TIOCMBIC) && defined(TIOCM_RTS)
407: if (ioctl(fd, TIOCMBIC, (caddr_t)&on) == -1)
408: {
409: perror("TIOCM_RTS");
410: }
411: #endif
412:
413: printf(" DCF77 monitor %s - Copyright (C) 1993-2005, Frank Kardel\n\n", revision);
414:
415: clock_time.hour = 0;
416: clock_time.minute = 0;
417: clock_time.day = 0;
418: clock_time.wday = 0;
419: clock_time.month = 0;
420: clock_time.year = 0;
421: clock_time.flags = 0;
422: buf[60] = '\0';
423: for ( i = 0; i < 60; i++)
424: buf[i] = '.';
425:
426: gettimeofday(&tlast, 0L);
427: i = 0;
428: while (read(fd, &c, 1) == 1)
429: {
430: gettimeofday(&t, 0L);
431: tt = t;
432: t.tv_sec -= tlast.tv_sec;
433: t.tv_usec -= tlast.tv_usec;
434: if (t.tv_usec < 0)
435: {
436: t.tv_usec += 1000000;
437: t.tv_sec -= 1;
438: }
439:
440: if (errs > LINES)
441: {
442: printf(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]);
443: printf(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]);
444: errs = 0;
445: }
446:
447: if (t.tv_sec > 1 ||
448: (t.tv_sec == 1 &&
449: t.tv_usec > 500000))
450: {
451: printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]);
452:
453: if ((rtc = convert_rawdcf((unsigned char *)buf, i, &clock_time)) != CVT_OK)
454: {
455: printf("\n");
456: clock_time.hour = 0;
457: clock_time.minute = 0;
458: clock_time.day = 0;
459: clock_time.wday = 0;
460: clock_time.month = 0;
461: clock_time.year = 0;
462: clock_time.flags = 0;
463: errs++;
464: }
465:
466: if (((c^0xFF)+1) & (c^0xFF))
467: buf[0] = '?';
468: else
469: buf[0] = type(c) ? '#' : '-';
470:
471: for ( i = 1; i < 60; i++)
472: buf[i] = '.';
473:
474: i = 0;
475: }
476: else
477: {
478: if (((c^0xFF)+1) & (c^0xFF))
479: buf[i] = '?';
480: else
481: buf[i] = type(c) ? '#' : '-';
482:
483: printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]);
484: }
485:
486: if (rtc == CVT_OK)
487: {
488: printf("%s, %2d:%02d:%02d, %d.%02d.%02d, <%s%s%s%s>",
489: wday[clock_time.wday],
490: (int)clock_time.hour, (int)clock_time.minute, (int)i, (int)clock_time.day, (int)clock_time.month,
491: (int)clock_time.year,
492: (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_",
493: (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_",
494: (clock_time.flags & DCFB_DST) ? "D" : "_",
495: (clock_time.flags & DCFB_LEAP) ? "L" : "_"
496: );
497: if (trace && (i == 0))
498: {
499: printf("\n");
500: errs++;
501: }
502: }
503:
504: printf("\r");
505:
506: if (i < 60)
507: {
508: i++;
509: }
510:
511: tlast = tt;
512:
513: fflush(stdout);
514: }
515: close(fd);
516: }
517: }
518: return 0;
519: }
520:
521: /*
522: * History:
523: *
524: * testdcf.c,v
525: * Revision 4.10 2005/08/06 14:18:43 kardel
526: * cleanup warnings
527: *
528: * Revision 4.9 2005/08/06 14:14:38 kardel
529: * document revision on startup
530: *
531: * Revision 4.8 2005/08/06 14:10:08 kardel
532: * fix setting of baud rate
533: *
534: * Revision 4.7 2005/04/16 17:32:10 kardel
535: * update copyright
536: *
537: * Revision 4.6 2004/11/14 15:29:42 kardel
538: * support PPSAPI, upgrade Copyright to Berkeley style
539: *
540: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>