Annotation of embedaddon/ntp/ntpd/refclock_chronolog.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * refclock_chronolog - clock driver for Chronolog K-series WWVB receiver.
                      3:  */
                      4: 
                      5: /*
                      6:  * Must interpolate back to local time.  Very annoying.
                      7:  */
                      8: #define GET_LOCALTIME
                      9: 
                     10: #ifdef HAVE_CONFIG_H
                     11: #include <config.h>
                     12: #endif
                     13: 
                     14: #if defined(REFCLOCK) && defined(CLOCK_CHRONOLOG)
                     15: 
                     16: #include "ntpd.h"
                     17: #include "ntp_io.h"
                     18: #include "ntp_refclock.h"
                     19: #include "ntp_calendar.h"
                     20: #include "ntp_stdlib.h"
                     21: 
                     22: #include <stdio.h>
                     23: #include <ctype.h>
                     24: 
                     25: /*
                     26:  * This driver supports the Chronolog K-series WWVB receiver.
                     27:  *
                     28:  * Input format:
                     29:  *
                     30:  *     Y YY/MM/DD<cr><lf>
                     31:  *      Z hh:mm:ss<cr><lf>
                     32:  *
                     33:  * YY/MM/DD -- what you'd expect.  This arrives a few seconds before the
                     34:  * timestamp.
                     35:  * hh:mm:ss -- what you'd expect.  We take time on the <cr>.
                     36:  *
                     37:  * Our Chronolog writes time out at 2400 bps 8/N/1, but it can be configured
                     38:  * otherwise.  The clock seems to appear every 60 seconds, which doesn't make
                     39:  * for good statistics collection.
                     40:  *
                     41:  * The original source of this module was the WWVB module.
                     42:  */
                     43: 
                     44: /*
                     45:  * Interface definitions
                     46:  */
                     47: #define        DEVICE          "/dev/chronolog%d" /* device name and unit */
                     48: #define        SPEED232        B2400   /* uart speed (2400 baud) */
                     49: #define        PRECISION       (-13)   /* precision assumed (about 100 us) */
                     50: #define        REFID           "chronolog"     /* reference ID */
                     51: #define        DESCRIPTION     "Chrono-log K" /* WRU */
                     52: 
                     53: #define MONLIN         15      /* number of monitoring lines */
                     54: 
                     55: /*
                     56:  * Chrono-log unit control structure
                     57:  */
                     58: struct chronolog_unit {
                     59:        u_char  tcswitch;       /* timecode switch */
                     60:        l_fp    laststamp;      /* last receive timestamp */
                     61:        u_char  lasthour;       /* last hour (for monitor) */
                     62:        int     year;           /* Y2K-adjusted year */
                     63:        int     day;            /* day-of-month */
                     64:         int    month;          /* month-of-year */
                     65: };
                     66: 
                     67: /*
                     68:  * Function prototypes
                     69:  */
                     70: static int     chronolog_start         (int, struct peer *);
                     71: static void    chronolog_shutdown      (int, struct peer *);
                     72: static void    chronolog_receive       (struct recvbuf *);
                     73: static void    chronolog_poll          (int, struct peer *);
                     74: 
                     75: /*
                     76:  * Transfer vector
                     77:  */
                     78: struct refclock refclock_chronolog = {
                     79:        chronolog_start,        /* start up driver */
                     80:        chronolog_shutdown,     /* shut down driver */
                     81:        chronolog_poll,         /* poll the driver -- a nice fabrication */
                     82:        noentry,                /* not used */
                     83:        noentry,                /* not used */
                     84:        noentry,                /* not used */
                     85:        NOFLAGS                 /* not used */
                     86: };
                     87: 
                     88: 
                     89: /*
                     90:  * chronolog_start - open the devices and initialize data for processing
                     91:  */
                     92: static int
                     93: chronolog_start(
                     94:        int unit,
                     95:        struct peer *peer
                     96:        )
                     97: {
                     98:        register struct chronolog_unit *up;
                     99:        struct refclockproc *pp;
                    100:        int fd;
                    101:        char device[20];
                    102: 
                    103:        /*
                    104:         * Open serial port. Don't bother with CLK line discipline, since
                    105:         * it's not available.
                    106:         */
                    107:        snprintf(device, sizeof(device), DEVICE, unit);
                    108: #ifdef DEBUG
                    109:        if (debug)
                    110:                printf ("starting Chronolog with device %s\n",device);
                    111: #endif
                    112:        if (!(fd = refclock_open(device, SPEED232, 0)))
                    113:                return (0);
                    114: 
                    115:        /*
                    116:         * Allocate and initialize unit structure
                    117:         */
                    118:        up = emalloc(sizeof(*up));
                    119:        memset(up, 0, sizeof(*up));
                    120:        pp = peer->procptr;
                    121:        pp->unitptr = (caddr_t)up;
                    122:        pp->io.clock_recv = chronolog_receive;
                    123:        pp->io.srcclock = (caddr_t)peer;
                    124:        pp->io.datalen = 0;
                    125:        pp->io.fd = fd;
                    126:        if (!io_addclock(&pp->io)) {
                    127:                close(fd);
                    128:                pp->io.fd = -1;
                    129:                free(up);
                    130:                pp->unitptr = NULL;
                    131:                return (0);
                    132:        }
                    133: 
                    134:        /*
                    135:         * Initialize miscellaneous variables
                    136:         */
                    137:        peer->precision = PRECISION;
                    138:        pp->clockdesc = DESCRIPTION;
                    139:        memcpy((char *)&pp->refid, REFID, 4);
                    140:        return (1);
                    141: }
                    142: 
                    143: 
                    144: /*
                    145:  * chronolog_shutdown - shut down the clock
                    146:  */
                    147: static void
                    148: chronolog_shutdown(
                    149:        int unit,
                    150:        struct peer *peer
                    151:        )
                    152: {
                    153:        register struct chronolog_unit *up;
                    154:        struct refclockproc *pp;
                    155: 
                    156:        pp = peer->procptr;
                    157:        up = (struct chronolog_unit *)pp->unitptr;
                    158:        if (-1 != pp->io.fd)
                    159:                io_closeclock(&pp->io);
                    160:        if (NULL != up)
                    161:                free(up);
                    162: }
                    163: 
                    164: 
                    165: /*
                    166:  * chronolog_receive - receive data from the serial interface
                    167:  */
                    168: static void
                    169: chronolog_receive(
                    170:        struct recvbuf *rbufp
                    171:        )
                    172: {
                    173:        struct chronolog_unit *up;
                    174:        struct refclockproc *pp;
                    175:        struct peer *peer;
                    176: 
                    177:        l_fp         trtmp;     /* arrival timestamp */
                    178:        int          hours;     /* hour-of-day */
                    179:        int          minutes;   /* minutes-past-the-hour */
                    180:        int          seconds;   /* seconds */
                    181:        int          temp;      /* int temp */
                    182:        int          got_good;  /* got a good time flag */
                    183: 
                    184:        /*
                    185:         * Initialize pointers and read the timecode and timestamp
                    186:         */
                    187:        peer = (struct peer *)rbufp->recv_srcclock;
                    188:        pp = peer->procptr;
                    189:        up = (struct chronolog_unit *)pp->unitptr;
                    190:        temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
                    191: 
                    192:        if (temp == 0) {
                    193:                if (up->tcswitch == 0) {
                    194:                        up->tcswitch = 1;
                    195:                        up->laststamp = trtmp;
                    196:                } else
                    197:                    up->tcswitch = 0;
                    198:                return;
                    199:        }
                    200:        pp->lencode = temp;
                    201:        pp->lastrec = up->laststamp;
                    202:        up->laststamp = trtmp;
                    203:        up->tcswitch = 1;
                    204: 
                    205: #ifdef DEBUG
                    206:        if (debug)
                    207:                printf("chronolog: timecode %d %s\n", pp->lencode,
                    208:                    pp->a_lastcode);
                    209: #endif
                    210: 
                    211:        /*
                    212:         * We get down to business. Check the timecode format and decode
                    213:         * its contents. This code uses the first character to see whether
                    214:         * we're looking at a date or a time.  We store data data across
                    215:         * calls since it is transmitted a few seconds ahead of the
                    216:         * timestamp.
                    217:         */
                    218:        got_good=0;
                    219:        if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day))
                    220:        {
                    221:            /*
                    222:             * Y2K convert the 2-digit year
                    223:             */
                    224:            up->year = up->year >= 69 ? up->year : up->year + 100;
                    225:            return;
                    226:        }
                    227:        if (sscanf(pp->a_lastcode,"Z %02d:%02d:%02d",
                    228:                   &hours,&minutes,&seconds) == 3)
                    229:        {
                    230: #ifdef GET_LOCALTIME
                    231:            struct tm  local;
                    232:            struct tm *gmtp;
                    233:            time_t     unixtime;
                    234:            int        adjyear;
                    235:            int        adjmon;
                    236: 
                    237:            /*
                    238:             * Convert to GMT for sites that distribute localtime.  This
                    239:              * means we have to do Y2K conversion on the 2-digit year;
                    240:             * otherwise, we get the time wrong.
                    241:             */
                    242:            
                    243:            memset(&local, 0, sizeof(local));
                    244: 
                    245:            local.tm_year  = up->year;
                    246:            local.tm_mon   = up->month-1;
                    247:            local.tm_mday  = up->day;
                    248:            local.tm_hour  = hours;
                    249:            local.tm_min   = minutes;
                    250:            local.tm_sec   = seconds;
                    251:            local.tm_isdst = -1;
                    252: 
                    253:            unixtime = mktime (&local);
                    254:            if ((gmtp = gmtime (&unixtime)) == NULL)
                    255:            {
                    256:                refclock_report (peer, CEVNT_FAULT);
                    257:                return;
                    258:            }
                    259:            adjyear = gmtp->tm_year+1900;
                    260:            adjmon  = gmtp->tm_mon+1;
                    261:            pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
                    262:            pp->hour   = gmtp->tm_hour;
                    263:            pp->minute = gmtp->tm_min;
                    264:            pp->second = gmtp->tm_sec;
                    265: #ifdef DEBUG
                    266:            if (debug)
                    267:                printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
                    268:                        adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
                    269:                        pp->second);
                    270: #endif
                    271:            
                    272: #else
                    273:            /*
                    274:             * For more rational sites distributing UTC
                    275:             */
                    276:            pp->day    = ymd2yd(year+1900,month,day);
                    277:            pp->hour   = hours;
                    278:            pp->minute = minutes;
                    279:            pp->second = seconds;
                    280: 
                    281: #endif
                    282:            got_good=1;
                    283:        }
                    284: 
                    285:        if (!got_good)
                    286:            return;
                    287: 
                    288: 
                    289:        /*
                    290:         * Process the new sample in the median filter and determine the
                    291:         * timecode timestamp.
                    292:         */
                    293:        if (!refclock_process(pp)) {
                    294:                refclock_report(peer, CEVNT_BADTIME);
                    295:                return;
                    296:        }
                    297:        pp->lastref = pp->lastrec;
                    298:        refclock_receive(peer);
                    299:        record_clock_stats(&peer->srcadr, pp->a_lastcode);
                    300:        up->lasthour = pp->hour;
                    301: }
                    302: 
                    303: 
                    304: /*
                    305:  * chronolog_poll - called by the transmit procedure
                    306:  */
                    307: static void
                    308: chronolog_poll(
                    309:        int unit,
                    310:        struct peer *peer
                    311:        )
                    312: {
                    313:        /*
                    314:         * Time to poll the clock. The Chrono-log clock is supposed to
                    315:         * respond to a 'T' by returning a timecode in the format(s)
                    316:         * specified above.  Ours does (can?) not, but this seems to be
                    317:         * an installation-specific problem.  This code is dyked out,
                    318:         * but may be re-enabled if anyone ever finds a Chrono-log that
                    319:         * actually listens to this command.
                    320:         */
                    321: #if 0
                    322:        register struct chronolog_unit *up;
                    323:        struct refclockproc *pp;
                    324:        char pollchar;
                    325: 
                    326:        pp = peer->procptr;
                    327:        up = (struct chronolog_unit *)pp->unitptr;
                    328:        if (peer->burst == 0 && peer->reach == 0)
                    329:                refclock_report(peer, CEVNT_TIMEOUT);
                    330:        if (up->linect > 0)
                    331:                pollchar = 'R';
                    332:        else
                    333:                pollchar = 'T';
                    334:        if (write(pp->io.fd, &pollchar, 1) != 1)
                    335:                refclock_report(peer, CEVNT_FAULT);
                    336:        else
                    337:                pp->polls++;
                    338: #endif
                    339: }
                    340: 
                    341: #else
                    342: int refclock_chronolog_bs;
                    343: #endif /* REFCLOCK */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>