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>