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

1.1       misho       1: /*
                      2:  * refclock_acts - clock driver for the NIST/USNO/PTB/NPL Computer Time
                      3:  *     Services
                      4:  */
                      5: #ifdef HAVE_CONFIG_H
                      6: #include <config.h>
                      7: #endif
                      8: 
                      9: #if defined(REFCLOCK) && (defined(CLOCK_ACTS) || defined(CLOCK_PTBACTS))
                     10: 
                     11: #include "ntpd.h"
                     12: #include "ntp_io.h"
                     13: #include "ntp_unixtime.h"
                     14: #include "ntp_refclock.h"
                     15: #include "ntp_stdlib.h"
                     16: #include "ntp_control.h"
                     17: 
                     18: #include <stdio.h>
                     19: #include <ctype.h>
                     20: #ifdef HAVE_SYS_IOCTL_H
                     21: # include <sys/ioctl.h>
                     22: #endif /* HAVE_SYS_IOCTL_H */
                     23: 
                     24: /*
                     25:  * This driver supports the US (NIST, USNO) and European (PTB, NPL,
                     26:  * etc.) modem time services, as well as Spectracom GPS and WWVB
                     27:  * receivers connected via a modem. The driver periodically dials a
                     28:  * number from a telephone list, receives the timecode data and
                     29:  * calculates the local clock correction. It is designed primarily for
                     30:  * use as backup when neither a radio clock nor connectivity to Internet
                     31:  * time servers is available.
                     32:  *
                     33:  * This driver requires a modem with a Hayes-compatible command set and
                     34:  * control over the modem data terminal ready (DTR) control line. The
                     35:  * modem setup string is hard-coded in the driver and may require
                     36:  * changes for nonstandard modems or special circumstances. For reasons
                     37:  * unrelated to this driver, the data set ready (DSR) control line
                     38:  * should not be set when this driver is first started.
                     39:  *
                     40:  * The calling program is initiated by setting fudge flag1, either
                     41:  * manually or automatically. When flag1 is set, the calling program
                     42:  * dials the first number in the phone command of the configuration
                     43:  * file. If that call fails, the calling program dials the second number
                     44:  * and so on. The number is specified by the Hayes ATDT prefix followed
                     45:  * by the number itself, including the prefix and long-distance digits
                     46:  * and delay code, if necessary. The flag1 is reset and the calling
                     47:  * program terminated if (a) a valid clock update has been determined,
                     48:  * (b) no more numbers remain in the list, (c) a device fault or timeout
                     49:  * occurs or (d) fudge flag1 is reset manually.
                     50:  *
                     51:  * The driver is transparent to each of the modem time services and
                     52:  * Spectracom radios. It selects the parsing algorithm depending on the
                     53:  * message length. There is some hazard should the message be corrupted.
                     54:  * However, the data format is checked carefully and only if all checks
                     55:  * succeed is the message accepted. Corrupted lines are discarded
                     56:  * without complaint.
                     57:  *
                     58:  * Fudge controls
                     59:  *
                     60:  * flag1       force a call in manual mode
                     61:  * flag2       enable port locking (not verified)
                     62:  * flag3       no modem; port is directly connected to device
                     63:  * flag4       not used
                     64:  *
                     65:  * time1       offset adjustment (s)
                     66:  *
                     67:  * Ordinarily, the serial port is connected to a modem; however, it can
                     68:  * be connected directly to a device or another computer for testing and
                     69:  * calibration. In this case set fudge flag3 and the driver will send a
                     70:  * single character 'T' at each poll event. In principle, fudge flag2
                     71:  * enables port locking, allowing the modem to be shared when not in use
                     72:  * by this driver. At least on Solaris with the current NTP I/O
                     73:  * routines, this results only in lots of ugly error messages.
                     74:  */
                     75: /*
                     76:  * National Institute of Science and Technology (NIST)
                     77:  *
                     78:  * Phone: (303) 494-4774 (Boulder, CO); (808) 335-4721 (Hawaii)
                     79:  *
                     80:  * Data Format
                     81:  *
                     82:  * National Institute of Standards and Technology
                     83:  * Telephone Time Service, Generator 3B
                     84:  * Enter question mark "?" for HELP
                     85:  *                         D  L D
                     86:  *  MJD  YR MO DA H  M  S  ST S UT1 msADV        <OTM>
                     87:  * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) *<CR><LF>
                     88:  * ...
                     89:  *
                     90:  * MJD, DST, DUT1 and UTC are not used by this driver. The "*" or "#" is
                     91:  * the on-time markers echoed by the driver and used by NIST to measure
                     92:  * and correct for the propagation delay.
                     93:  *
                     94:  * US Naval Observatory (USNO)
                     95:  *
                     96:  * Phone: (202) 762-1594 (Washington, DC); (719) 567-6742 (Boulder, CO)
                     97:  *
                     98:  * Data Format (two lines, repeating at one-second intervals)
                     99:  *
                    100:  * jjjjj nnn hhmmss UTC<CR><LF>
                    101:  * *<CR><LF>
                    102:  *
                    103:  * jjjjj       modified Julian day number (not used)
                    104:  * nnn         day of year
                    105:  * hhmmss      second of day
                    106:  * *           on-time marker for previous timecode
                    107:  * ...
                    108:  *
                    109:  * USNO does not correct for the propagation delay. A fudge time1 of
                    110:  * about .06 s is advisable.
                    111:  *
                    112:  * European Services (PTB, NPL, etc.)
                    113:  *
                    114:  * PTB: +49 531 512038 (Germany)
                    115:  * NPL: 0906 851 6333 (UK only)
                    116:  *
                    117:  * Data format (see the documentation for phone numbers and formats.)
                    118:  *
                    119:  * 1995-01-23 20:58:51 MEZ  10402303260219950123195849740+40000500<CR><LF>
                    120:  *
                    121:  * Spectracom GPS and WWVB Receivers
                    122:  *
                    123:  * If a modem is connected to a Spectracom receiver, this driver will
                    124:  * call it up and retrieve the time in one of two formats. As this
                    125:  * driver does not send anything, the radio will have to either be
                    126:  * configured in continuous mode or be polled by another local driver.
                    127:  */
                    128: /*
                    129:  * Interface definitions
                    130:  */
                    131: #define        DEVICE          "/dev/acts%d" /* device name and unit */
                    132: #define        SPEED232        B9600   /* uart speed (9600 baud) */
                    133: #define        PRECISION       (-10)   /* precision assumed (about 1 ms) */
                    134: #define LOCKFILE       "/var/spool/locks/LCK..cua%d"
                    135: #define DESCRIPTION    "Automated Computer Time Service" /* WRU */
                    136: #define REFID          "NONE"  /* default reference ID */
                    137: #define MSGCNT         20      /* max message count */
                    138: #define SMAX           256     /* max clockstats line length */
                    139: #define        MAXPHONE        10      /* max number of phone numbers */
                    140: 
                    141: /*
                    142:  * Calling program modes
                    143:  */
                    144: #define MODE_AUTO      0       /* automatic mode */
                    145: #define MODE_BACKUP    1       /* backup mode */
                    146: #define MODE_MANUAL    2       /* manual mode */
                    147: 
                    148: /*
                    149:  * Service identifiers.
                    150:  */
                    151: #define REFACTS                "NIST"  /* NIST reference ID */
                    152: #define LENACTS                50      /* NIST format */
                    153: #define REFUSNO                "USNO"  /* USNO reference ID */
                    154: #define LENUSNO                20      /* USNO */
                    155: #define REFPTB         "PTB\0" /* PTB/NPL reference ID */
                    156: #define LENPTB         78      /* PTB/NPL format */
                    157: #define REFWWVB                "WWVB"  /* WWVB reference ID */
                    158: #define        LENWWVB0        22      /* WWVB format 0 */
                    159: #define        LENWWVB2        24      /* WWVB format 2 */
                    160: #define LF             0x0a    /* ASCII LF */
                    161: 
                    162: /*
                    163:  * Modem setup strings. These may have to be changed for some modems.
                    164:  *
                    165:  * AT  command prefix
                    166:  * B1  US answer tone
                    167:  * &C0 disable carrier detect
                    168:  * &D2 hang up and return to command mode on DTR transition
                    169:  * E0  modem command echo disabled
                    170:  * l1  set modem speaker volume to low level
                    171:  * M1  speaker enabled until carrier detect
                    172:  * Q0  return result codes
                    173:  * V1  return result codes as English words
                    174:  */
                    175: #define MODEM_SETUP    "ATB1&C0&D2E0L1M1Q0V1\r" /* modem setup */
                    176: #define MODEM_HANGUP   "ATH\r" /* modem disconnect */
                    177: 
                    178: /*
                    179:  * Timeouts (all in seconds)
                    180:  */
                    181: #define SETUP          3       /* setup timeout */
                    182: #define        DTR             1       /* DTR timeout */
                    183: #define ANSWER         60      /* answer timeout */
                    184: #define CONNECT                20      /* first valid message timeout */
                    185: #define TIMECODE       30      /* all valid messages timeout */
                    186: 
                    187: /*
                    188:  * State machine codes
                    189:  */
                    190: #define S_IDLE         0       /* wait for poll */
                    191: #define S_OK           1       /* wait for modem setup */
                    192: #define S_DTR          2       /* wait for modem DTR */
                    193: #define S_CONNECT      3       /* wait for answer*/
                    194: #define S_FIRST                4       /* wait for first valid message */
                    195: #define S_MSG          5       /* wait for all messages */
                    196: #define S_CLOSE                6       /* wait after sending disconnect */
                    197: 
                    198: /*
                    199:  * Unit control structure
                    200:  */
                    201: struct actsunit {
                    202:        int     unit;           /* unit number */
                    203:        int     state;          /* the first one was Delaware */
                    204:        int     timer;          /* timeout counter */
                    205:        int     retry;          /* retry index */
                    206:        int     msgcnt;         /* count of messages received */
                    207:        l_fp    tstamp;         /* on-time timestamp */
                    208:        char    *bufptr;        /* buffer pointer */
                    209: };
                    210: 
                    211: /*
                    212:  * Function prototypes
                    213:  */
                    214: static int     acts_start      (int, struct peer *);
                    215: static void    acts_shutdown   (int, struct peer *);
                    216: static void    acts_receive    (struct recvbuf *);
                    217: static void    acts_message    (struct peer *);
                    218: static void    acts_timecode   (struct peer *, char *);
                    219: static void    acts_poll       (int, struct peer *);
                    220: static void    acts_timeout    (struct peer *);
                    221: static void    acts_disc       (struct peer *);
                    222: static void    acts_timer      (int, struct peer *);
                    223: 
                    224: /*
                    225:  * Transfer vector (conditional structure name)
                    226:  */
                    227: struct refclock refclock_acts = {
                    228:        acts_start,             /* start up driver */
                    229:        acts_shutdown,          /* shut down driver */
                    230:        acts_poll,              /* transmit poll message */
                    231:        noentry,                /* not used */
                    232:        noentry,                /* not used */
                    233:        noentry,                /* not used */
                    234:        acts_timer              /* housekeeping timer */
                    235: };
                    236: 
                    237: /*
                    238:  * Initialize data for processing
                    239:  */
                    240: static int
                    241: acts_start (
                    242:        int     unit,
                    243:        struct peer *peer
                    244:        )
                    245: {
                    246:        struct actsunit *up;
                    247:        struct refclockproc *pp;
                    248: 
                    249:        /*
                    250:         * Allocate and initialize unit structure
                    251:         */
                    252:        up = emalloc(sizeof(struct actsunit));
                    253:        memset(up, 0, sizeof(struct actsunit));
                    254:        up->unit = unit;
                    255:        pp = peer->procptr;
                    256:        pp->unitptr = (caddr_t)up;
                    257:        pp->io.clock_recv = acts_receive;
                    258:        pp->io.srcclock = (caddr_t)peer;
                    259:        pp->io.datalen = 0;
                    260: 
                    261:        /*
                    262:         * Initialize miscellaneous variables
                    263:         */
                    264:        peer->precision = PRECISION;
                    265:        pp->clockdesc = DESCRIPTION;
                    266:        memcpy((char *)&pp->refid, REFID, 4);
                    267:        peer->sstclktype = CTL_SST_TS_TELEPHONE;
                    268:        up->bufptr = pp->a_lastcode;
                    269:        return (1);
                    270: }
                    271: 
                    272: 
                    273: /*
                    274:  * acts_shutdown - shut down the clock
                    275:  */
                    276: static void
                    277: acts_shutdown (
                    278:        int     unit,
                    279:        struct peer *peer
                    280:        )
                    281: {
                    282:        struct actsunit *up;
                    283:        struct refclockproc *pp;
                    284: 
                    285:        /*
                    286:         * Warning: do this only when a call is not in progress.
                    287:         */
                    288:        pp = peer->procptr;
                    289:        up = (struct actsunit *)pp->unitptr;
                    290:        free(up);
                    291: }
                    292: 
                    293: 
                    294: /*
                    295:  * acts_receive - receive data from the serial interface
                    296:  */
                    297: static void
                    298: acts_receive (
                    299:        struct recvbuf *rbufp
                    300:        )
                    301: {
                    302:        struct actsunit *up;
                    303:        struct refclockproc *pp;
                    304:        struct peer *peer;
                    305:        char    tbuf[BMAX];
                    306:        char    *tptr;
                    307: 
                    308:        /*
                    309:         * Initialize pointers and read the timecode and timestamp. Note
                    310:         * we are in raw mode and victim of whatever the terminal
                    311:         * interface kicks up; so, we have to reassemble messages from
                    312:         * arbitrary fragments. Capture the timecode at the beginning of
                    313:         * the message and at the '*' and '#' on-time characters.
                    314:         */
                    315:        peer = (struct peer *)rbufp->recv_srcclock;
                    316:        pp = peer->procptr;
                    317:        up = (struct actsunit *)pp->unitptr;
                    318:        pp->lencode = refclock_gtraw(rbufp, tbuf, BMAX - (up->bufptr -
                    319:            pp->a_lastcode), &pp->lastrec);
                    320:        for (tptr = tbuf; *tptr != '\0'; tptr++) {
                    321:                if (*tptr == LF) {
                    322:                        if (up->bufptr == pp->a_lastcode) {
                    323:                                up->tstamp = pp->lastrec;
                    324:                                continue;
                    325: 
                    326:                        } else {
                    327:                                *up->bufptr = '\0';
                    328:                                acts_message(peer);
                    329:                                up->bufptr = pp->a_lastcode;
                    330:                        }
                    331:                } else if (!iscntrl(*tptr)) {
                    332:                        *up->bufptr++ = *tptr;
                    333:                        if (*tptr == '*' || *tptr == '#') {
                    334:                                up->tstamp = pp->lastrec;
                    335:                                write(pp->io.fd, tptr, 1);
                    336:                        }
                    337:                }
                    338:        }
                    339: }
                    340: 
                    341: 
                    342: /*
                    343:  * acts_message - process message
                    344:  */
                    345: void
                    346: acts_message(
                    347:        struct peer *peer
                    348:        )
                    349: {
                    350:        struct actsunit *up;
                    351:        struct refclockproc *pp;
                    352:        int     dtr = TIOCM_DTR;
                    353:        char    tbuf[SMAX];
                    354: #ifdef DEBUG
                    355:        u_int   modem;
                    356: #endif
                    357: 
                    358:        /*
                    359:         * What to do depends on the state and the first token in the
                    360:         * message.      */
                    361:        pp = peer->procptr;
                    362:        up = (struct actsunit *)pp->unitptr;
                    363: #ifdef DEBUG
                    364:        ioctl(pp->io.fd, TIOCMGET, (char *)&modem);
                    365:        snprintf(tbuf, sizeof(tbuf), "acts: %04x (%d %d) %lu %s", modem,
                    366:                 up->state, up->timer, (u_long)strlen(pp->a_lastcode),
                    367:                 pp->a_lastcode);
                    368:        if (debug)
                    369:                printf("%s\n", tbuf);
                    370: #endif
                    371: 
                    372:        /*
                    373:         * Extract the first token in the line. A NO token sends the
                    374:         * message to the clockstats.
                    375:         */
                    376:        strncpy(tbuf, pp->a_lastcode, SMAX);
                    377:        strtok(tbuf, " ");
                    378:        if (strcmp(tbuf, "NO") == 0) {
                    379:                report_event(PEVNT_CLOCK, peer, pp->a_lastcode);
                    380:                return;
                    381:        }
                    382:        switch(up->state) {
                    383: 
                    384:        /*
                    385:         * We are waiting for the OK response to the modem setup
                    386:         * command. When this happens, raise DTR and dial the number
                    387:         * followed by \r.
                    388:         */
                    389:        case S_OK:
                    390:                if (strcmp(tbuf, "OK") != 0) {
                    391:                        msyslog(LOG_ERR, "acts: setup error %s",
                    392:                            pp->a_lastcode);
                    393:                        acts_disc(peer);
                    394:                        return;
                    395:                }
                    396:                ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr);
                    397:                up->state = S_DTR;
                    398:                up->timer = DTR;
                    399:                return;
                    400: 
                    401:        /*
                    402:         * We are waiting for the call to be answered. All we care about
                    403:         * here is token CONNECT. Send the message to the clockstats.
                    404:         */
                    405:        case S_CONNECT:
                    406:                report_event(PEVNT_CLOCK, peer, pp->a_lastcode);
                    407:                if (strcmp(tbuf, "CONNECT") != 0) {
                    408:                        acts_disc(peer);
                    409:                        return;
                    410:                }
                    411:                up->state = S_FIRST;
                    412:                up->timer = CONNECT;
                    413:                return;
                    414: 
                    415:        /*
                    416:         * We are waiting for a timecode. Pass it to the parser.
                    417:         */
                    418:        case S_FIRST:
                    419:        case S_MSG:
                    420:                acts_timecode(peer, pp->a_lastcode);
                    421:                break;
                    422:        }
                    423: }
                    424: 
                    425: /*
                    426:  * acts_timecode - identify the service and parse the timecode message
                    427:  */
                    428: void
                    429: acts_timecode(
                    430:        struct peer *peer,      /* peer structure pointer */
                    431:        char    *str            /* timecode string */
                    432:        )
                    433: {
                    434:        struct actsunit *up;
                    435:        struct refclockproc *pp;
                    436:        int     day;            /* day of the month */
                    437:        int     month;          /* month of the year */
                    438:        u_long  mjd;            /* Modified Julian Day */
                    439:        double  dut1;           /* DUT adjustment */
                    440: 
                    441:        u_int   dst;            /* ACTS daylight/standard time */
                    442:        u_int   leap;           /* ACTS leap indicator */
                    443:        double  msADV;          /* ACTS transmit advance (ms) */
                    444:        char    utc[10];        /* ACTS timescale */
                    445:        char    flag;           /* ACTS on-time character (* or #) */
                    446: 
                    447:        char    synchar;        /* WWVB synchronized indicator */
                    448:        char    qualchar;       /* WWVB quality indicator */
                    449:        char    leapchar;       /* WWVB leap indicator */
                    450:        char    dstchar;        /* WWVB daylight/savings indicator */
                    451:        int     tz;             /* WWVB timezone */
                    452: 
                    453:        u_int   leapmonth;      /* PTB/NPL month of leap */
                    454:        char    leapdir;        /* PTB/NPL leap direction */
                    455: 
                    456:        /*
                    457:         * The parser selects the modem format based on the message
                    458:         * length. Since the data are checked carefully, occasional
                    459:         * errors due noise are forgivable.
                    460:         */
                    461:        pp = peer->procptr;
                    462:        up = (struct actsunit *)pp->unitptr;
                    463:        pp->nsec = 0;
                    464:        switch(strlen(str)) {
                    465: 
                    466:        /*
                    467:         * For USNO format on-time character '*', which is on a line by
                    468:         * itself. Be sure a timecode has been received.
                    469:         */
                    470:        case 1:
                    471:                if (*str == '*' && up->msgcnt > 0) 
                    472:                        break;
                    473: 
                    474:                return;
                    475:        
                    476:        /*
                    477:         * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa
                    478:         * UTC(NIST) *"
                    479:         */
                    480:        case LENACTS:
                    481:                if (sscanf(str,
                    482:                    "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c",
                    483:                    &mjd, &pp->year, &month, &day, &pp->hour,
                    484:                    &pp->minute, &pp->second, &dst, &leap, &dut1,
                    485:                    &msADV, utc, &flag) != 13) {
                    486:                        refclock_report(peer, CEVNT_BADREPLY);
                    487:                        return;
                    488:                }
                    489: 
                    490:                /*
                    491:                 * Wait until ACTS has calculated the roundtrip delay.
                    492:                 * We don't need to do anything, as ACTS adjusts the
                    493:                 * on-time epoch.
                    494:                 */
                    495:                if (flag != '#')
                    496:                        return;
                    497: 
                    498:                pp->day = ymd2yd(pp->year, month, day);
                    499:                pp->leap = LEAP_NOWARNING;
                    500:                if (leap == 1)
                    501:                        pp->leap = LEAP_ADDSECOND;
                    502:                else if (pp->leap == 2)
                    503:                        pp->leap = LEAP_DELSECOND;
                    504:                memcpy(&pp->refid, REFACTS, 4);
                    505:                if (up->msgcnt == 0)
                    506:                        record_clock_stats(&peer->srcadr, str);
                    507:                up->msgcnt++;
                    508:                break;
                    509: 
                    510:        /*
                    511:         * USNO format: "jjjjj nnn hhmmss UTC"
                    512:         */
                    513:        case LENUSNO:
                    514:                if (sscanf(str, "%5ld %3d %2d%2d%2d %3s",
                    515:                    &mjd, &pp->day, &pp->hour, &pp->minute,
                    516:                    &pp->second, utc) != 6) {
                    517:                        refclock_report(peer, CEVNT_BADREPLY);
                    518:                        return;
                    519:                }
                    520: 
                    521:                /*
                    522:                 * Wait for the on-time character, which follows in a
                    523:                 * separate message. There is no provision for leap
                    524:                 * warning.
                    525:                 */
                    526:                pp->leap = LEAP_NOWARNING;
                    527:                memcpy(&pp->refid, REFUSNO, 4);
                    528:                if (up->msgcnt == 0)
                    529:                        record_clock_stats(&peer->srcadr, str);
                    530:                up->msgcnt++;
                    531:                return;
                    532: 
                    533:        /*
                    534:         * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ" 
                    535:         */
                    536:        case LENPTB:
                    537:                if (sscanf(str,
                    538:                    "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c",
                    539:                    &pp->second, &pp->year, &month, &day, &pp->hour,
                    540:                    &pp->minute, &mjd, &dut1, &leapdir, &leapmonth,
                    541:                    &msADV, &flag) != 12) {
                    542:                        refclock_report(peer, CEVNT_BADREPLY);
                    543:                        return;
                    544:                }
                    545:                pp->leap = LEAP_NOWARNING;
                    546:                if (leapmonth == month) {
                    547:                        if (leapdir == '+')
                    548:                                pp->leap = LEAP_ADDSECOND;
                    549:                        else if (leapdir == '-')
                    550:                                pp->leap = LEAP_DELSECOND;
                    551:                }
                    552:                pp->day = ymd2yd(pp->year, month, day);
                    553:                memcpy(&pp->refid, REFPTB, 4);
                    554:                if (up->msgcnt == 0)
                    555:                        record_clock_stats(&peer->srcadr, str);
                    556:                up->msgcnt++;
                    557:                break;
                    558: 
                    559: 
                    560:        /*
                    561:         * WWVB format 0: "I  ddd hh:mm:ss DTZ=nn"
                    562:         */
                    563:        case LENWWVB0:
                    564:                if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d",
                    565:                    &synchar, &pp->day, &pp->hour, &pp->minute,
                    566:                    &pp->second, &dstchar, &tz) != 7) {
                    567:                        refclock_report(peer, CEVNT_BADREPLY);
                    568:                        return;
                    569:                }
                    570:                pp->leap = LEAP_NOWARNING;
                    571:                if (synchar != ' ')
                    572:                        pp->leap = LEAP_NOTINSYNC;
                    573:                memcpy(&pp->refid, REFWWVB, 4);
                    574:                if (up->msgcnt == 0)
                    575:                        record_clock_stats(&peer->srcadr, str);
                    576:                up->msgcnt++;
                    577:                break;
                    578: 
                    579:        /*
                    580:         * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD"
                    581:         */
                    582:        case LENWWVB2:
                    583:                if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c",
                    584:                    &synchar, &qualchar, &pp->year, &pp->day,
                    585:                    &pp->hour, &pp->minute, &pp->second, &pp->nsec,
                    586:                    &dstchar, &leapchar, &dstchar) != 11) {
                    587:                        refclock_report(peer, CEVNT_BADREPLY);
                    588:                        return;
                    589:                }
                    590:                pp->nsec *= 1000000;
                    591:                pp->leap = LEAP_NOWARNING;
                    592:                if (synchar != ' ')
                    593:                        pp->leap = LEAP_NOTINSYNC;
                    594:                else if (leapchar == 'L')
                    595:                        pp->leap = LEAP_ADDSECOND;
                    596:                memcpy(&pp->refid, REFWWVB, 4);
                    597:                if (up->msgcnt == 0)
                    598:                        record_clock_stats(&peer->srcadr, str);
                    599:                up->msgcnt++;
                    600:                break;
                    601: 
                    602:        /*
                    603:         * None of the above. Just forget about it and wait for the next
                    604:         * message or timeout.
                    605:         */
                    606:        default:
                    607:                return;
                    608:        }
                    609: 
                    610:        /*
                    611:         * We have a valid timecode. The fudge time1 value is added to
                    612:         * each sample by the main line routines. Note that in current
                    613:         * telephone networks the propatation time can be different for
                    614:         * each call and can reach 200 ms for some calls.
                    615:         */
                    616:        peer->refid = pp->refid;
                    617:        pp->lastrec = up->tstamp;
                    618:        if (!refclock_process(pp)) {
                    619:                refclock_report(peer, CEVNT_BADTIME);
                    620:                return;
                    621:        }
                    622:        pp->lastref = pp->lastrec;
                    623:        if (up->state != S_MSG) {
                    624:                up->state = S_MSG;
                    625:                up->timer = TIMECODE;
                    626:        }
                    627: }
                    628: 
                    629: 
                    630: /*
                    631:  * acts_poll - called by the transmit routine
                    632:  */
                    633: static void
                    634: acts_poll (
                    635:        int     unit,
                    636:        struct peer *peer
                    637:        )
                    638: {
                    639:        struct actsunit *up;
                    640:        struct refclockproc *pp;
                    641: 
                    642:        /*
                    643:         * This routine is called at every system poll. All it does is
                    644:         * set flag1 under certain conditions. The real work is done by
                    645:         * the timeout routine and state machine.
                    646:         */
                    647:        pp = peer->procptr;
                    648:        up = (struct actsunit *)pp->unitptr;
                    649:        switch (peer->ttl) {
                    650: 
                    651:        /*
                    652:         * In manual mode the calling program is activated by the ntpdc
                    653:         * program using the enable flag (fudge flag1), either manually
                    654:         * or by a cron job.
                    655:         */
                    656:        case MODE_MANUAL:
                    657:                /* fall through */
                    658:                break;
                    659: 
                    660:        /*
                    661:         * In automatic mode the calling program runs continuously at
                    662:         * intervals determined by the poll event or specified timeout.
                    663:         */
                    664:        case MODE_AUTO:
                    665:                pp->sloppyclockflag |= CLK_FLAG1;
                    666:                break;
                    667: 
                    668:        /*
                    669:         * In backup mode the calling program runs continuously as long
                    670:         * as either no peers are available or this peer is selected.
                    671:         */
                    672:        case MODE_BACKUP:
                    673:                if (sys_peer == NULL || sys_peer == peer)
                    674:                        pp->sloppyclockflag |= CLK_FLAG1;
                    675:                break;
                    676:        }
                    677: }
                    678: 
                    679: 
                    680: /*
                    681:  * acts_timer - called at one-second intervals
                    682:  */
                    683: static void
                    684: acts_timer(
                    685:        int     unit,
                    686:        struct peer *peer
                    687:        )
                    688: {
                    689:        struct actsunit *up;
                    690:        struct refclockproc *pp;
                    691: 
                    692:        /*
                    693:         * This routine implments a timeout which runs for a programmed
                    694:         * interval. The counter is initialized by the state machine and
                    695:         * counts down to zero. Upon reaching zero, the state machine is
                    696:         * called. If flag1 is set while in S_IDLE state, force a
                    697:         * timeout.
                    698:         */
                    699:        pp = peer->procptr;
                    700:        up = (struct actsunit *)pp->unitptr;
                    701:        if (pp->sloppyclockflag & CLK_FLAG1 && up->state == S_IDLE) {
                    702:                acts_timeout(peer);
                    703:                return;
                    704:        }
                    705:        if (up->timer == 0)
                    706:                return;
                    707: 
                    708:        up->timer--;
                    709:        if (up->timer == 0)
                    710:                acts_timeout(peer);
                    711: }
                    712: 
                    713: 
                    714: /*
                    715:  * acts_timeout - called on timeout
                    716:  */
                    717: static void
                    718: acts_timeout(
                    719:        struct peer *peer
                    720:        )
                    721: {
                    722:        struct actsunit *up;
                    723:        struct refclockproc *pp;
                    724:        int     fd;
                    725:        char    device[20];
                    726:        char    lockfile[128], pidbuf[8];
                    727:        char    tbuf[SMAX];
                    728: 
                    729:        /*
                    730:         * The state machine is driven by messages from the modem, when
                    731:         * first stated and at timeout.
                    732:         */
                    733:        pp = peer->procptr;
                    734:        up = (struct actsunit *)pp->unitptr;
                    735:        pp->sloppyclockflag &= ~CLK_FLAG1;
                    736:        if (sys_phone[up->retry] == NULL && !(pp->sloppyclockflag &
                    737:            CLK_FLAG3)) {
                    738:                msyslog(LOG_ERR, "acts: no phones");
                    739:                return;
                    740:        }
                    741:        switch(up->state) {
                    742: 
                    743:        /*
                    744:         * System poll event. Lock the modem port and open the device.
                    745:         */
                    746:        case S_IDLE:
                    747: 
                    748:                /*
                    749:                 * Lock the modem port. If busy, retry later. Note: if
                    750:                 * something fails between here and the close, the lock
                    751:                 * file may not be removed.
                    752:                 */
                    753:                if (pp->sloppyclockflag & CLK_FLAG2) {
                    754:                        snprintf(lockfile, sizeof(lockfile), LOCKFILE,
                    755:                            up->unit);
                    756:                        fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
                    757:                            0644);
                    758:                        if (fd < 0) {
                    759:                                msyslog(LOG_ERR, "acts: port busy");
                    760:                                return;
                    761:                        }
                    762:                        snprintf(pidbuf, sizeof(pidbuf), "%d\n",
                    763:                            (u_int)getpid());
                    764:                        write(fd, pidbuf, strlen(pidbuf));
                    765:                        close(fd);
                    766:                }
                    767: 
                    768:                /*
                    769:                 * Open the device in raw mode and link the I/O.
                    770:                 */
                    771:                if (!pp->io.fd) {
                    772:                        snprintf(device, sizeof(device), DEVICE,
                    773:                            up->unit);
                    774:                        fd = refclock_open(device, SPEED232,
                    775:                            LDISC_ACTS | LDISC_RAW | LDISC_REMOTE);
                    776:                        if (fd == 0) {
                    777:                                msyslog(LOG_ERR,
                    778:                                    "acts: open fails");
                    779:                                return;
                    780:                        }
                    781:                        pp->io.fd = fd;
                    782:                        if (!io_addclock(&pp->io)) {
                    783:                                msyslog(LOG_ERR,
                    784:                                    "acts: addclock fails");
                    785:                                close(fd);
                    786:                                pp->io.fd = 0;
                    787:                                return;
                    788:                        }
                    789:                }
                    790: 
                    791:                /*
                    792:                 * If the port is directly connected to the device, skip
                    793:                 * the modem business and send 'T' for Spectrabum.
                    794:                 */
                    795:                if (pp->sloppyclockflag & CLK_FLAG3) {
                    796:                        if (write(pp->io.fd, "T", 1) < 0) {
                    797:                                msyslog(LOG_ERR, "acts: write %m");
                    798:                                return;
                    799:                        }
                    800:                        up->state = S_FIRST;
                    801:                        up->timer = CONNECT;
                    802:                        return;
                    803:                }
                    804: 
                    805:                /*
                    806:                 * Initialize the modem. This works with Hayes commands.
                    807:                 */
                    808: #ifdef DEBUG
                    809:                if (debug)
                    810:                        printf("acts: setup %s\n", MODEM_SETUP);
                    811: #endif
                    812:                if (write(pp->io.fd, MODEM_SETUP, strlen(MODEM_SETUP)) <
                    813:                    0) {
                    814:                        msyslog(LOG_ERR, "acts: write %m");
                    815:                        return;
                    816:                }
                    817:                up->state = S_OK;
                    818:                up->timer = SETUP;
                    819:                return;
                    820: 
                    821:        /*
                    822:         * In OK state the modem did not respond to setup.
                    823:         */
                    824:        case S_OK:
                    825:                msyslog(LOG_ERR, "acts: no modem");
                    826:                break;
                    827: 
                    828:        /*
                    829:         * In DTR state we are waiting for the modem to settle down
                    830:         * before hammering it with a dial command.
                    831:         */
                    832:        case S_DTR:
                    833:                snprintf(tbuf, sizeof(tbuf), "DIAL #%d %s", up->retry,
                    834:                    sys_phone[up->retry]);
                    835:                report_event(PEVNT_CLOCK, peer, tbuf);
                    836: #ifdef DEBUG
                    837:                if (debug)
                    838:                        printf("%s\n", tbuf);
                    839: #endif
                    840:                write(pp->io.fd, sys_phone[up->retry],
                    841:                    strlen(sys_phone[up->retry]));
                    842:                write(pp->io.fd, "\r", 1);
                    843:                up->state = S_CONNECT;
                    844:                up->timer = ANSWER;
                    845:                return;
                    846: 
                    847:        /*
                    848:         * In CONNECT state the call did not complete.
                    849:         */
                    850:        case S_CONNECT:
                    851:                msyslog(LOG_ERR, "acts: no answer");
                    852:                break;
                    853: 
                    854:        /*
                    855:         * In FIRST state no messages were received.
                    856:         */
                    857:        case S_FIRST:
                    858:                msyslog(LOG_ERR, "acts: no messages");
                    859:                break;
                    860: 
                    861:        /*
                    862:         * In CLOSE state hangup is complete. Close the doors and
                    863:         * windows and get some air.
                    864:         */
                    865:        case S_CLOSE:
                    866: 
                    867:                /*
                    868:                 * Close the device and unlock a shared modem.
                    869:                 */
                    870:                if (pp->io.fd) {
                    871:                        io_closeclock(&pp->io);
                    872:                        close(pp->io.fd);
                    873:                        if (pp->sloppyclockflag & CLK_FLAG2) {
                    874:                                snprintf(lockfile, sizeof(lockfile),
                    875:                                    LOCKFILE, up->unit);
                    876:                                unlink(lockfile);
                    877:                        }
                    878:                        pp->io.fd = 0;
                    879:                }
                    880: 
                    881:                /*
                    882:                 * If messages were received, fold the tent and wait for
                    883:                 * the next poll. If no messages and there are more
                    884:                 * numbers to dial, retry after a short wait.
                    885:                 */
                    886:                up->bufptr = pp->a_lastcode;
                    887:                up->timer = 0;
                    888:                up->state = S_IDLE;
                    889:                if ( up->msgcnt == 0) {
                    890:                        up->retry++;
                    891:                        if (sys_phone[up->retry] == NULL)
                    892:                                up->retry = 0;
                    893:                        else
                    894:                                up->timer = SETUP;
                    895:                } else {
                    896:                        up->retry = 0;
                    897:                }
                    898:                up->msgcnt = 0;
                    899:                return;
                    900:        }
                    901:        acts_disc(peer);
                    902: }
                    903: 
                    904: 
                    905: /*
                    906:  * acts_disc - disconnect the call and clean the place up.
                    907:  */
                    908: static void
                    909: acts_disc (
                    910:        struct peer *peer
                    911:        )
                    912: {
                    913:        struct actsunit *up;
                    914:        struct refclockproc *pp;
                    915:        int     dtr = TIOCM_DTR;
                    916: 
                    917:        /*
                    918:         * We get here if the call terminated successfully or if an
                    919:         * error occured. If the median filter has something in it,
                    920:         * feed the data to the clock filter. If a modem port, drop DTR
                    921:         * to force command mode and send modem hangup.
                    922:         */
                    923:        pp = peer->procptr;
                    924:        up = (struct actsunit *)pp->unitptr;
                    925:        if (up->msgcnt > 0)
                    926:                refclock_receive(peer);
                    927:        if (!(pp->sloppyclockflag & CLK_FLAG3)) {
                    928:                ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr);
                    929:                write(pp->io.fd, MODEM_HANGUP, strlen(MODEM_HANGUP));
                    930:        }
                    931:        up->timer = SETUP;
                    932:        up->state = S_CLOSE;
                    933: }
                    934: #else
                    935: int refclock_acts_bs;
                    936: #endif /* REFCLOCK */

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