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