File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_gpsvme.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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, &regp[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>