Annotation of embedaddon/ntp/ntpd/refclock_gpsvme.c, revision 1.1
1.1 ! misho 1: /* refclock_psc.c: clock driver for Brandywine PCI-SyncClock32/HP-UX 11.X */
! 2:
! 3: #ifdef HAVE_CONFIG_H
! 4: #include <config.h>
! 5: #endif /* HAVE_CONFIG_H */
! 6:
! 7: #if defined(REFCLOCK) && defined(CLOCK_GPSVME)
! 8:
! 9: #include "ntpd.h"
! 10: #include "ntp_io.h"
! 11: #include "ntp_refclock.h"
! 12: #include "ntp_unixtime.h"
! 13: #include "ntp_stdlib.h"
! 14:
! 15: #ifdef __hpux
! 16: #include <sys/rtprio.h> /* may already be included above */
! 17: #include <sys/lock.h> /* NEEDED for PROCLOCK */
! 18: #endif /* __hpux */
! 19:
! 20: #ifdef __linux__
! 21: #include <sys/ioctl.h> /* for _IOR, ioctl */
! 22: #endif /* __linux__ */
! 23:
! 24: enum { /* constants */
! 25: BUFSIZE = 32,
! 26: PSC_SYNC_OK = 0x40, /* Sync status bit */
! 27: DP_LEAPSEC_DAY10DAY1 = 0x82, /* DP RAM address */
! 28: DP_LEAPSEC_DAY1000DAY100 = 0x83,
! 29: DELAY = 1,
! 30: NUNIT = 2 /* max UNITS */
! 31: };
! 32:
! 33: /* clock card registers */
! 34: struct psc_regs {
! 35: uint32_t low_time; /* card base + 0x00 */
! 36: uint32_t high_time; /* card base + 0x04 */
! 37: uint32_t ext_low_time; /* card base + 0x08 */
! 38: uint32_t ext_high_time; /* card base + 0x0C */
! 39: uint8_t device_status; /* card base + 0x10 */
! 40: uint8_t device_control; /* card base + 0x11 */
! 41: uint8_t reserved0; /* card base + 0x12 */
! 42: uint8_t ext_100ns; /* card base + 0x13 */
! 43: uint8_t match_usec; /* card base + 0x14 */
! 44: uint8_t match_msec; /* card base + 0x15 */
! 45: uint8_t reserved1; /* card base + 0x16 */
! 46: uint8_t reserved2; /* card base + 0x17 */
! 47: uint8_t reserved3; /* card base + 0x18 */
! 48: uint8_t reserved4; /* card base + 0x19 */
! 49: uint8_t dp_ram_addr; /* card base + 0x1A */
! 50: uint8_t reserved5; /* card base + 0x1B */
! 51: uint8_t reserved6; /* card base + 0x1C */
! 52: uint8_t reserved7; /* card base + 0x1D */
! 53: uint8_t dp_ram_data; /* card base + 0x1E */
! 54: uint8_t reserved8; /* card base + 0x1F */
! 55: } *volatile regp[NUNIT];
! 56:
! 57: #define PSC_REGS _IOR('K', 0, long) /* ioctl argument */
! 58:
! 59: /* Macros to swap byte order and convert BCD to binary */
! 60: #define SWAP(val) ( ((val) >> 24) | (((val) & 0x00ff0000) >> 8) | \
! 61: (((val) & 0x0000ff00) << 8) | (((val) & 0x000000ff) << 24) )
! 62: #define BCD2INT2(val) ( ((val) >> 4 & 0x0f)*10 + ((val) & 0x0f) )
! 63: #define BCD2INT3(val) ( ((val) >> 8 & 0x0f)*100 + ((val) >> 4 & 0x0f)*10 + \
! 64: ((val) & 0x0f) )
! 65:
! 66: /* PSC interface definitions */
! 67: #define PRECISION (-20) /* precision assumed (1 us) */
! 68: #define REFID "USNO" /* reference ID */
! 69: #define DESCRIPTION "Brandywine PCI-SyncClock32"
! 70: #define DEVICE "/dev/refclock%1d" /* device file */
! 71:
! 72: /* clock unit control structure */
! 73: struct psc_unit {
! 74: short unit; /* NTP refclock unit number */
! 75: short last_hour; /* last hour (monitor leap sec) */
! 76: int msg_flag[2]; /* count error messages */
! 77: };
! 78: int fd[NUNIT]; /* file descriptor */
! 79:
! 80: /* Local function prototypes */
! 81: static int psc_start(int, struct peer *);
! 82: static void psc_shutdown(int, struct peer *);
! 83: static void psc_poll(int, struct peer *);
! 84: static void check_leap_sec(struct refclockproc *, int);
! 85:
! 86: /* Transfer vector */
! 87: struct refclock refclock_gpsvme = {
! 88: psc_start, psc_shutdown, psc_poll, noentry, noentry, noentry, NOFLAGS
! 89: };
! 90:
! 91: /* psc_start: open device and initialize data for processing */
! 92: static int
! 93: psc_start(
! 94: int unit,
! 95: struct peer *peer
! 96: )
! 97: {
! 98: char buf[BUFSIZE];
! 99: struct refclockproc *pp;
! 100: struct psc_unit *up = emalloc(sizeof *up);
! 101:
! 102: if (unit < 0 || unit > 1) { /* support units 0 and 1 */
! 103: msyslog(LOG_ERR, "psc_start: bad unit: %d", unit);
! 104: return 0;
! 105: }
! 106:
! 107: memset(up, '\0', sizeof *up);
! 108:
! 109: snprintf(buf, sizeof(buf), DEVICE, unit); /* dev file name */
! 110: fd[unit] = open(buf, O_RDONLY); /* open device file */
! 111: if (fd[unit] < 0) {
! 112: msyslog(LOG_ERR, "psc_start: unit: %d, open failed. %m", unit);
! 113: return 0;
! 114: }
! 115:
! 116: /* get the address of the mapped regs */
! 117: if (ioctl(fd[unit], PSC_REGS, ®p[unit]) < 0) {
! 118: msyslog(LOG_ERR, "psc_start: unit: %d, ioctl failed. %m", unit);
! 119: return 0;
! 120: }
! 121:
! 122: /* initialize peer variables */
! 123: pp = peer->procptr;
! 124: pp->io.clock_recv = noentry;
! 125: pp->io.srcclock = (caddr_t) peer;
! 126: pp->io.datalen = 0;
! 127: pp->io.fd = -1;
! 128: pp->unitptr = (caddr_t) up;
! 129: get_systime(&pp->lastrec);
! 130: memcpy(&pp->refid, REFID, 4);
! 131: peer->precision = PRECISION;
! 132: pp->clockdesc = DESCRIPTION;
! 133: up->unit = unit;
! 134: #ifdef __hpux
! 135: rtprio(0,120); /* set real time priority */
! 136: plock(PROCLOCK); /* lock process in memory */
! 137: #endif /* __hpux */
! 138: return 1;
! 139: }
! 140:
! 141: /* psc_shutdown: shut down the clock */
! 142: static void
! 143: psc_shutdown(
! 144: int unit,
! 145: struct peer *peer
! 146: )
! 147: {
! 148: if (NULL != peer->procptr->unitptr)
! 149: free(peer->procptr->unitptr);
! 150: if (fd[unit] > 0)
! 151: close(fd[unit]);
! 152: }
! 153:
! 154: /* psc_poll: read, decode, and record device time */
! 155: static void
! 156: psc_poll(
! 157: int unit,
! 158: struct peer *peer
! 159: )
! 160: {
! 161: struct refclockproc *pp = peer->procptr;
! 162: struct psc_unit *up;
! 163: unsigned tlo, thi;
! 164: unsigned char status;
! 165:
! 166: up = (struct psc_unit *) pp->unitptr;
! 167: tlo = regp[unit]->low_time; /* latch and read first 4 bytes */
! 168: thi = regp[unit]->high_time; /* read 4 higher order bytes */
! 169: status = regp[unit]->device_status; /* read device status byte */
! 170:
! 171: if (!(status & PSC_SYNC_OK)) {
! 172: refclock_report(peer, CEVNT_BADTIME);
! 173: if (!up->msg_flag[unit]) { /* write once to system log */
! 174: msyslog(LOG_WARNING,
! 175: "SYNCHRONIZATION LOST on unit %1d, status %02x\n",
! 176: status, unit);
! 177: up->msg_flag[unit] = 1;
! 178: }
! 179: return;
! 180: }
! 181:
! 182: get_systime(&pp->lastrec);
! 183: pp->polls++;
! 184:
! 185: tlo = SWAP(tlo); /* little to big endian swap on */
! 186: thi = SWAP(thi); /* copy of data */
! 187: /* convert the BCD time to broken down time used by refclockproc */
! 188: pp->day = BCD2INT3((thi & 0x0FFF0000) >> 16);
! 189: pp->hour = BCD2INT2((thi & 0x0000FF00) >> 8);
! 190: pp->minute = BCD2INT2(thi & 0x000000FF);
! 191: pp->second = BCD2INT2(tlo >> 24);
! 192: /* ntp_process() in ntp_refclock.c appears to use usec as fraction of
! 193: second in microseconds if usec is nonzero. */
! 194: pp->nsec = 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) +
! 195: BCD2INT3(tlo & 0x00000FFF);
! 196:
! 197: snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
! 198: "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x", pp->day,
! 199: pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
! 200: tlo);
! 201: pp->lencode = strlen(pp->a_lastcode);
! 202:
! 203: /* compute the timecode timestamp */
! 204: if (!refclock_process(pp)) {
! 205: refclock_report(peer, CEVNT_BADTIME);
! 206: return;
! 207: }
! 208: /* simulate the NTP receive and packet procedures */
! 209: refclock_receive(peer);
! 210: /* write clock statistics to file */
! 211: record_clock_stats(&peer->srcadr, pp->a_lastcode);
! 212:
! 213: /* With the first timecode beginning the day, check for a GPS
! 214: leap second notification. */
! 215: if (pp->hour < up->last_hour) {
! 216: check_leap_sec(pp, unit);
! 217: up->msg_flag[0] = up->msg_flag[1] = 0; /* reset flags */
! 218: }
! 219: up->last_hour = pp->hour;
! 220: }
! 221:
! 222: /* check_leap_sec: read the Dual Port RAM leap second day registers. The
! 223: onboard GPS receiver should write the hundreds digit of day of year in
! 224: DP_LeapSec_Day1000Day100 and the tens and ones digits in
! 225: DP_LeapSec_Day10Day1. If these values are nonzero and today, we have
! 226: a leap second pending, so we set the pp->leap flag to LEAP_ADDSECOND.
! 227: If the BCD data are zero or a date other than today, set pp->leap to
! 228: LEAP_NOWARNING. */
! 229: static void
! 230: check_leap_sec(struct refclockproc *pp, int unit)
! 231: {
! 232: unsigned char dhi, dlo;
! 233: int leap_day;
! 234:
! 235: regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY10DAY1;
! 236: usleep(DELAY);
! 237: dlo = regp[unit]->dp_ram_data;
! 238: regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY1000DAY100;
! 239: usleep(DELAY);
! 240: dhi = regp[unit]->dp_ram_data;
! 241: leap_day = BCD2INT2(dlo) + 100*(dhi & 0x0F);
! 242:
! 243: pp->leap = LEAP_NOWARNING; /* default */
! 244: if (leap_day && leap_day == pp->day) {
! 245: pp->leap = LEAP_ADDSECOND; /* leap second today */
! 246: msyslog(LOG_ERR, "LEAP_ADDSECOND flag set, day %d (%x %x).",
! 247: leap_day, dhi, dlo);
! 248: }
! 249: }
! 250:
! 251: #else
! 252: int refclock_gpsvme_bs;
! 253: #endif /* REFCLOCK */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>