Annotation of embedaddon/ntp/ntpd/refclock_leitch.c, revision 1.1
1.1 ! misho 1: /*
! 2: * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock
! 3: */
! 4:
! 5: #ifdef HAVE_CONFIG_H
! 6: # include <config.h>
! 7: #endif
! 8:
! 9: #if defined(REFCLOCK) && defined(CLOCK_LEITCH)
! 10:
! 11: #include "ntpd.h"
! 12: #include "ntp_io.h"
! 13: #include "ntp_refclock.h"
! 14: #include "ntp_unixtime.h"
! 15:
! 16: #include <stdio.h>
! 17: #include <ctype.h>
! 18:
! 19: #ifdef STREAM
! 20: #include <stropts.h>
! 21: #if defined(LEITCHCLK)
! 22: #include <sys/clkdefs.h>
! 23: #endif /* LEITCHCLK */
! 24: #endif /* STREAM */
! 25:
! 26: #include "ntp_stdlib.h"
! 27:
! 28:
! 29: /*
! 30: * Driver for Leitch CSD-5300 Master Clock System
! 31: *
! 32: * COMMANDS:
! 33: * DATE: D <CR>
! 34: * TIME: T <CR>
! 35: * STATUS: S <CR>
! 36: * LOOP: L <CR>
! 37: *
! 38: * FORMAT:
! 39: * DATE: YYMMDD<CR>
! 40: * TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/
! 41: * second bondaried on the stop bit of the <CR>
! 42: * second boundaries at '/' above.
! 43: * STATUS: G (good), D (diag fail), T (time not provided) or
! 44: * P (last phone update failed)
! 45: */
! 46: #define PRECISION (-20) /* 1x10-8 */
! 47: #define MAXUNITS 1 /* max number of LEITCH units */
! 48: #define LEITCHREFID "ATOM" /* reference id */
! 49: #define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver"
! 50: #define LEITCH232 "/dev/leitch%d" /* name of radio device */
! 51: #define SPEED232 B300 /* uart speed (300 baud) */
! 52: #ifdef DEBUG
! 53: #define leitch_send(A,M) \
! 54: if (debug) fprintf(stderr,"write leitch %s\n",M); \
! 55: if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\
! 56: if (debug) \
! 57: fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \
! 58: else \
! 59: msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);}
! 60: #else
! 61: #define leitch_send(A,M) \
! 62: if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\
! 63: msyslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);}
! 64: #endif
! 65:
! 66: #define STATE_IDLE 0
! 67: #define STATE_DATE 1
! 68: #define STATE_TIME1 2
! 69: #define STATE_TIME2 3
! 70: #define STATE_TIME3 4
! 71:
! 72: /*
! 73: * LEITCH unit control structure
! 74: */
! 75: struct leitchunit {
! 76: struct peer *peer;
! 77: struct refclockio leitchio;
! 78: u_char unit;
! 79: short year;
! 80: short yearday;
! 81: short month;
! 82: short day;
! 83: short hour;
! 84: short second;
! 85: short minute;
! 86: short state;
! 87: u_short fudge1;
! 88: l_fp reftime1;
! 89: l_fp reftime2;
! 90: l_fp reftime3;
! 91: l_fp codetime1;
! 92: l_fp codetime2;
! 93: l_fp codetime3;
! 94: u_long yearstart;
! 95: };
! 96:
! 97: /*
! 98: * Function prototypes
! 99: */
! 100: static void leitch_init (void);
! 101: static int leitch_start (int, struct peer *);
! 102: static void leitch_shutdown (int, struct peer *);
! 103: static void leitch_poll (int, struct peer *);
! 104: static void leitch_control (int, struct refclockstat *, struct refclockstat *, struct peer *);
! 105: #define leitch_buginfo noentry
! 106: static void leitch_receive (struct recvbuf *);
! 107: static void leitch_process (struct leitchunit *);
! 108: #if 0
! 109: static void leitch_timeout (struct peer *);
! 110: #endif
! 111: static int leitch_get_date (struct recvbuf *, struct leitchunit *);
! 112: static int leitch_get_time (struct recvbuf *, struct leitchunit *, int);
! 113: static int days_per_year (int);
! 114:
! 115: static struct leitchunit leitchunits[MAXUNITS];
! 116: static u_char unitinuse[MAXUNITS];
! 117: static u_char stratumtouse[MAXUNITS];
! 118: static u_int32 refid[MAXUNITS];
! 119:
! 120: static char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
! 121:
! 122: /*
! 123: * Transfer vector
! 124: */
! 125: struct refclock refclock_leitch = {
! 126: leitch_start, leitch_shutdown, leitch_poll,
! 127: leitch_control, leitch_init, leitch_buginfo, NOFLAGS
! 128: };
! 129:
! 130: /*
! 131: * leitch_init - initialize internal leitch driver data
! 132: */
! 133: static void
! 134: leitch_init(void)
! 135: {
! 136: int i;
! 137:
! 138: memset((char*)leitchunits, 0, sizeof(leitchunits));
! 139: memset((char*)unitinuse, 0, sizeof(unitinuse));
! 140: for (i = 0; i < MAXUNITS; i++)
! 141: memcpy((char *)&refid[i], LEITCHREFID, 4);
! 142: }
! 143:
! 144: /*
! 145: * leitch_shutdown - shut down a LEITCH clock
! 146: */
! 147: static void
! 148: leitch_shutdown(
! 149: int unit,
! 150: struct peer *peer
! 151: )
! 152: {
! 153: struct leitchunit *leitch;
! 154:
! 155: if (unit >= MAXUNITS) {
! 156: return;
! 157: }
! 158: leitch = &leitchunits[unit];
! 159: if (-1 != leitch->leitchio.fd)
! 160: io_closeclock(&leitch->leitchio);
! 161: #ifdef DEBUG
! 162: if (debug)
! 163: fprintf(stderr, "leitch_shutdown()\n");
! 164: #endif
! 165: }
! 166:
! 167: /*
! 168: * leitch_poll - called by the transmit procedure
! 169: */
! 170: static void
! 171: leitch_poll(
! 172: int unit,
! 173: struct peer *peer
! 174: )
! 175: {
! 176: struct leitchunit *leitch;
! 177:
! 178: /* start the state machine rolling */
! 179:
! 180: #ifdef DEBUG
! 181: if (debug)
! 182: fprintf(stderr, "leitch_poll()\n");
! 183: #endif
! 184: if (unit >= MAXUNITS) {
! 185: /* XXXX syslog it */
! 186: return;
! 187: }
! 188:
! 189: leitch = &leitchunits[unit];
! 190:
! 191: if (leitch->state != STATE_IDLE) {
! 192: /* reset and wait for next poll */
! 193: /* XXXX syslog it */
! 194: leitch->state = STATE_IDLE;
! 195: } else {
! 196: leitch_send(leitch,"D\r");
! 197: leitch->state = STATE_DATE;
! 198: }
! 199: }
! 200:
! 201: static void
! 202: leitch_control(
! 203: int unit,
! 204: struct refclockstat *in,
! 205: struct refclockstat *out,
! 206: struct peer *passed_peer
! 207: )
! 208: {
! 209: if (unit >= MAXUNITS) {
! 210: msyslog(LOG_ERR,
! 211: "leitch_control: unit %d invalid", unit);
! 212: return;
! 213: }
! 214:
! 215: if (in) {
! 216: if (in->haveflags & CLK_HAVEVAL1)
! 217: stratumtouse[unit] = (u_char)(in->fudgeval1);
! 218: if (in->haveflags & CLK_HAVEVAL2)
! 219: refid[unit] = in->fudgeval2;
! 220: if (unitinuse[unit]) {
! 221: struct peer *peer;
! 222:
! 223: peer = (&leitchunits[unit])->peer;
! 224: peer->stratum = stratumtouse[unit];
! 225: peer->refid = refid[unit];
! 226: }
! 227: }
! 228:
! 229: if (out) {
! 230: memset((char *)out, 0, sizeof (struct refclockstat));
! 231: out->type = REFCLK_ATOM_LEITCH;
! 232: out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
! 233: out->fudgeval1 = (int32)stratumtouse[unit];
! 234: out->fudgeval2 = refid[unit];
! 235: out->p_lastcode = "";
! 236: out->clockdesc = LEITCH_DESCRIPTION;
! 237: }
! 238: }
! 239:
! 240: /*
! 241: * leitch_start - open the LEITCH devices and initialize data for processing
! 242: */
! 243: static int
! 244: leitch_start(
! 245: int unit,
! 246: struct peer *peer
! 247: )
! 248: {
! 249: struct leitchunit *leitch;
! 250: int fd232;
! 251: char leitchdev[20];
! 252:
! 253: /*
! 254: * Check configuration info.
! 255: */
! 256: if (unit >= MAXUNITS) {
! 257: msyslog(LOG_ERR, "leitch_start: unit %d invalid", unit);
! 258: return (0);
! 259: }
! 260:
! 261: if (unitinuse[unit]) {
! 262: msyslog(LOG_ERR, "leitch_start: unit %d in use", unit);
! 263: return (0);
! 264: }
! 265:
! 266: /*
! 267: * Open serial port.
! 268: */
! 269: snprintf(leitchdev, sizeof(leitchdev), LEITCH232, unit);
! 270: fd232 = open(leitchdev, O_RDWR, 0777);
! 271: if (fd232 == -1) {
! 272: msyslog(LOG_ERR,
! 273: "leitch_start: open of %s: %m", leitchdev);
! 274: return (0);
! 275: }
! 276:
! 277: leitch = &leitchunits[unit];
! 278: memset(leitch, 0, sizeof(*leitch));
! 279:
! 280: #if defined(HAVE_SYSV_TTYS)
! 281: /*
! 282: * System V serial line parameters (termio interface)
! 283: *
! 284: */
! 285: { struct termio ttyb;
! 286: if (ioctl(fd232, TCGETA, &ttyb) < 0) {
! 287: msyslog(LOG_ERR,
! 288: "leitch_start: ioctl(%s, TCGETA): %m", leitchdev);
! 289: goto screwed;
! 290: }
! 291: ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
! 292: ttyb.c_oflag = 0;
! 293: ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
! 294: ttyb.c_lflag = ICANON;
! 295: ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
! 296: if (ioctl(fd232, TCSETA, &ttyb) < 0) {
! 297: msyslog(LOG_ERR,
! 298: "leitch_start: ioctl(%s, TCSETA): %m", leitchdev);
! 299: goto screwed;
! 300: }
! 301: }
! 302: #endif /* HAVE_SYSV_TTYS */
! 303: #if defined(HAVE_TERMIOS)
! 304: /*
! 305: * POSIX serial line parameters (termios interface)
! 306: *
! 307: * The LEITCHCLK option provides timestamping at the driver level.
! 308: * It requires the tty_clk streams module.
! 309: */
! 310: { struct termios ttyb, *ttyp;
! 311:
! 312: ttyp = &ttyb;
! 313: if (tcgetattr(fd232, ttyp) < 0) {
! 314: msyslog(LOG_ERR,
! 315: "leitch_start: tcgetattr(%s): %m", leitchdev);
! 316: goto screwed;
! 317: }
! 318: ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
! 319: ttyp->c_oflag = 0;
! 320: ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
! 321: ttyp->c_lflag = ICANON;
! 322: ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
! 323: if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
! 324: msyslog(LOG_ERR,
! 325: "leitch_start: tcsetattr(%s): %m", leitchdev);
! 326: goto screwed;
! 327: }
! 328: if (tcflush(fd232, TCIOFLUSH) < 0) {
! 329: msyslog(LOG_ERR,
! 330: "leitch_start: tcflush(%s): %m", leitchdev);
! 331: goto screwed;
! 332: }
! 333: }
! 334: #endif /* HAVE_TERMIOS */
! 335: #ifdef STREAM
! 336: #if defined(LEITCHCLK)
! 337: if (ioctl(fd232, I_PUSH, "clk") < 0)
! 338: msyslog(LOG_ERR,
! 339: "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev);
! 340: if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
! 341: msyslog(LOG_ERR,
! 342: "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev);
! 343: #endif /* LEITCHCLK */
! 344: #endif /* STREAM */
! 345: #if defined(HAVE_BSD_TTYS)
! 346: /*
! 347: * 4.3bsd serial line parameters (sgttyb interface)
! 348: *
! 349: * The LEITCHCLK option provides timestamping at the driver level.
! 350: * It requires the tty_clk line discipline and 4.3bsd or later.
! 351: */
! 352: { struct sgttyb ttyb;
! 353: #if defined(LEITCHCLK)
! 354: int ldisc = CLKLDISC;
! 355: #endif /* LEITCHCLK */
! 356:
! 357: if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
! 358: msyslog(LOG_ERR,
! 359: "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev);
! 360: goto screwed;
! 361: }
! 362: ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
! 363: #if defined(LEITCHCLK)
! 364: ttyb.sg_erase = ttyb.sg_kill = '\r';
! 365: ttyb.sg_flags = RAW;
! 366: #else
! 367: ttyb.sg_erase = ttyb.sg_kill = '\0';
! 368: ttyb.sg_flags = EVENP|ODDP|CRMOD;
! 369: #endif /* LEITCHCLK */
! 370: if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
! 371: msyslog(LOG_ERR,
! 372: "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev);
! 373: goto screwed;
! 374: }
! 375: #if defined(LEITCHCLK)
! 376: if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
! 377: msyslog(LOG_ERR,
! 378: "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev);
! 379: goto screwed;
! 380: }
! 381: #endif /* LEITCHCLK */
! 382: }
! 383: #endif /* HAVE_BSD_TTYS */
! 384:
! 385: /*
! 386: * Set up the structures
! 387: */
! 388: leitch->peer = peer;
! 389: leitch->unit = unit;
! 390: leitch->state = STATE_IDLE;
! 391: leitch->fudge1 = 15; /* 15ms */
! 392:
! 393: leitch->leitchio.clock_recv = leitch_receive;
! 394: leitch->leitchio.srcclock = (caddr_t) leitch;
! 395: leitch->leitchio.datalen = 0;
! 396: leitch->leitchio.fd = fd232;
! 397: if (!io_addclock(&leitch->leitchio)) {
! 398: leitch->leitchio.fd = -1;
! 399: goto screwed;
! 400: }
! 401:
! 402: /*
! 403: * All done. Initialize a few random peer variables, then
! 404: * return success.
! 405: */
! 406: peer->precision = PRECISION;
! 407: peer->stratum = stratumtouse[unit];
! 408: peer->refid = refid[unit];
! 409: unitinuse[unit] = 1;
! 410: return(1);
! 411:
! 412: /*
! 413: * Something broke; abandon ship.
! 414: */
! 415: screwed:
! 416: close(fd232);
! 417: return(0);
! 418: }
! 419:
! 420: /*
! 421: * leitch_receive - receive data from the serial interface on a leitch
! 422: * clock
! 423: */
! 424: static void
! 425: leitch_receive(
! 426: struct recvbuf *rbufp
! 427: )
! 428: {
! 429: struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock;
! 430:
! 431: #ifdef DEBUG
! 432: if (debug)
! 433: fprintf(stderr, "leitch_recieve(%*.*s)\n",
! 434: rbufp->recv_length, rbufp->recv_length,
! 435: rbufp->recv_buffer);
! 436: #endif
! 437: if (rbufp->recv_length != 7)
! 438: return; /* The date is return with a trailing newline,
! 439: discard it. */
! 440:
! 441: switch (leitch->state) {
! 442: case STATE_IDLE: /* unexpected, discard and resync */
! 443: return;
! 444: case STATE_DATE:
! 445: if (!leitch_get_date(rbufp,leitch)) {
! 446: leitch->state = STATE_IDLE;
! 447: break;
! 448: }
! 449: leitch_send(leitch,"T\r");
! 450: #ifdef DEBUG
! 451: if (debug)
! 452: fprintf(stderr, "%u\n",leitch->yearday);
! 453: #endif
! 454: leitch->state = STATE_TIME1;
! 455: break;
! 456: case STATE_TIME1:
! 457: if (!leitch_get_time(rbufp,leitch,1)) {
! 458: }
! 459: if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
! 460: leitch->second, 1, rbufp->recv_time.l_ui,
! 461: &leitch->yearstart, &leitch->reftime1.l_ui)) {
! 462: leitch->state = STATE_IDLE;
! 463: break;
! 464: }
! 465: leitch->reftime1.l_uf = 0;
! 466: #ifdef DEBUG
! 467: if (debug)
! 468: fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui);
! 469: #endif
! 470: MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf);
! 471: leitch->codetime1 = rbufp->recv_time;
! 472: leitch->state = STATE_TIME2;
! 473: break;
! 474: case STATE_TIME2:
! 475: if (!leitch_get_time(rbufp,leitch,2)) {
! 476: }
! 477: if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
! 478: leitch->second, 1, rbufp->recv_time.l_ui,
! 479: &leitch->yearstart, &leitch->reftime2.l_ui)) {
! 480: leitch->state = STATE_IDLE;
! 481: break;
! 482: }
! 483: #ifdef DEBUG
! 484: if (debug)
! 485: fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui);
! 486: #endif
! 487: MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf);
! 488: leitch->codetime2 = rbufp->recv_time;
! 489: leitch->state = STATE_TIME3;
! 490: break;
! 491: case STATE_TIME3:
! 492: if (!leitch_get_time(rbufp,leitch,3)) {
! 493: }
! 494: if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
! 495: leitch->second, GMT, rbufp->recv_time.l_ui,
! 496: &leitch->yearstart, &leitch->reftime3.l_ui)) {
! 497: leitch->state = STATE_IDLE;
! 498: break;
! 499: }
! 500: #ifdef DEBUG
! 501: if (debug)
! 502: fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui);
! 503: #endif
! 504: MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf);
! 505: leitch->codetime3 = rbufp->recv_time;
! 506: leitch_process(leitch);
! 507: leitch->state = STATE_IDLE;
! 508: break;
! 509: default:
! 510: msyslog(LOG_ERR,
! 511: "leitech_receive: invalid state %d unit %d",
! 512: leitch->state, leitch->unit);
! 513: }
! 514: }
! 515:
! 516: /*
! 517: * leitch_process - process a pile of samples from the clock
! 518: *
! 519: * This routine uses a three-stage median filter to calculate offset and
! 520: * dispersion. reduce jitter. The dispersion is calculated as the span
! 521: * of the filter (max - min), unless the quality character (format 2) is
! 522: * non-blank, in which case the dispersion is calculated on the basis of
! 523: * the inherent tolerance of the internal radio oscillator, which is
! 524: * +-2e-5 according to the radio specifications.
! 525: */
! 526: static void
! 527: leitch_process(
! 528: struct leitchunit *leitch
! 529: )
! 530: {
! 531: l_fp off;
! 532: l_fp tmp_fp;
! 533: /*double doffset;*/
! 534:
! 535: off = leitch->reftime1;
! 536: L_SUB(&off,&leitch->codetime1);
! 537: tmp_fp = leitch->reftime2;
! 538: L_SUB(&tmp_fp,&leitch->codetime2);
! 539: if (L_ISGEQ(&off,&tmp_fp))
! 540: off = tmp_fp;
! 541: tmp_fp = leitch->reftime3;
! 542: L_SUB(&tmp_fp,&leitch->codetime3);
! 543:
! 544: if (L_ISGEQ(&off,&tmp_fp))
! 545: off = tmp_fp;
! 546: /*LFPTOD(&off, doffset);*/
! 547: refclock_receive(leitch->peer);
! 548: }
! 549:
! 550: /*
! 551: * days_per_year
! 552: */
! 553: static int
! 554: days_per_year(
! 555: int year
! 556: )
! 557: {
! 558: if (year%4) { /* not a potential leap year */
! 559: return (365);
! 560: } else {
! 561: if (year % 100) { /* is a leap year */
! 562: return (366);
! 563: } else {
! 564: if (year % 400) {
! 565: return (365);
! 566: } else {
! 567: return (366);
! 568: }
! 569: }
! 570: }
! 571: }
! 572:
! 573: static int
! 574: leitch_get_date(
! 575: struct recvbuf *rbufp,
! 576: struct leitchunit *leitch
! 577: )
! 578: {
! 579: int i;
! 580:
! 581: if (rbufp->recv_length < 6)
! 582: return(0);
! 583: #undef BAD /* confict: defined as (-1) in AIX sys/param.h */
! 584: #define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9')
! 585: if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
! 586: return(0);
! 587: #define ATOB(A) ((rbufp->recv_buffer[A])-'0')
! 588: leitch->year = ATOB(0)*10 + ATOB(1);
! 589: leitch->month = ATOB(2)*10 + ATOB(3);
! 590: leitch->day = ATOB(4)*10 + ATOB(5);
! 591:
! 592: /* sanity checks */
! 593: if (leitch->month > 12)
! 594: return(0);
! 595: if (leitch->day > days_in_month[leitch->month-1])
! 596: return(0);
! 597:
! 598: /* calculate yearday */
! 599: i = 0;
! 600: leitch->yearday = leitch->day;
! 601:
! 602: while ( i < (leitch->month-1) )
! 603: leitch->yearday += days_in_month[i++];
! 604:
! 605: if ((days_per_year((leitch->year>90?1900:2000)+leitch->year)==365) &&
! 606: leitch->month > 2)
! 607: leitch->yearday--;
! 608:
! 609: return(1);
! 610: }
! 611:
! 612: /*
! 613: * leitch_get_time
! 614: */
! 615: static int
! 616: leitch_get_time(
! 617: struct recvbuf *rbufp,
! 618: struct leitchunit *leitch,
! 619: int which
! 620: )
! 621: {
! 622: if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
! 623: return(0);
! 624: leitch->hour = ATOB(0)*10 +ATOB(1);
! 625: leitch->minute = ATOB(2)*10 +ATOB(3);
! 626: leitch->second = ATOB(4)*10 +ATOB(5);
! 627:
! 628: if ((leitch->hour > 23) || (leitch->minute > 60) ||
! 629: (leitch->second > 60))
! 630: return(0);
! 631: return(1);
! 632: }
! 633:
! 634: #else
! 635: int refclock_leitch_bs;
! 636: #endif /* REFCLOCK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>