Annotation of embedaddon/ntp/util/tg.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * tg.c generate WWV or IRIG signals for test
        !             3:  */
        !             4: /*
        !             5:  * This program can generate audio signals that simulate the WWV/H
        !             6:  * broadcast timecode. Alternatively, it can generate the IRIG-B
        !             7:  * timecode commonly used to synchronize laboratory equipment. It is
        !             8:  * intended to test the WWV/H driver (refclock_wwv.c) and the IRIG
        !             9:  * driver (refclock_irig.c) in the NTP driver collection.
        !            10:  *
        !            11:  * Besides testing the drivers themselves, this program can be used to
        !            12:  * synchronize remote machines over audio transmission lines or program
        !            13:  * feeds. The program reads the time on the local machine and sets the
        !            14:  * initial epoch of the signal generator within one millisecond.
        !            15:  * Alernatively, the initial epoch can be set to an arbitrary time. This
        !            16:  * is useful when searching for bugs and testing for correct response to
        !            17:  * a leap second in UTC. Note however, the ultimate accuracy is limited
        !            18:  * by the intrinsic frequency error of the codec sample clock, which can
        !            19:  # reach well over 100 PPM.
        !            20:  *
        !            21:  * The default is to route generated signals to the line output
        !            22:  * jack; the s option on the command line routes these signals to the
        !            23:  * internal speaker as well. The v option controls the speaker volume
        !            24:  * over the range 0-255. The signal generator by default uses WWV
        !            25:  * format; the h option switches to WWVH format and the i option
        !            26:  * switches to IRIG-B format.
        !            27:  *
        !            28:  * Once started the program runs continuously. The default initial epoch
        !            29:  * for the signal generator is read from the computer system clock when
        !            30:  * the program starts. The y option specifies an alternate epoch using a
        !            31:  * string yydddhhmmss, where yy is the year of century, ddd the day of
        !            32:  * year, hh the hour of day and mm the minute of hour. For instance,
        !            33:  * 1946Z on 1 January 2006 is 060011946. The l option lights the leap
        !            34:  * warning bit in the WWV/H timecode, so is handy to check for correct
        !            35:  * behavior at the next leap second epoch. The remaining options are
        !            36:  * specified below under the Parse Options heading. Most of these are
        !            37:  * for testing.
        !            38:  *
        !            39:  * During operation the program displays the WWV/H timecode (9 digits)
        !            40:  * or IRIG timecode (20 digits) as each new string is constructed. The
        !            41:  * display is followed by the BCD binary bits as transmitted. Note that
        !            42:  * the transmissionorder is low-order first as the frame is processed
        !            43:  * left to right. For WWV/H The leap warning L preceeds the first bit.
        !            44:  * For IRIG the on-time marker M preceeds the first (units) bit, so its
        !            45:  * code is delayed one bit and the next digit (tens) needs only three
        !            46:  * bits.
        !            47:  *
        !            48:  * The program has been tested with the Sun Blade 1500 running Solaris
        !            49:  * 10, but not yet with other machines. It uses no special features and
        !            50:  * should be readily portable to other hardware and operating systems.
        !            51:  */
        !            52: #include <stdio.h>
        !            53: #include <stdlib.h>
        !            54: #include <time.h>
        !            55: #include <sys/audio.h>
        !            56: #include <math.h>
        !            57: #include <errno.h>
        !            58: #include <sys/types.h>
        !            59: #include <sys/stat.h>
        !            60: #include <fcntl.h>
        !            61: #include <string.h>
        !            62: #include <unistd.h>
        !            63: 
        !            64: #define        SECOND  8000            /* one second of 125-us samples */
        !            65: #define BUFLNG 400             /* buffer size */
        !            66: #define        DEVICE  "/dev/audio"    /* default audio device */
        !            67: #define        WWV     0               /* WWV encoder */
        !            68: #define        IRIG    1               /* IRIG-B encoder */
        !            69: #define        OFF     0               /* zero amplitude */
        !            70: #define        LOW     1               /* low amplitude */
        !            71: #define        HIGH    2               /* high amplitude */
        !            72: #define        DATA0   200             /* WWV/H 0 pulse */
        !            73: #define        DATA1   500             /* WWV/H 1 pulse */
        !            74: #define PI     800             /* WWV/H PI pulse */
        !            75: #define        M2      2               /* IRIG 0 pulse */
        !            76: #define        M5      5               /* IRIG 1 pulse */
        !            77: #define        M8      8               /* IRIG PI pulse */
        !            78: 
        !            79: /*
        !            80:  * Companded sine table amplitude 3000 units
        !            81:  */
        !            82: int c3000[] = {1, 48, 63, 70, 78, 82, 85, 89, 92, 94,  /* 0-9 */
        !            83:      96,  98,  99, 100, 101, 101, 102, 103, 103, 103,  /* 10-19 */
        !            84:     103, 103, 103, 103, 102, 101, 101, 100,  99,  98,  /* 20-29 */
        !            85:      96,  94,  92,  89,  85,  82,  78,  70,  63,  48,  /* 30-39 */
        !            86:     129, 176, 191, 198, 206, 210, 213, 217, 220, 222,  /* 40-49 */
        !            87:     224, 226, 227, 228, 229, 229, 230, 231, 231, 231,  /* 50-59 */
        !            88:     231, 231, 231, 231, 230, 229, 229, 228, 227, 226,  /* 60-69 */
        !            89:     224, 222, 220, 217, 213, 210, 206, 198, 191, 176};         /* 70-79 */
        !            90: /*
        !            91:  * Companded sine table amplitude 6000 units
        !            92:  */
        !            93: int c6000[] = {1, 63, 78, 86, 93, 98, 101, 104, 107, 110, /* 0-9 */
        !            94:     112, 113, 115, 116, 117, 117, 118, 118, 119, 119,  /* 10-19 */
        !            95:     119, 119, 119, 118, 118, 117, 117, 116, 115, 113,  /* 20-29 */
        !            96:     112, 110, 107, 104, 101,  98,  93,  86,  78,  63,  /* 30-39 */
        !            97:     129, 191, 206, 214, 221, 226, 229, 232, 235, 238,  /* 40-49 */
        !            98:     240, 241, 243, 244, 245, 245, 246, 246, 247, 247,  /* 50-59 */
        !            99:     247, 247, 247, 246, 246, 245, 245, 244, 243, 241,  /* 60-69 */
        !           100:     240, 238, 235, 232, 229, 226, 221, 214, 206, 191};         /* 70-79 */
        !           101: 
        !           102: /*
        !           103:  * Decoder operations at the end of each second are driven by a state
        !           104:  * machine. The transition matrix consists of a dispatch table indexed
        !           105:  * by second number. Each entry in the table contains a case switch
        !           106:  * number and argument.
        !           107:  */
        !           108: struct progx {
        !           109:        int sw;                 /* case switch number */
        !           110:        int arg;                /* argument */
        !           111: };
        !           112: 
        !           113: /*
        !           114:  * Case switch numbers
        !           115:  */
        !           116: #define DATA   0               /* send data (0, 1, PI) */
        !           117: #define COEF   1               /* send BCD bit */
        !           118: #define        DEC     2               /* decrement to next digit */
        !           119: #define        MIN     3               /* minute pulse */
        !           120: #define        LEAP    4               /* leap warning */
        !           121: #define        DUT1    5               /* DUT1 bits */
        !           122: #define        DST1    6               /* DST1 bit */
        !           123: #define        DST2    7               /* DST2 bit */
        !           124: 
        !           125: /*
        !           126:  * WWV/H format (100-Hz, 9 digits, 1 m frame)
        !           127:  */
        !           128: struct progx progx[] = {
        !           129:        {MIN,   800},           /* 0 minute sync pulse */
        !           130:        {DATA,  DATA0},         /* 1 */
        !           131:        {DST2,  0},             /* 2 DST2 */
        !           132:        {LEAP,  0},             /* 3 leap warning */
        !           133:        {COEF,  1},             /* 4 1 year units */
        !           134:        {COEF,  2},             /* 5 2 */
        !           135:        {COEF,  4},             /* 6 4 */
        !           136:        {COEF,  8},             /* 7 8 */
        !           137:        {DEC,   DATA0},         /* 8 */
        !           138:        {DATA,  PI},            /* 9 p1 */
        !           139:        {COEF,  1},             /* 10 1 minute units */
        !           140:        {COEF,  2},             /* 11 2 */
        !           141:        {COEF,  4},             /* 12 4 */
        !           142:        {COEF,  8},             /* 13 8 */
        !           143:        {DEC,   DATA0},         /* 14 */
        !           144:        {COEF,  1},             /* 15 10 minute tens */
        !           145:        {COEF,  2},             /* 16 20 */
        !           146:        {COEF,  4},             /* 17 40 */
        !           147:        {COEF,  8},             /* 18 80 (not used) */
        !           148:        {DEC,   PI},            /* 19 p2 */
        !           149:        {COEF,  1},             /* 20 1 hour units */
        !           150:        {COEF,  2},             /* 21 2 */
        !           151:        {COEF,  4},             /* 22 4 */
        !           152:        {COEF,  8},             /* 23 8 */
        !           153:        {DEC,   DATA0},         /* 24 */
        !           154:        {COEF,  1},             /* 25 10 hour tens */
        !           155:        {COEF,  2},             /* 26 20 */
        !           156:        {COEF,  4},             /* 27 40 (not used) */
        !           157:        {COEF,  8},             /* 28 80 (not used) */
        !           158:        {DEC,   PI},            /* 29 p3 */
        !           159:        {COEF,  1},             /* 30 1 day units */
        !           160:        {COEF,  2},             /* 31 2 */
        !           161:        {COEF,  4},             /* 32 4 */
        !           162:        {COEF,  8},             /* 33 8 */
        !           163:        {DEC,   DATA0},         /* 34 not used */
        !           164:        {COEF,  1},             /* 35 10 day tens */
        !           165:        {COEF,  2},             /* 36 20 */
        !           166:        {COEF,  4},             /* 37 40 */
        !           167:        {COEF,  8},             /* 38 80 */
        !           168:        {DEC,   PI},            /* 39 p4 */
        !           169:        {COEF,  1},             /* 40 100 day hundreds */
        !           170:        {COEF,  2},             /* 41 200 */
        !           171:        {COEF,  4},             /* 42 400 (not used) */
        !           172:        {COEF,  8},             /* 43 800 (not used) */
        !           173:        {DEC,   DATA0},         /* 44 */
        !           174:        {DATA,  DATA0},         /* 45 */
        !           175:        {DATA,  DATA0},         /* 46 */
        !           176:        {DATA,  DATA0},         /* 47 */
        !           177:        {DATA,  DATA0},         /* 48 */
        !           178:        {DATA,  PI},            /* 49 p5 */
        !           179:        {DUT1,  8},             /* 50 DUT1 sign */
        !           180:        {COEF,  1},             /* 51 10 year tens */
        !           181:        {COEF,  2},             /* 52 20 */
        !           182:        {COEF,  4},             /* 53 40 */
        !           183:        {COEF,  8},             /* 54 80 */
        !           184:        {DST1,  0},             /* 55 DST1 */
        !           185:        {DUT1,  1},             /* 56 0.1 DUT1 fraction */
        !           186:        {DUT1,  2},             /* 57 0.2 */
        !           187:        {DUT1,  4},             /* 58 0.4 */
        !           188:        {DATA,  PI},            /* 59 p6 */
        !           189:        {DATA,  DATA0},         /* 60 leap */
        !           190: };
        !           191: 
        !           192: /*
        !           193:  * IRIG format except first frame (1000 Hz, 20 digits, 1 s frame)
        !           194:  */
        !           195: struct progx progy[] = {
        !           196:        {COEF,  1},             /* 0 1 units */
        !           197:        {COEF,  2},             /* 1 2 */
        !           198:        {COEF,  4},             /* 2 4 */
        !           199:        {COEF,  8},             /* 3 8 */
        !           200:        {DEC,   M2},            /* 4 im */
        !           201:        {COEF,  1},             /* 5 10 tens */
        !           202:        {COEF,  2},             /* 6 20 */
        !           203:        {COEF,  4},             /* 7 40 */
        !           204:        {COEF,  8},             /* 8 80 */
        !           205:        {DEC,   M8},            /* 9 pi */
        !           206: };
        !           207: 
        !           208: /*
        !           209:  * IRIG format first frame (1000 Hz, 20 digits, 1 s frame)
        !           210:  */
        !           211: struct progx progz[] = {
        !           212:        {MIN,   M8},            /* 0 pi (second) */
        !           213:        {COEF,  1},             /* 1 1 units */
        !           214:        {COEF,  2},             /* 2 2 */
        !           215:        {COEF,  4},             /* 3 4 */
        !           216:        {COEF,  8},             /* 4 8 */
        !           217:        {DEC,   M2},            /* 5 im */
        !           218:        {COEF,  1},             /* 6 10 tens */
        !           219:        {COEF,  2},             /* 7 20 */
        !           220:        {COEF,  4},             /* 8 40 */
        !           221:        {DEC,   M8},            /* 9 pi */
        !           222: };
        !           223: 
        !           224: /*
        !           225:  * Forward declarations
        !           226:  */
        !           227: void   sec(int);               /* send second */
        !           228: void   digit(int);             /* encode digit */
        !           229: void   peep(int, int, int);    /* send cycles */
        !           230: void   delay(int);             /* delay samples */
        !           231: 
        !           232: /*
        !           233:  * Global variables
        !           234:  */
        !           235: char   buffer[BUFLNG];         /* output buffer */
        !           236: int    bufcnt = 0;             /* buffer counter */
        !           237: int    second = 0;             /* seconds counter */
        !           238: int    fd;                     /* audio codec file descriptor */
        !           239: int    tone = 1000;            /* WWV sync frequency */
        !           240: int    level = AUDIO_MAX_GAIN / 8; /* output level */
        !           241: int    port = AUDIO_LINE_OUT;  /* output port */
        !           242: int    encode = WWV;           /* encoder select */
        !           243: int    leap = 0;               /* leap indicator */
        !           244: int    dst = 0;                /* winter/summer time */
        !           245: int    dut1 = 0;               /* DUT1 correction (sign, magnitude) */
        !           246: int    utc = 0;                /* option epoch */
        !           247: 
        !           248: /*
        !           249:  * Main program
        !           250:  */
        !           251: int
        !           252: main(
        !           253:        int     argc,           /* command line options */
        !           254:        char    **argv          /* poiniter to list of tokens */
        !           255:        )
        !           256: {
        !           257:        struct timeval tv;      /* system clock at startup */
        !           258:        audio_info_t info;      /* Sun audio structure */
        !           259:        struct tm *tm = NULL;   /* structure returned by gmtime */
        !           260:        char    device[50];     /* audio device */
        !           261:        char    code[100];      /* timecode */
        !           262:        int     rval, temp, arg, sw, ptr;
        !           263:        int     minute, hour, day, year;
        !           264:        int     i;
        !           265: 
        !           266:        /*
        !           267:         * Parse options
        !           268:         */
        !           269:        strcpy(device, DEVICE);
        !           270:        year = 0;
        !           271:        while ((temp = getopt(argc, argv, "a:dhilsu:v:y:")) != -1) {
        !           272:                switch (temp) {
        !           273: 
        !           274:                case 'a':       /* specify audio device (/dev/audio) */
        !           275:                        strcpy(device, optarg);
        !           276:                        break;
        !           277: 
        !           278:                case 'd':       /* set DST for summer (WWV/H only) */
        !           279:                        dst++;
        !           280:                        break;
        !           281: 
        !           282:                case 'h':       /* select WWVH sync frequency */
        !           283:                        tone = 1200;
        !           284:                        break;
        !           285: 
        !           286:                case 'i':       /* select irig format */
        !           287:                        encode = IRIG;
        !           288:                        break;
        !           289: 
        !           290:                case 'l':       /* set leap warning bit (WWV/H only) */
        !           291:                        leap++;
        !           292:                        break;
        !           293: 
        !           294:                case 's':       /* enable speaker */
        !           295:                        port |= AUDIO_SPEAKER;
        !           296:                        break;
        !           297: 
        !           298:                case 'u':       /* set DUT1 offset (-7 to +7) */
        !           299:                        sscanf(optarg, "%d", &dut1);
        !           300:                        if (dut1 < 0)
        !           301:                                dut1 = abs(dut1);
        !           302:                        else
        !           303:                                dut1 |= 0x8;
        !           304:                        break;
        !           305: 
        !           306:                case 'v':       /* set output level (0-255) */
        !           307:                        sscanf(optarg, "%d", &level);
        !           308:                        break;
        !           309: 
        !           310:                case 'y':       /* set initial date and time */
        !           311:                        sscanf(optarg, "%2d%3d%2d%2d", &year, &day,
        !           312:                            &hour, &minute);
        !           313:                        utc++;
        !           314:                        break;
        !           315: 
        !           316:                defult:
        !           317:                        printf("invalid option %c\n", temp);
        !           318:                        break;
        !           319:                }
        !           320:        }
        !           321: 
        !           322:        /*
        !           323:         * Open audio device and set options
        !           324:         */
        !           325:        fd = open("/dev/audio", O_WRONLY);
        !           326:        if (fd <= 0) {
        !           327:                printf("audio open %s\n", strerror(errno));
        !           328:                exit(1);
        !           329:        }
        !           330:        rval = ioctl(fd, AUDIO_GETINFO, &info);
        !           331:        if (rval < 0) {
        !           332:                printf("audio control %s\n", strerror(errno));
        !           333:                exit(0);
        !           334:        }
        !           335:        info.play.port = port;
        !           336:        info.play.gain = level;
        !           337:        info.play.sample_rate = SECOND;
        !           338:        info.play.channels = 1;
        !           339:        info.play.precision = 8;
        !           340:        info.play.encoding = AUDIO_ENCODING_ULAW;
        !           341:        printf("port %d gain %d rate %d chan %d prec %d encode %d\n",
        !           342:            info.play.port, info.play.gain, info.play.sample_rate,
        !           343:            info.play.channels, info.play.precision,
        !           344:            info.play.encoding);
        !           345:        ioctl(fd, AUDIO_SETINFO, &info);
        !           346: 
        !           347:        /*
        !           348:         * Unless specified otherwise, read the system clock and
        !           349:         * initialize the time.
        !           350:         */
        !           351:        if (!utc) {
        !           352:                gettimeofday(&tv, NULL);
        !           353:                tm = gmtime(&tv.tv_sec);
        !           354:                minute = tm->tm_min;
        !           355:                hour = tm->tm_hour;
        !           356:                day = tm->tm_yday + 1;
        !           357:                year = tm->tm_year % 100;
        !           358:                second = tm->tm_sec;
        !           359: 
        !           360:                /*
        !           361:                 * Delay the first second so the generator is accurately
        !           362:                 * aligned with the system clock within one sample (125
        !           363:                 * microseconds ).
        !           364:                 */
        !           365:                delay(SECOND - tv.tv_usec * 8 / 1000);
        !           366:        }
        !           367:        memset(code, 0, sizeof(code));
        !           368:        switch (encode) {
        !           369: 
        !           370:        /*
        !           371:         * For WWV/H and default time, carefully set the signal
        !           372:         * generator seconds number to agree with the current time.
        !           373:         */ 
        !           374:        case WWV:
        !           375:                printf("year %d day %d time %02d:%02d:%02d tone %d\n",
        !           376:                    year, day, hour, minute, second, tone);
        !           377:                sprintf(code, "%01d%03d%02d%02d%01d", year / 10, day,
        !           378:                    hour, minute, year % 10);
        !           379:                printf("%s\n", code);
        !           380:                ptr = 8;
        !           381:                for (i = 0; i <= second; i++) {
        !           382:                        if (progx[i].sw == DEC)
        !           383:                                ptr--;
        !           384:                }
        !           385:                break;
        !           386: 
        !           387:        /*
        !           388:         * For IRIG the signal generator runs every second, so requires
        !           389:         * no additional alignment.
        !           390:         */
        !           391:        case IRIG:
        !           392:                printf("sbs %x year %d day %d time %02d:%02d:%02d\n",
        !           393:                    0, year, day, hour, minute, second);
        !           394:                break;
        !           395:        }
        !           396: 
        !           397:        /*
        !           398:         * Run the signal generator to generate new timecode strings
        !           399:         * once per minute for WWV/H and once per second for IRIG.
        !           400:         */
        !           401:        while(1) {
        !           402: 
        !           403:                /*
        !           404:                 * Crank the state machine to propagate carries to the
        !           405:                 * year of century. Note that we delayed up to one
        !           406:                 * second for alignment after reading the time, so this
        !           407:                 * is the next second.
        !           408:                 */
        !           409:                second = (second + 1) % 60;
        !           410:                if (second == 0) {
        !           411:                        minute++;
        !           412:                        if (minute >= 60) {
        !           413:                                minute = 0;
        !           414:                                hour++;
        !           415:                        }
        !           416:                        if (hour >= 24) {
        !           417:                                hour = 0;
        !           418:                                day++;
        !           419:                        }
        !           420: 
        !           421:                        /*
        !           422:                         * At year rollover check for leap second.
        !           423:                         */
        !           424:                        if (day >= (year & 0x3 ? 366 : 367)) {
        !           425:                                if (leap) {
        !           426:                                        sec(DATA0);
        !           427:                                        printf("\nleap!");
        !           428:                                        leap = 0;
        !           429:                                }
        !           430:                                day = 1;
        !           431:                                year++;
        !           432:                        }
        !           433:                        if (encode == WWV) {
        !           434:                                sprintf(code, "%01d%03d%02d%02d%01d",
        !           435:                                    year / 10, day, hour, minute, year %
        !           436:                                    10);
        !           437:                                printf("\n%s\n", code);
        !           438:                                ptr = 8;
        !           439:                        }
        !           440:                }
        !           441:                if (encode == IRIG) {
        !           442:                        sprintf(code, "%04x%04d%06d%02d%02d%02d", 0,
        !           443:                            year, day, hour, minute, second);
        !           444:                        printf("%s\n", code);
        !           445:                        ptr = 19;
        !           446:                }
        !           447: 
        !           448:                /*
        !           449:                 * Generate data for the second
        !           450:                 */
        !           451:                switch(encode) {
        !           452: 
        !           453:                /*
        !           454:                 * The IRIG second consists of 20 BCD digits of width-
        !           455:                 * modulateod pulses at 2, 5 and 8 ms and modulated 50
        !           456:                 * percent on the 1000-Hz carrier.
        !           457:                 */
        !           458:                case IRIG:
        !           459:                        for (i = 0; i < 100; i++) {
        !           460:                                if (i < 10) {
        !           461:                                        sw = progz[i].sw;
        !           462:                                        arg = progz[i].arg;
        !           463:                                } else {
        !           464:                                        sw = progy[i % 10].sw;
        !           465:                                        arg = progy[i % 10].arg;
        !           466:                                }
        !           467:                                switch(sw) {
        !           468: 
        !           469:                                case COEF:      /* send BCD bit */
        !           470:                                        if (code[ptr] & arg) {
        !           471:                                                peep(M5, 1000, HIGH);
        !           472:                                                peep(M5, 1000, LOW);
        !           473:                                                printf("1");
        !           474:                                        } else {
        !           475:                                                peep(M2, 1000, HIGH);
        !           476:                                                peep(M8, 1000, LOW);
        !           477:                                                printf("0");
        !           478:                                        }
        !           479:                                        break;
        !           480: 
        !           481:                                case DEC:       /* send IM/PI bit */
        !           482:                                        ptr--;
        !           483:                                        printf(" ");
        !           484:                                        peep(arg, 1000, HIGH);
        !           485:                                        peep(10 - arg, 1000, LOW);
        !           486:                                        break;
        !           487: 
        !           488:                                case MIN:       /* send data bit */
        !           489:                                        peep(arg, 1000, HIGH);
        !           490:                                        peep(10 - arg, 1000, LOW);
        !           491:                                        printf("M ");
        !           492:                                        break;
        !           493:                                }
        !           494:                                if (ptr < 0)
        !           495:                                        break;
        !           496:                        }
        !           497:                        printf("\n");
        !           498:                        break;
        !           499: 
        !           500:                /*
        !           501:                 * The WWV/H second consists of 9 BCD digits of width-
        !           502:                 * modulateod pulses 200, 500 and 800 ms at 100-Hz.
        !           503:                 */
        !           504:                case WWV:
        !           505:                        sw = progx[second].sw;
        !           506:                        arg = progx[second].arg;
        !           507:                        switch(sw) {
        !           508: 
        !           509:                        case DATA:              /* send data bit */
        !           510:                                sec(arg);
        !           511:                                break;
        !           512: 
        !           513:                        case COEF:              /* send BCD bit */
        !           514:                                if (code[ptr] & arg) {
        !           515:                                        sec(DATA1);
        !           516:                                        printf("1");
        !           517:                                } else {
        !           518:                                        sec(DATA0);
        !           519:                                        printf("0");
        !           520:                                }
        !           521:                                break;
        !           522: 
        !           523:                        case LEAP:              /* send leap bit */
        !           524:                                if (leap) {
        !           525:                                        sec(DATA1);
        !           526:                                        printf("L ");
        !           527:                                } else {
        !           528:                                        sec(DATA0);
        !           529:                                        printf("  ");
        !           530:                                }
        !           531:                                break;
        !           532: 
        !           533:                        case DEC:               /* send data bit */
        !           534:                                ptr--;
        !           535:                                sec(arg);
        !           536:                                printf(" ");
        !           537:                                break;
        !           538: 
        !           539:                        case MIN:               /* send minute sync */
        !           540:                                peep(arg, tone, HIGH);
        !           541:                                peep(1000 - arg, tone, OFF);
        !           542:                                break;
        !           543: 
        !           544:                        case DUT1:              /* send DUT1 bits */
        !           545:                                if (dut1 & arg)
        !           546:                                        sec(DATA1);
        !           547:                                else
        !           548:                                        sec(DATA0);
        !           549:                                break;
        !           550:                                
        !           551:                        case DST1:              /* send DST1 bit */
        !           552:                                ptr--;
        !           553:                                if (dst)
        !           554:                                        sec(DATA1);
        !           555:                                else
        !           556:                                        sec(DATA0);
        !           557:                                printf(" ");
        !           558:                                break;
        !           559: 
        !           560:                        case DST2:              /* send DST2 bit */
        !           561:                                if (dst)
        !           562:                                        sec(DATA1);
        !           563:                                else
        !           564:                                        sec(DATA0);
        !           565:                                break;
        !           566:                        }
        !           567:                }
        !           568:        }
        !           569: }
        !           570: 
        !           571: 
        !           572: /*
        !           573:  * Generate WWV/H 0 or 1 data pulse.
        !           574:  */
        !           575: void sec(
        !           576:        int     code            /* DATA0, DATA1, PI */
        !           577:        )
        !           578: {
        !           579:        /*
        !           580:         * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
        !           581:         * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
        !           582:         * 100 Hz corresponding to 0, 1 or position indicator (PI),
        !           583:         * respectively. Note the 100-Hz data pulses are transmitted 6
        !           584:         * dB below the 1000-Hz sync pulses. Originally the data pulses
        !           585:         * were transmited 10 dB below the sync pulses, but the station
        !           586:         * engineers increased that to 6 dB because the Heath GC-1000
        !           587:         * WWV/H radio clock worked much better.
        !           588:         */
        !           589:        peep(5, tone, HIGH);            /* send seconds tick */
        !           590:        peep(25, tone, OFF);
        !           591:        peep(code - 30, 100, LOW);      /* send data */
        !           592:        peep(1000 - code, 100, OFF);
        !           593: }
        !           594: 
        !           595: 
        !           596: /*
        !           597:  * Generate cycles of 100 Hz or any multiple of 100 Hz.
        !           598:  */
        !           599: void peep(
        !           600:        int     pulse,          /* pulse length (ms) */
        !           601:        int     freq,           /* frequency (Hz) */
        !           602:        int     amp             /* amplitude */
        !           603:        )
        !           604: {
        !           605:        int     increm;         /* phase increment */
        !           606:        int     i, j;
        !           607: 
        !           608:        if (amp == OFF || freq == 0)
        !           609:                increm = 10;
        !           610:        else
        !           611:                increm = freq / 100;
        !           612:        j = 0;
        !           613:        for (i = 0 ; i < pulse * 8; i++) {
        !           614:                switch (amp) {
        !           615: 
        !           616:                case HIGH:
        !           617:                        buffer[bufcnt++] = ~c6000[j];
        !           618:                        break;
        !           619: 
        !           620:                case LOW:
        !           621:                        buffer[bufcnt++] = ~c3000[j];
        !           622:                        break;
        !           623: 
        !           624:                default:
        !           625:                        buffer[bufcnt++] = ~0;
        !           626:                }
        !           627:                if (bufcnt >= BUFLNG) {
        !           628:                        write(fd, buffer, BUFLNG);
        !           629:                        bufcnt = 0;
        !           630:                }
        !           631:                j = (j + increm) % 80;
        !           632:        }
        !           633: }
        !           634: 
        !           635: 
        !           636: /*
        !           637:  * Delay for initial phasing
        !           638:  */
        !           639: void delay (
        !           640:        int     delay           /* delay in samples */
        !           641:        )
        !           642: {
        !           643:        int     samples;        /* samples remaining */
        !           644: 
        !           645:        samples = delay;
        !           646:        memset(buffer, 0, BUFLNG);
        !           647:        while (samples >= BUFLNG) {
        !           648:                write(fd, buffer, BUFLNG);
        !           649:                samples -= BUFLNG;
        !           650:        }
        !           651:                write(fd, buffer, samples);
        !           652: }

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