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