Annotation of embedaddon/ntp/ntpd/refclock_dumbclock.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * refclock_dumbclock - clock driver for a unknown time distribution system
        !             3:  * that only provides hh:mm:ss (in local time, yet!).
        !             4:  */
        !             5: 
        !             6: /*
        !             7:  * Must interpolate back to local time.  Very annoying.
        !             8:  */
        !             9: #define GET_LOCALTIME
        !            10: 
        !            11: #ifdef HAVE_CONFIG_H
        !            12: #include <config.h>
        !            13: #endif
        !            14: 
        !            15: #if defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK)
        !            16: 
        !            17: #include "ntpd.h"
        !            18: #include "ntp_io.h"
        !            19: #include "ntp_refclock.h"
        !            20: #include "ntp_calendar.h"
        !            21: #include "ntp_stdlib.h"
        !            22: 
        !            23: #include <stdio.h>
        !            24: #include <ctype.h>
        !            25: 
        !            26: #ifdef SYS_WINNT
        !            27: extern int async_write(int, const void *, unsigned int);
        !            28: #undef write
        !            29: #define write(fd, data, octets)        async_write(fd, data, octets)
        !            30: #endif
        !            31: 
        !            32: /*
        !            33:  * This driver supports a generic dumb clock that only outputs hh:mm:ss,
        !            34:  * in local time, no less.
        !            35:  *
        !            36:  * Input format:
        !            37:  *
        !            38:  *     hh:mm:ss   <cr>
        !            39:  *
        !            40:  * hh:mm:ss -- what you'd expect, with a 24 hour clock.  (Heck, that's the only
        !            41:  * way it could get stupider.)  We take time on the <cr>.
        !            42:  *
        !            43:  * The original source of this module was the WWVB module.
        !            44:  */
        !            45: 
        !            46: /*
        !            47:  * Interface definitions
        !            48:  */
        !            49: #define        DEVICE          "/dev/dumbclock%d" /* device name and unit */
        !            50: #define        SPEED232        B9600   /* uart speed (9600 baud) */
        !            51: #define        PRECISION       (-13)   /* precision assumed (about 100 us) */
        !            52: #define        REFID           "dumbclock"     /* reference ID */
        !            53: #define        DESCRIPTION     "Dumb clock" /* WRU */
        !            54: 
        !            55: 
        !            56: /*
        !            57:  * Insanity check.  Since the time is local, we need to make sure that during midnight
        !            58:  * transitions, we can convert back to Unix time.  If the conversion results in some number
        !            59:  * worse than this number of seconds away, assume the next day and retry.
        !            60:  */
        !            61: #define INSANE_SECONDS 3600
        !            62: 
        !            63: /*
        !            64:  * Dumb clock control structure
        !            65:  */
        !            66: struct dumbclock_unit {
        !            67:        u_char    tcswitch;     /* timecode switch */
        !            68:        l_fp      laststamp;    /* last receive timestamp */
        !            69:        u_char    lasthour;     /* last hour (for monitor) */
        !            70:        u_char    linect;       /* count ignored lines (for monitor */
        !            71:        struct tm ymd;          /* struct tm for y/m/d only */
        !            72: };
        !            73: 
        !            74: /*
        !            75:  * Function prototypes
        !            76:  */
        !            77: static int     dumbclock_start         (int, struct peer *);
        !            78: static void    dumbclock_shutdown      (int, struct peer *);
        !            79: static void    dumbclock_receive       (struct recvbuf *);
        !            80: #if 0
        !            81: static void    dumbclock_poll          (int, struct peer *);
        !            82: #endif
        !            83: 
        !            84: /*
        !            85:  * Transfer vector
        !            86:  */
        !            87: struct refclock refclock_dumbclock = {
        !            88:        dumbclock_start,                     /* start up driver */
        !            89:        dumbclock_shutdown,                  /* shut down driver */
        !            90:        noentry,                             /* poll the driver -- a nice fabrication */
        !            91:        noentry,                             /* not used */
        !            92:        noentry,                             /* not used */
        !            93:        noentry,                             /* not used */
        !            94:        NOFLAGS                              /* not used */
        !            95: };
        !            96: 
        !            97: 
        !            98: /*
        !            99:  * dumbclock_start - open the devices and initialize data for processing
        !           100:  */
        !           101: static int
        !           102: dumbclock_start(
        !           103:        int unit,
        !           104:        struct peer *peer
        !           105:        )
        !           106: {
        !           107:        register struct dumbclock_unit *up;
        !           108:        struct refclockproc *pp;
        !           109:        int fd;
        !           110:        char device[20];
        !           111:        struct tm *tm_time_p;
        !           112:        time_t     now;
        !           113: 
        !           114:        /*
        !           115:         * Open serial port. Don't bother with CLK line discipline, since
        !           116:         * it's not available.
        !           117:         */
        !           118:        snprintf(device, sizeof(device), DEVICE, unit);
        !           119: #ifdef DEBUG
        !           120:        if (debug)
        !           121:                printf ("starting Dumbclock with device %s\n",device);
        !           122: #endif
        !           123:        fd = refclock_open(device, SPEED232, 0);
        !           124:        if (!fd)
        !           125:                return (0);
        !           126: 
        !           127:        /*
        !           128:         * Allocate and initialize unit structure
        !           129:         */
        !           130:        up = emalloc(sizeof(*up));
        !           131:        memset(up, 0, sizeof(*up));
        !           132:        pp = peer->procptr;
        !           133:        pp->unitptr = (caddr_t)up;
        !           134:        pp->io.clock_recv = dumbclock_receive;
        !           135:        pp->io.srcclock = (caddr_t)peer;
        !           136:        pp->io.datalen = 0;
        !           137:        pp->io.fd = fd;
        !           138:        if (!io_addclock(&pp->io)) {
        !           139:                close(fd);
        !           140:                pp->io.fd = -1;
        !           141:                free(up);
        !           142:                pp->unitptr = NULL;
        !           143:                return (0);
        !           144:        }
        !           145: 
        !           146: 
        !           147:        time(&now);
        !           148: #ifdef GET_LOCALTIME
        !           149:        tm_time_p = localtime(&now);
        !           150: #else
        !           151:        tm_time_p = gmtime(&now);
        !           152: #endif
        !           153:        if (tm_time_p)
        !           154:                up->ymd = *tm_time_p;
        !           155:        else
        !           156:                return 0;
        !           157: 
        !           158:        /*
        !           159:         * Initialize miscellaneous variables
        !           160:         */
        !           161:        peer->precision = PRECISION;
        !           162:        pp->clockdesc = DESCRIPTION;
        !           163:        memcpy((char *)&pp->refid, REFID, 4);
        !           164:        return (1);
        !           165: }
        !           166: 
        !           167: 
        !           168: /*
        !           169:  * dumbclock_shutdown - shut down the clock
        !           170:  */
        !           171: static void
        !           172: dumbclock_shutdown(
        !           173:        int unit,
        !           174:        struct peer *peer
        !           175:        )
        !           176: {
        !           177:        register struct dumbclock_unit *up;
        !           178:        struct refclockproc *pp;
        !           179: 
        !           180:        pp = peer->procptr;
        !           181:        up = (struct dumbclock_unit *)pp->unitptr;
        !           182:        if (-1 != pp->io.fd)
        !           183:                io_closeclock(&pp->io);
        !           184:        if (NULL != up)
        !           185:                free(up);
        !           186: }
        !           187: 
        !           188: 
        !           189: /*
        !           190:  * dumbclock_receive - receive data from the serial interface
        !           191:  */
        !           192: static void
        !           193: dumbclock_receive(
        !           194:        struct recvbuf *rbufp
        !           195:        )
        !           196: {
        !           197:        struct dumbclock_unit *up;
        !           198:        struct refclockproc *pp;
        !           199:        struct peer *peer;
        !           200: 
        !           201:        l_fp    trtmp;          /* arrival timestamp */
        !           202:        int     hours;          /* hour-of-day */
        !           203:        int     minutes;        /* minutes-past-the-hour */
        !           204:        int     seconds;        /* seconds */
        !           205:        int     temp;           /* int temp */
        !           206:        int     got_good;       /* got a good time flag */
        !           207: 
        !           208:        /*
        !           209:         * Initialize pointers and read the timecode and timestamp
        !           210:         */
        !           211:        peer = (struct peer *)rbufp->recv_srcclock;
        !           212:        pp = peer->procptr;
        !           213:        up = (struct dumbclock_unit *)pp->unitptr;
        !           214:        temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
        !           215: 
        !           216:        if (temp == 0) {
        !           217:                if (up->tcswitch == 0) {
        !           218:                        up->tcswitch = 1;
        !           219:                        up->laststamp = trtmp;
        !           220:                } else
        !           221:                        up->tcswitch = 0;
        !           222:                return;
        !           223:        }
        !           224:        pp->lencode = (u_short)temp;
        !           225:        pp->lastrec = up->laststamp;
        !           226:        up->laststamp = trtmp;
        !           227:        up->tcswitch = 1;
        !           228: 
        !           229: #ifdef DEBUG
        !           230:        if (debug)
        !           231:                printf("dumbclock: timecode %d %s\n",
        !           232:                       pp->lencode, pp->a_lastcode);
        !           233: #endif
        !           234: 
        !           235:        /*
        !           236:         * We get down to business. Check the timecode format...
        !           237:         */
        !           238:        got_good=0;
        !           239:        if (sscanf(pp->a_lastcode,"%02d:%02d:%02d",
        !           240:                   &hours,&minutes,&seconds) == 3)
        !           241:        {
        !           242:            struct tm *gmtp;
        !           243:            struct tm *lt_p;
        !           244:            time_t     asserted_time;        /* the SPM time based on the composite time+date */
        !           245:            struct tm  asserted_tm;          /* the struct tm of the same */
        !           246:            int        adjyear;
        !           247:            int        adjmon;
        !           248:            time_t     reality_delta;
        !           249:            time_t     now;
        !           250: 
        !           251: 
        !           252:            /*
        !           253:             * Convert to GMT for sites that distribute localtime.  This
        !           254:             * means we have to figure out what day it is.  Easier said
        !           255:             * than done...
        !           256:             */
        !           257: 
        !           258:            memset(&asserted_tm, 0, sizeof(asserted_tm));
        !           259: 
        !           260:            asserted_tm.tm_year  = up->ymd.tm_year;
        !           261:            asserted_tm.tm_mon   = up->ymd.tm_mon;
        !           262:            asserted_tm.tm_mday  = up->ymd.tm_mday;
        !           263:            asserted_tm.tm_hour  = hours;
        !           264:            asserted_tm.tm_min   = minutes;
        !           265:            asserted_tm.tm_sec   = seconds;
        !           266:            asserted_tm.tm_isdst = -1;
        !           267: 
        !           268: #ifdef GET_LOCALTIME
        !           269:            asserted_time = mktime (&asserted_tm);
        !           270:            time(&now);
        !           271: #else
        !           272: #include "GMT unsupported for dumbclock!"
        !           273: #endif
        !           274:            reality_delta = asserted_time - now;
        !           275: 
        !           276:            /*
        !           277:             * We assume that if the time is grossly wrong, it's because we got the
        !           278:             * year/month/day wrong.
        !           279:             */
        !           280:            if (reality_delta > INSANE_SECONDS)
        !           281:            {
        !           282:                asserted_time -= SECSPERDAY; /* local clock behind real time */
        !           283:            }
        !           284:            else if (-reality_delta > INSANE_SECONDS)
        !           285:            {
        !           286:                asserted_time += SECSPERDAY; /* local clock ahead of real time */
        !           287:            }
        !           288:            lt_p = localtime(&asserted_time);
        !           289:            if (lt_p)
        !           290:            {
        !           291:                up->ymd = *lt_p;
        !           292:            }
        !           293:            else
        !           294:            {
        !           295:                refclock_report (peer, CEVNT_FAULT);
        !           296:                return;
        !           297:            }
        !           298: 
        !           299:            if ((gmtp = gmtime (&asserted_time)) == NULL)
        !           300:            {
        !           301:                refclock_report (peer, CEVNT_FAULT);
        !           302:                return;
        !           303:            }
        !           304:            adjyear = gmtp->tm_year+1900;
        !           305:            adjmon  = gmtp->tm_mon+1;
        !           306:            pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday);
        !           307:            pp->hour   = gmtp->tm_hour;
        !           308:            pp->minute = gmtp->tm_min;
        !           309:            pp->second = gmtp->tm_sec;
        !           310: #ifdef DEBUG
        !           311:            if (debug)
        !           312:                printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
        !           313:                        adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute,
        !           314:                        pp->second);
        !           315: #endif
        !           316: 
        !           317:            got_good=1;
        !           318:        }
        !           319: 
        !           320:        if (!got_good)
        !           321:        {
        !           322:            if (up->linect > 0)
        !           323:                up->linect--;
        !           324:            else
        !           325:                refclock_report(peer, CEVNT_BADREPLY);
        !           326:            return;
        !           327:        }
        !           328: 
        !           329:        /*
        !           330:         * Process the new sample in the median filter and determine the
        !           331:         * timecode timestamp.
        !           332:         */
        !           333:        if (!refclock_process(pp)) {
        !           334:                refclock_report(peer, CEVNT_BADTIME);
        !           335:                return;
        !           336:        }
        !           337:        pp->lastref = pp->lastrec;
        !           338:        refclock_receive(peer);
        !           339:        record_clock_stats(&peer->srcadr, pp->a_lastcode);
        !           340:        up->lasthour = (u_char)pp->hour;
        !           341: }
        !           342: 
        !           343: #if 0
        !           344: /*
        !           345:  * dumbclock_poll - called by the transmit procedure
        !           346:  */
        !           347: static void
        !           348: dumbclock_poll(
        !           349:        int unit,
        !           350:        struct peer *peer
        !           351:        )
        !           352: {
        !           353:        register struct dumbclock_unit *up;
        !           354:        struct refclockproc *pp;
        !           355:        char pollchar;
        !           356: 
        !           357:        /*
        !           358:         * Time to poll the clock. The Chrono-log clock is supposed to
        !           359:         * respond to a 'T' by returning a timecode in the format(s)
        !           360:         * specified above.  Ours does (can?) not, but this seems to be
        !           361:         * an installation-specific problem.  This code is dyked out,
        !           362:         * but may be re-enabled if anyone ever finds a Chrono-log that
        !           363:         * actually listens to this command.
        !           364:         */
        !           365: #if 0
        !           366:        pp = peer->procptr;
        !           367:        up = (struct dumbclock_unit *)pp->unitptr;
        !           368:        if (peer->reach == 0)
        !           369:                refclock_report(peer, CEVNT_TIMEOUT);
        !           370:        if (up->linect > 0)
        !           371:                pollchar = 'R';
        !           372:        else
        !           373:                pollchar = 'T';
        !           374:        if (write(pp->io.fd, &pollchar, 1) != 1)
        !           375:                refclock_report(peer, CEVNT_FAULT);
        !           376:        else
        !           377:                pp->polls++;
        !           378: #endif
        !           379: }
        !           380: #endif
        !           381: 
        !           382: #else
        !           383: int refclock_dumbclock_bs;
        !           384: #endif /* defined(REFCLOCK) && defined(CLOCK_DUMBCLOCK) */

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