Annotation of embedaddon/ntp/ntpd/refclock_pcf.c, revision 1.1
1.1 ! misho 1: /*
! 2: * refclock_pcf - clock driver for the Conrad parallel port radio clock
! 3: */
! 4:
! 5: #ifdef HAVE_CONFIG_H
! 6: # include <config.h>
! 7: #endif
! 8:
! 9: #if defined(REFCLOCK) && defined(CLOCK_PCF)
! 10:
! 11: #include "ntpd.h"
! 12: #include "ntp_io.h"
! 13: #include "ntp_refclock.h"
! 14: #include "ntp_calendar.h"
! 15: #include "ntp_stdlib.h"
! 16:
! 17: /*
! 18: * This driver supports the parallel port radio clock sold by Conrad
! 19: * Electronic under order numbers 967602 and 642002.
! 20: *
! 21: * It requires that the local timezone be CET/CEST and that the pcfclock
! 22: * device driver be installed. A device driver for Linux is available at
! 23: * http://home.pages.de/~voegele/pcf.html. Information about a FreeBSD
! 24: * driver is available at http://schumann.cx/pcfclock/.
! 25: */
! 26:
! 27: /*
! 28: * Interface definitions
! 29: */
! 30: #define DEVICE "/dev/pcfclocks/%d"
! 31: #define OLDDEVICE "/dev/pcfclock%d"
! 32: #define PRECISION (-1) /* precision assumed (about 0.5 s) */
! 33: #define REFID "PCF"
! 34: #define DESCRIPTION "Conrad parallel port radio clock"
! 35:
! 36: #define LENPCF 18 /* timecode length */
! 37:
! 38: /*
! 39: * Function prototypes
! 40: */
! 41: static int pcf_start (int, struct peer *);
! 42: static void pcf_shutdown (int, struct peer *);
! 43: static void pcf_poll (int, struct peer *);
! 44:
! 45: /*
! 46: * Transfer vector
! 47: */
! 48: struct refclock refclock_pcf = {
! 49: pcf_start, /* start up driver */
! 50: pcf_shutdown, /* shut down driver */
! 51: pcf_poll, /* transmit poll message */
! 52: noentry, /* not used */
! 53: noentry, /* initialize driver (not used) */
! 54: noentry, /* not used */
! 55: NOFLAGS /* not used */
! 56: };
! 57:
! 58:
! 59: /*
! 60: * pcf_start - open the device and initialize data for processing
! 61: */
! 62: static int
! 63: pcf_start(
! 64: int unit,
! 65: struct peer *peer
! 66: )
! 67: {
! 68: struct refclockproc *pp;
! 69: int fd;
! 70: char device[128];
! 71:
! 72: /*
! 73: * Open device file for reading.
! 74: */
! 75: snprintf(device, sizeof(device), DEVICE, unit);
! 76: fd = open(device, O_RDONLY);
! 77: if (fd == -1) {
! 78: snprintf(device, sizeof(device), OLDDEVICE, unit);
! 79: fd = open(device, O_RDONLY);
! 80: }
! 81: #ifdef DEBUG
! 82: if (debug)
! 83: printf ("starting PCF with device %s\n",device);
! 84: #endif
! 85: if (fd == -1) {
! 86: return (0);
! 87: }
! 88:
! 89: pp = peer->procptr;
! 90: pp->io.clock_recv = noentry;
! 91: pp->io.srcclock = (caddr_t)peer;
! 92: pp->io.datalen = 0;
! 93: pp->io.fd = fd;
! 94:
! 95: /*
! 96: * Initialize miscellaneous variables
! 97: */
! 98: peer->precision = PRECISION;
! 99: pp->clockdesc = DESCRIPTION;
! 100: /* one transmission takes 172.5 milliseconds since the radio clock
! 101: transmits 69 bits with a period of 2.5 milliseconds per bit */
! 102: pp->fudgetime1 = 0.1725;
! 103: memcpy((char *)&pp->refid, REFID, 4);
! 104:
! 105: return (1);
! 106: }
! 107:
! 108:
! 109: /*
! 110: * pcf_shutdown - shut down the clock
! 111: */
! 112: static void
! 113: pcf_shutdown(
! 114: int unit,
! 115: struct peer *peer
! 116: )
! 117: {
! 118: struct refclockproc *pp;
! 119:
! 120: pp = peer->procptr;
! 121: (void)close(pp->io.fd);
! 122: }
! 123:
! 124:
! 125: /*
! 126: * pcf_poll - called by the transmit procedure
! 127: */
! 128: static void
! 129: pcf_poll(
! 130: int unit,
! 131: struct peer *peer
! 132: )
! 133: {
! 134: struct refclockproc *pp;
! 135: char buf[LENPCF];
! 136: struct tm tm, *tp;
! 137: time_t t;
! 138:
! 139: pp = peer->procptr;
! 140:
! 141: buf[0] = 0;
! 142: if (read(pp->io.fd, buf, sizeof(buf)) < sizeof(buf) || buf[0] != 9) {
! 143: refclock_report(peer, CEVNT_FAULT);
! 144: return;
! 145: }
! 146:
! 147: memset(&tm, 0, sizeof(tm));
! 148:
! 149: tm.tm_mday = buf[11] * 10 + buf[10];
! 150: tm.tm_mon = buf[13] * 10 + buf[12] - 1;
! 151: tm.tm_year = buf[15] * 10 + buf[14];
! 152: tm.tm_hour = buf[7] * 10 + buf[6];
! 153: tm.tm_min = buf[5] * 10 + buf[4];
! 154: tm.tm_sec = buf[3] * 10 + buf[2];
! 155: tm.tm_isdst = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1;
! 156:
! 157: /*
! 158: * Y2K convert the 2-digit year
! 159: */
! 160: if (tm.tm_year < 99)
! 161: tm.tm_year += 100;
! 162:
! 163: t = mktime(&tm);
! 164: if (t == (time_t) -1) {
! 165: refclock_report(peer, CEVNT_BADTIME);
! 166: return;
! 167: }
! 168:
! 169: #if defined(__GLIBC__) && defined(_BSD_SOURCE)
! 170: if ((tm.tm_isdst > 0 && tm.tm_gmtoff != 7200)
! 171: || (tm.tm_isdst == 0 && tm.tm_gmtoff != 3600)
! 172: || tm.tm_isdst < 0) {
! 173: #ifdef DEBUG
! 174: if (debug)
! 175: printf ("local time zone not set to CET/CEST\n");
! 176: #endif
! 177: refclock_report(peer, CEVNT_BADTIME);
! 178: return;
! 179: }
! 180: #endif
! 181:
! 182: pp->lencode = strftime(pp->a_lastcode, BMAX, "%Y %m %d %H %M %S", &tm);
! 183:
! 184: #if defined(_REENTRANT) || defined(_THREAD_SAFE)
! 185: tp = gmtime_r(&t, &tm);
! 186: #else
! 187: tp = gmtime(&t);
! 188: #endif
! 189: if (!tp) {
! 190: refclock_report(peer, CEVNT_FAULT);
! 191: return;
! 192: }
! 193:
! 194: get_systime(&pp->lastrec);
! 195: pp->polls++;
! 196: pp->year = tp->tm_year + 1900;
! 197: pp->day = tp->tm_yday + 1;
! 198: pp->hour = tp->tm_hour;
! 199: pp->minute = tp->tm_min;
! 200: pp->second = tp->tm_sec;
! 201: pp->nsec = buf[16] * 31250000;
! 202: if (buf[17] & 1)
! 203: pp->nsec += 500000000;
! 204:
! 205: #ifdef DEBUG
! 206: if (debug)
! 207: printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
! 208: unit, pp->year, tp->tm_mon + 1, tp->tm_mday, pp->hour,
! 209: pp->minute, pp->second);
! 210: #endif
! 211:
! 212: if (!refclock_process(pp)) {
! 213: refclock_report(peer, CEVNT_BADTIME);
! 214: return;
! 215: }
! 216: record_clock_stats(&peer->srcadr, pp->a_lastcode);
! 217: if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2))
! 218: pp->leap = LEAP_NOTINSYNC;
! 219: else
! 220: pp->leap = LEAP_NOWARNING;
! 221: pp->lastref = pp->lastrec;
! 222: refclock_receive(peer);
! 223: }
! 224: #else
! 225: int refclock_pcf_bs;
! 226: #endif /* REFCLOCK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>