Annotation of embedaddon/ntp/libparse/clk_rawdcf.c, revision 1.1
1.1 ! misho 1: /*
! 2: * /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_rawdcf.c,v 4.18 2006/06/22 18:40:01 kardel RELEASE_20060622_A
! 3: *
! 4: * clk_rawdcf.c,v 4.18 2006/06/22 18:40:01 kardel RELEASE_20060622_A
! 5: *
! 6: * Raw DCF77 pulse clock support
! 7: *
! 8: * Copyright (c) 1995-2006 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: #ifdef HAVE_CONFIG_H
! 38: # include <config.h>
! 39: #endif
! 40:
! 41: #if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_RAWDCF)
! 42:
! 43: #include "ntp_fp.h"
! 44: #include "ntp_unixtime.h"
! 45: #include "ntp_calendar.h"
! 46:
! 47: #include "parse.h"
! 48: #ifdef PARSESTREAM
! 49: # include <sys/parsestreams.h>
! 50: #endif
! 51:
! 52: #ifndef PARSEKERNEL
! 53: # include "ntp_stdlib.h"
! 54: #endif
! 55:
! 56: /*
! 57: * DCF77 raw time code
! 58: *
! 59: * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
! 60: * und Berlin, Maerz 1989
! 61: *
! 62: * Timecode transmission:
! 63: * AM:
! 64: * time marks are send every second except for the second before the
! 65: * next minute mark
! 66: * time marks consist of a reduction of transmitter power to 25%
! 67: * of the nominal level
! 68: * the falling edge is the time indication (on time)
! 69: * time marks of a 100ms duration constitute a logical 0
! 70: * time marks of a 200ms duration constitute a logical 1
! 71: * FM:
! 72: * see the spec. (basically a (non-)inverted psuedo random phase shift)
! 73: *
! 74: * Encoding:
! 75: * Second Contents
! 76: * 0 - 10 AM: free, FM: 0
! 77: * 11 - 14 free
! 78: * 15 R - alternate antenna
! 79: * 16 A1 - expect zone change (1 hour before)
! 80: * 17 - 18 Z1,Z2 - time zone
! 81: * 0 0 illegal
! 82: * 0 1 MEZ (MET)
! 83: * 1 0 MESZ (MED, MET DST)
! 84: * 1 1 illegal
! 85: * 19 A2 - expect leap insertion/deletion (1 hour before)
! 86: * 20 S - start of time code (1)
! 87: * 21 - 24 M1 - BCD (lsb first) Minutes
! 88: * 25 - 27 M10 - BCD (lsb first) 10 Minutes
! 89: * 28 P1 - Minute Parity (even)
! 90: * 29 - 32 H1 - BCD (lsb first) Hours
! 91: * 33 - 34 H10 - BCD (lsb first) 10 Hours
! 92: * 35 P2 - Hour Parity (even)
! 93: * 36 - 39 D1 - BCD (lsb first) Days
! 94: * 40 - 41 D10 - BCD (lsb first) 10 Days
! 95: * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday)
! 96: * 45 - 49 MO - BCD (lsb first) Month
! 97: * 50 MO0 - 10 Months
! 98: * 51 - 53 Y1 - BCD (lsb first) Years
! 99: * 54 - 57 Y10 - BCD (lsb first) 10 Years
! 100: * 58 P3 - Date Parity (even)
! 101: * 59 - usually missing (minute indication), except for leap insertion
! 102: */
! 103:
! 104: static u_long pps_rawdcf (parse_t *, int, timestamp_t *);
! 105: static u_long cvt_rawdcf (unsigned char *, int, struct format *, clocktime_t *, void *);
! 106: static u_long inp_rawdcf (parse_t *, unsigned int, timestamp_t *);
! 107:
! 108: typedef struct last_tcode {
! 109: time_t tcode; /* last converted time code */
! 110: } last_tcode_t;
! 111:
! 112: #define BUFFER_MAX 61
! 113:
! 114: clockformat_t clock_rawdcf =
! 115: {
! 116: inp_rawdcf, /* DCF77 input handling */
! 117: cvt_rawdcf, /* raw dcf input conversion */
! 118: pps_rawdcf, /* examining PPS information */
! 119: 0, /* no private configuration data */
! 120: "RAW DCF77 Timecode", /* direct decoding / time synthesis */
! 121:
! 122: BUFFER_MAX, /* bit buffer */
! 123: sizeof(last_tcode_t)
! 124: };
! 125:
! 126: static struct dcfparam
! 127: {
! 128: unsigned char *onebits;
! 129: unsigned char *zerobits;
! 130: } dcfparameter =
! 131: {
! 132: (unsigned char *)"###############RADMLS1248124P124812P1248121241248112481248P??", /* 'ONE' representation */
! 133: (unsigned char *)"--------------------s-------p------p----------------------p__" /* 'ZERO' representation */
! 134: };
! 135:
! 136: static struct rawdcfcode
! 137: {
! 138: char offset; /* start bit */
! 139: } rawdcfcode[] =
! 140: {
! 141: { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 },
! 142: { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 }
! 143: };
! 144:
! 145: #define DCF_M 0
! 146: #define DCF_R 1
! 147: #define DCF_A1 2
! 148: #define DCF_Z 3
! 149: #define DCF_A2 4
! 150: #define DCF_S 5
! 151: #define DCF_M1 6
! 152: #define DCF_M10 7
! 153: #define DCF_P1 8
! 154: #define DCF_H1 9
! 155: #define DCF_H10 10
! 156: #define DCF_P2 11
! 157: #define DCF_D1 12
! 158: #define DCF_D10 13
! 159: #define DCF_DW 14
! 160: #define DCF_MO 15
! 161: #define DCF_MO0 16
! 162: #define DCF_Y1 17
! 163: #define DCF_Y10 18
! 164: #define DCF_P3 19
! 165:
! 166: static struct partab
! 167: {
! 168: char offset; /* start bit of parity field */
! 169: } partab[] =
! 170: {
! 171: { 21 }, { 29 }, { 36 }, { 59 }
! 172: };
! 173:
! 174: #define DCF_P_P1 0
! 175: #define DCF_P_P2 1
! 176: #define DCF_P_P3 2
! 177:
! 178: #define DCF_Z_MET 0x2
! 179: #define DCF_Z_MED 0x1
! 180:
! 181: static u_long
! 182: ext_bf(
! 183: unsigned char *buf,
! 184: int idx,
! 185: unsigned char *zero
! 186: )
! 187: {
! 188: u_long sum = 0;
! 189: int i, first;
! 190:
! 191: first = rawdcfcode[idx].offset;
! 192:
! 193: for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--)
! 194: {
! 195: sum <<= 1;
! 196: sum |= (buf[i] != zero[i]);
! 197: }
! 198: return sum;
! 199: }
! 200:
! 201: static unsigned
! 202: pcheck(
! 203: unsigned char *buf,
! 204: int idx,
! 205: unsigned char *zero
! 206: )
! 207: {
! 208: int i,last;
! 209: unsigned psum = 1;
! 210:
! 211: last = partab[idx+1].offset;
! 212:
! 213: for (i = partab[idx].offset; i < last; i++)
! 214: psum ^= (buf[i] != zero[i]);
! 215:
! 216: return psum;
! 217: }
! 218:
! 219: static u_long
! 220: convert_rawdcf(
! 221: unsigned char *buffer,
! 222: int size,
! 223: struct dcfparam *dcfprm,
! 224: clocktime_t *clock_time
! 225: )
! 226: {
! 227: unsigned char *s = buffer;
! 228: unsigned char *b = dcfprm->onebits;
! 229: unsigned char *c = dcfprm->zerobits;
! 230: int i;
! 231:
! 232: parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer));
! 233:
! 234: if (size < 57)
! 235: {
! 236: #ifndef PARSEKERNEL
! 237: msyslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits\n", size);
! 238: #endif
! 239: return CVT_NONE;
! 240: }
! 241:
! 242: for (i = 0; i < size; i++)
! 243: {
! 244: if ((*s != *b) && (*s != *c))
! 245: {
! 246: /*
! 247: * we only have two types of bytes (ones and zeros)
! 248: */
! 249: #ifndef PARSEKERNEL
! 250: msyslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion");
! 251: #endif
! 252: return CVT_NONE;
! 253: }
! 254: if (*b) b++;
! 255: if (*c) c++;
! 256: s++;
! 257: }
! 258:
! 259: /*
! 260: * check Start and Parity bits
! 261: */
! 262: if ((ext_bf(buffer, DCF_S, dcfprm->zerobits) == 1) &&
! 263: pcheck(buffer, DCF_P_P1, dcfprm->zerobits) &&
! 264: pcheck(buffer, DCF_P_P2, dcfprm->zerobits) &&
! 265: pcheck(buffer, DCF_P_P3, dcfprm->zerobits))
! 266: {
! 267: /*
! 268: * buffer OK
! 269: */
! 270: parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n"));
! 271:
! 272: clock_time->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP;
! 273: clock_time->utctime= 0;
! 274: clock_time->usecond= 0;
! 275: clock_time->second = 0;
! 276: clock_time->minute = ext_bf(buffer, DCF_M10, dcfprm->zerobits);
! 277: clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1, dcfprm->zerobits);
! 278: clock_time->hour = ext_bf(buffer, DCF_H10, dcfprm->zerobits);
! 279: clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1, dcfprm->zerobits);
! 280: clock_time->day = ext_bf(buffer, DCF_D10, dcfprm->zerobits);
! 281: clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1, dcfprm->zerobits);
! 282: clock_time->month = ext_bf(buffer, DCF_MO0, dcfprm->zerobits);
! 283: clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO, dcfprm->zerobits);
! 284: clock_time->year = ext_bf(buffer, DCF_Y10, dcfprm->zerobits);
! 285: clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1, dcfprm->zerobits);
! 286:
! 287: switch (ext_bf(buffer, DCF_Z, dcfprm->zerobits))
! 288: {
! 289: case DCF_Z_MET:
! 290: clock_time->utcoffset = -1*60*60;
! 291: break;
! 292:
! 293: case DCF_Z_MED:
! 294: clock_time->flags |= PARSEB_DST;
! 295: clock_time->utcoffset = -2*60*60;
! 296: break;
! 297:
! 298: default:
! 299: parseprintf(DD_RAWDCF,("parse: convert_rawdcf: BAD TIME ZONE\n"));
! 300: return CVT_FAIL|CVT_BADFMT;
! 301: }
! 302:
! 303: if (ext_bf(buffer, DCF_A1, dcfprm->zerobits))
! 304: clock_time->flags |= PARSEB_ANNOUNCE;
! 305:
! 306: if (ext_bf(buffer, DCF_A2, dcfprm->zerobits))
! 307: clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */
! 308:
! 309: if (ext_bf(buffer, DCF_R, dcfprm->zerobits))
! 310: clock_time->flags |= PARSEB_ALTERNATE;
! 311:
! 312: parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%lx\n",
! 313: (int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year,
! 314: (u_long)clock_time->flags));
! 315: return CVT_OK;
! 316: }
! 317: else
! 318: {
! 319: /*
! 320: * bad format - not for us
! 321: */
! 322: #ifndef PARSEKERNEL
! 323: msyslog(LOG_ERR, "parse: convert_rawdcf: parity check FAILED for \"%s\"\n", buffer);
! 324: #endif
! 325: return CVT_FAIL|CVT_BADFMT;
! 326: }
! 327: }
! 328:
! 329: /*
! 330: * raw dcf input routine - needs to fix up 50 baud
! 331: * characters for 1/0 decision
! 332: */
! 333: static u_long
! 334: cvt_rawdcf(
! 335: unsigned char *buffer,
! 336: int size,
! 337: struct format *param,
! 338: clocktime_t *clock_time,
! 339: void *local
! 340: )
! 341: {
! 342: last_tcode_t *t = (last_tcode_t *)local;
! 343: unsigned char *s = (unsigned char *)buffer;
! 344: unsigned char *e = s + size;
! 345: unsigned char *b = dcfparameter.onebits;
! 346: unsigned char *c = dcfparameter.zerobits;
! 347: u_long rtc = CVT_NONE;
! 348: unsigned int i, lowmax, highmax, cutoff, span;
! 349: #define BITS 9
! 350: unsigned char histbuf[BITS];
! 351: /*
! 352: * the input buffer contains characters with runs of consecutive
! 353: * bits set. These set bits are an indication of the DCF77 pulse
! 354: * length. We assume that we receive the pulse at 50 Baud. Thus
! 355: * a 100ms pulse would generate a 4 bit train (20ms per bit and
! 356: * start bit)
! 357: * a 200ms pulse would create all zeroes (and probably a frame error)
! 358: */
! 359:
! 360: for (i = 0; i < BITS; i++)
! 361: {
! 362: histbuf[i] = 0;
! 363: }
! 364:
! 365: cutoff = 0;
! 366: lowmax = 0;
! 367:
! 368: while (s < e)
! 369: {
! 370: unsigned int ch = *s ^ 0xFF;
! 371: /*
! 372: * these lines are left as an excercise to the reader 8-)
! 373: */
! 374: if (!((ch+1) & ch) || !*s)
! 375: {
! 376:
! 377: for (i = 0; ch; i++)
! 378: {
! 379: ch >>= 1;
! 380: }
! 381:
! 382: *s = i;
! 383: histbuf[i]++;
! 384: cutoff += i;
! 385: lowmax++;
! 386: }
! 387: else
! 388: {
! 389: parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, (int)(s - (unsigned char *)buffer)));
! 390: *s = (unsigned char)~0;
! 391: rtc = CVT_FAIL|CVT_BADFMT;
! 392: }
! 393: s++;
! 394: }
! 395:
! 396: if (lowmax)
! 397: {
! 398: cutoff /= lowmax;
! 399: }
! 400: else
! 401: {
! 402: cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */
! 403: }
! 404:
! 405: parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: average bit count: %d\n", cutoff));
! 406:
! 407: lowmax = 0;
! 408: highmax = 0;
! 409:
! 410: parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: histogram:"));
! 411: for (i = 0; i <= cutoff; i++)
! 412: {
! 413: lowmax+=histbuf[i] * i;
! 414: highmax += histbuf[i];
! 415: parseprintf(DD_RAWDCF,(" %d", histbuf[i]));
! 416: }
! 417: parseprintf(DD_RAWDCF, (" <M>"));
! 418:
! 419: lowmax += highmax / 2;
! 420:
! 421: if (highmax)
! 422: {
! 423: lowmax /= highmax;
! 424: }
! 425: else
! 426: {
! 427: lowmax = 0;
! 428: }
! 429:
! 430: highmax = 0;
! 431: cutoff = 0;
! 432:
! 433: for (; i < BITS; i++)
! 434: {
! 435: highmax+=histbuf[i] * i;
! 436: cutoff +=histbuf[i];
! 437: parseprintf(DD_RAWDCF,(" %d", histbuf[i]));
! 438: }
! 439: parseprintf(DD_RAWDCF,("\n"));
! 440:
! 441: if (cutoff)
! 442: {
! 443: highmax /= cutoff;
! 444: }
! 445: else
! 446: {
! 447: highmax = BITS-1;
! 448: }
! 449:
! 450: span = cutoff = lowmax;
! 451: for (i = lowmax; i <= highmax; i++)
! 452: {
! 453: if (histbuf[cutoff] > histbuf[i])
! 454: {
! 455: cutoff = i;
! 456: span = i;
! 457: }
! 458: else
! 459: if (histbuf[cutoff] == histbuf[i])
! 460: {
! 461: span = i;
! 462: }
! 463: }
! 464:
! 465: cutoff = (cutoff + span) / 2;
! 466:
! 467: parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff));
! 468:
! 469: s = (unsigned char *)buffer;
! 470: while (s < e)
! 471: {
! 472: if (*s == (unsigned char)~0)
! 473: {
! 474: *s = '?';
! 475: }
! 476: else
! 477: {
! 478: *s = (*s >= cutoff) ? *b : *c;
! 479: }
! 480: s++;
! 481: if (*b) b++;
! 482: if (*c) c++;
! 483: }
! 484:
! 485: if (rtc == CVT_NONE)
! 486: {
! 487: rtc = convert_rawdcf(buffer, size, &dcfparameter, clock_time);
! 488: if (rtc == CVT_OK)
! 489: {
! 490: time_t newtime;
! 491:
! 492: newtime = parse_to_unixtime(clock_time, &rtc);
! 493: if ((rtc == CVT_OK) && t)
! 494: {
! 495: if ((newtime - t->tcode) == 60) /* guard against multi bit errors */
! 496: {
! 497: clock_time->utctime = newtime;
! 498: }
! 499: else
! 500: {
! 501: rtc = CVT_FAIL|CVT_BADTIME;
! 502: }
! 503: t->tcode = newtime;
! 504: }
! 505: }
! 506: }
! 507:
! 508: return rtc;
! 509: }
! 510:
! 511: /*
! 512: * pps_rawdcf
! 513: *
! 514: * currently a very stupid version - should be extended to decode
! 515: * also ones and zeros (which is easy)
! 516: */
! 517: /*ARGSUSED*/
! 518: static u_long
! 519: pps_rawdcf(
! 520: parse_t *parseio,
! 521: int status,
! 522: timestamp_t *ptime
! 523: )
! 524: {
! 525: if (!status) /* negative edge for simpler wiring (Rx->DCD) */
! 526: {
! 527: parseio->parse_dtime.parse_ptime = *ptime;
! 528: parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
! 529: }
! 530:
! 531: return CVT_NONE;
! 532: }
! 533:
! 534: static u_long
! 535: snt_rawdcf(
! 536: parse_t *parseio,
! 537: timestamp_t *ptime
! 538: )
! 539: {
! 540: if ((parseio->parse_dtime.parse_status & CVT_MASK) == CVT_OK)
! 541: {
! 542: parseio->parse_dtime.parse_stime = *ptime;
! 543:
! 544: #ifdef PARSEKERNEL
! 545: parseio->parse_dtime.parse_time.tv.tv_sec++;
! 546: #else
! 547: parseio->parse_dtime.parse_time.fp.l_ui++;
! 548: #endif
! 549:
! 550: parseprintf(DD_RAWDCF,("parse: snt_rawdcf: time stamp synthesized offset %d seconds\n", parseio->parse_index - 1));
! 551:
! 552: return updatetimeinfo(parseio, parseio->parse_lstate);
! 553: }
! 554: return CVT_NONE;
! 555: }
! 556:
! 557: /*
! 558: * inp_rawdcf
! 559: *
! 560: * grab DCF77 data from input stream
! 561: */
! 562: static u_long
! 563: inp_rawdcf(
! 564: parse_t *parseio,
! 565: unsigned int ch,
! 566: timestamp_t *tstamp
! 567: )
! 568: {
! 569: static struct timeval timeout = { 1, 500000 }; /* 1.5 secongs denote second #60 */
! 570:
! 571: parseprintf(DD_PARSE, ("inp_rawdcf(0x%lx, 0x%x, ...)\n", (long)parseio, ch));
! 572:
! 573: parseio->parse_dtime.parse_stime = *tstamp; /* collect timestamp */
! 574:
! 575: if (parse_timedout(parseio, tstamp, &timeout))
! 576: {
! 577: parseprintf(DD_PARSE, ("inp_rawdcf: time out seen\n"));
! 578:
! 579: (void) parse_end(parseio);
! 580: (void) parse_addchar(parseio, ch);
! 581: return PARSE_INP_TIME;
! 582: }
! 583: else
! 584: {
! 585: unsigned int rtc;
! 586:
! 587: rtc = parse_addchar(parseio, ch);
! 588: if (rtc == PARSE_INP_SKIP)
! 589: {
! 590: if (snt_rawdcf(parseio, tstamp) == CVT_OK)
! 591: return PARSE_INP_SYNTH;
! 592: }
! 593: return rtc;
! 594: }
! 595: }
! 596:
! 597: #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RAWDCF) */
! 598: int clk_rawdcf_bs;
! 599: #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_RAWDCF) */
! 600:
! 601: /*
! 602: * History:
! 603: *
! 604: * clk_rawdcf.c,v
! 605: * Revision 4.18 2006/06/22 18:40:01 kardel
! 606: * clean up signedness (gcc 4)
! 607: *
! 608: * Revision 4.17 2006/01/22 16:01:55 kardel
! 609: * update version information
! 610: *
! 611: * Revision 4.16 2006/01/22 15:51:22 kardel
! 612: * generate reasonable timecode output on invalid input
! 613: *
! 614: * Revision 4.15 2005/08/06 19:17:06 kardel
! 615: * clean log output
! 616: *
! 617: * Revision 4.14 2005/08/06 17:39:40 kardel
! 618: * cleanup size handling wrt/ to buffer boundaries
! 619: *
! 620: * Revision 4.13 2005/04/16 17:32:10 kardel
! 621: * update copyright
! 622: *
! 623: * Revision 4.12 2004/11/14 15:29:41 kardel
! 624: * support PPSAPI, upgrade Copyright to Berkeley style
! 625: *
! 626: * Revision 4.9 1999/12/06 13:42:23 kardel
! 627: * transfer correctly converted time codes always into tcode
! 628: *
! 629: * Revision 4.8 1999/11/28 09:13:50 kardel
! 630: * RECON_4_0_98F
! 631: *
! 632: * Revision 4.7 1999/04/01 20:07:20 kardel
! 633: * added checking for minutie increment of timestamps in clk_rawdcf.c
! 634: *
! 635: * Revision 4.6 1998/06/14 21:09:37 kardel
! 636: * Sun acc cleanup
! 637: *
! 638: * Revision 4.5 1998/06/13 12:04:16 kardel
! 639: * fix SYSV clock name clash
! 640: *
! 641: * Revision 4.4 1998/06/12 15:22:28 kardel
! 642: * fix prototypes
! 643: *
! 644: * Revision 4.3 1998/06/06 18:33:36 kardel
! 645: * simplified condidional compile expression
! 646: *
! 647: * Revision 4.2 1998/05/24 11:04:18 kardel
! 648: * triggering PPS on negative edge for simpler wiring (Rx->DCD)
! 649: *
! 650: * Revision 4.1 1998/05/24 09:39:53 kardel
! 651: * implementation of the new IO handling model
! 652: *
! 653: * Revision 4.0 1998/04/10 19:45:30 kardel
! 654: * Start 4.0 release version numbering
! 655: *
! 656: * from V3 3.24 log info deleted 1998/04/11 kardel
! 657: *
! 658: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>