Annotation of embedaddon/ntp/ntpd/refclock_gpsvme.c, revision 1.1.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, &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>