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