Home | History | Annotate | Line # | Download | only in util
tg.c revision 1.1.1.7
      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 	strlcpy(device, DEVICE, sizeof(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 			strlcpy(device, optarg, sizeof(device));
    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 		snprintf(code, sizeof(code), "%01d%03d%02d%02d%01d",
    378 		    year / 10, day, 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 				snprintf(code, sizeof(code),
    435 				    "%01d%03d%02d%02d%01d", year / 10,
    436 				    day, hour, minute, year % 10);
    437 				printf("\n%s\n", code);
    438 				ptr = 8;
    439 			}
    440 		}
    441 		if (encode == IRIG) {
    442 			snprintf(code, sizeof(code),
    443 			    "%04x%04d%06d%02d%02d%02d", 0, year, day,
    444 			    hour, minute, second);
    445 			printf("%s\n", code);
    446 			ptr = 19;
    447 		}
    448 
    449 		/*
    450 		 * Generate data for the second
    451 		 */
    452 		switch(encode) {
    453 
    454 		/*
    455 		 * The IRIG second consists of 20 BCD digits of width-
    456 		 * modulateod pulses at 2, 5 and 8 ms and modulated 50
    457 		 * percent on the 1000-Hz carrier.
    458 		 */
    459 		case IRIG:
    460 			for (i = 0; i < 100; i++) {
    461 				if (i < 10) {
    462 					sw = progz[i].sw;
    463 					arg = progz[i].arg;
    464 				} else {
    465 					sw = progy[i % 10].sw;
    466 					arg = progy[i % 10].arg;
    467 				}
    468 				switch(sw) {
    469 
    470 				case COEF:	/* send BCD bit */
    471 					if (code[ptr] & arg) {
    472 						peep(M5, 1000, HIGH);
    473 						peep(M5, 1000, LOW);
    474 						printf("1");
    475 					} else {
    476 						peep(M2, 1000, HIGH);
    477 						peep(M8, 1000, LOW);
    478 						printf("0");
    479 					}
    480 					break;
    481 
    482 				case DEC:	/* send IM/PI bit */
    483 					ptr--;
    484 					printf(" ");
    485 					peep(arg, 1000, HIGH);
    486 					peep(10 - arg, 1000, LOW);
    487 					break;
    488 
    489 				case MIN:	/* send data bit */
    490 					peep(arg, 1000, HIGH);
    491 					peep(10 - arg, 1000, LOW);
    492 					printf("M ");
    493 					break;
    494 				}
    495 				if (ptr < 0)
    496 					break;
    497 			}
    498 			printf("\n");
    499 			break;
    500 
    501 		/*
    502 		 * The WWV/H second consists of 9 BCD digits of width-
    503 		 * modulateod pulses 200, 500 and 800 ms at 100-Hz.
    504 		 */
    505 		case WWV:
    506 			sw = progx[second].sw;
    507 			arg = progx[second].arg;
    508 			switch(sw) {
    509 
    510 			case DATA:		/* send data bit */
    511 				sec(arg);
    512 				break;
    513 
    514 			case COEF:		/* send BCD bit */
    515 				if (code[ptr] & arg) {
    516 					sec(DATA1);
    517 					printf("1");
    518 				} else {
    519 					sec(DATA0);
    520 					printf("0");
    521 				}
    522 				break;
    523 
    524 			case LEAP:		/* send leap bit */
    525 				if (leap) {
    526 					sec(DATA1);
    527 					printf("L ");
    528 				} else {
    529 					sec(DATA0);
    530 					printf("  ");
    531 				}
    532 				break;
    533 
    534 			case DEC:		/* send data bit */
    535 				ptr--;
    536 				sec(arg);
    537 				printf(" ");
    538 				break;
    539 
    540 			case MIN:		/* send minute sync */
    541 				peep(arg, tone, HIGH);
    542 				peep(1000 - arg, tone, OFF);
    543 				break;
    544 
    545 			case DUT1:		/* send DUT1 bits */
    546 				if (dut1 & arg)
    547 					sec(DATA1);
    548 				else
    549 					sec(DATA0);
    550 				break;
    551 
    552 			case DST1:		/* send DST1 bit */
    553 				ptr--;
    554 				if (dst)
    555 					sec(DATA1);
    556 				else
    557 					sec(DATA0);
    558 				printf(" ");
    559 				break;
    560 
    561 			case DST2:		/* send DST2 bit */
    562 				if (dst)
    563 					sec(DATA1);
    564 				else
    565 					sec(DATA0);
    566 				break;
    567 			}
    568 		}
    569 	}
    570 }
    571 
    572 
    573 /*
    574  * Generate WWV/H 0 or 1 data pulse.
    575  */
    576 void sec(
    577 	int	code		/* DATA0, DATA1, PI */
    578 	)
    579 {
    580 	/*
    581 	 * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
    582 	 * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
    583 	 * 100 Hz corresponding to 0, 1 or position indicator (PI),
    584 	 * respectively. Note the 100-Hz data pulses are transmitted 6
    585 	 * dB below the 1000-Hz sync pulses. Originally the data pulses
    586 	 * were transmited 10 dB below the sync pulses, but the station
    587 	 * engineers increased that to 6 dB because the Heath GC-1000
    588 	 * WWV/H radio clock worked much better.
    589 	 */
    590 	peep(5, tone, HIGH);		/* send seconds tick */
    591 	peep(25, tone, OFF);
    592 	peep(code - 30, 100, LOW);	/* send data */
    593 	peep(1000 - code, 100, OFF);
    594 }
    595 
    596 
    597 /*
    598  * Generate cycles of 100 Hz or any multiple of 100 Hz.
    599  */
    600 void peep(
    601 	int	pulse,		/* pulse length (ms) */
    602 	int	freq,		/* frequency (Hz) */
    603 	int	amp		/* amplitude */
    604 	)
    605 {
    606 	int	increm;		/* phase increment */
    607 	int	i, j;
    608 
    609 	if (amp == OFF || freq == 0)
    610 		increm = 10;
    611 	else
    612 		increm = freq / 100;
    613 	j = 0;
    614 	for (i = 0 ; i < pulse * 8; i++) {
    615 		switch (amp) {
    616 
    617 		case HIGH:
    618 			buffer[bufcnt++] = ~c6000[j];
    619 			break;
    620 
    621 		case LOW:
    622 			buffer[bufcnt++] = ~c3000[j];
    623 			break;
    624 
    625 		default:
    626 			buffer[bufcnt++] = ~0;
    627 		}
    628 		if (bufcnt >= BUFLNG) {
    629 			write(fd, buffer, BUFLNG);
    630 			bufcnt = 0;
    631 		}
    632 		j = (j + increm) % 80;
    633 	}
    634 }
    635 
    636 
    637 /*
    638  * Delay for initial phasing
    639  */
    640 void delay (
    641 	int	delay		/* delay in samples */
    642 	)
    643 {
    644 	int	samples;	/* samples remaining */
    645 
    646 	samples = delay;
    647 	memset(buffer, 0, BUFLNG);
    648 	while (samples >= BUFLNG) {
    649 		write(fd, buffer, BUFLNG);
    650 		samples -= BUFLNG;
    651 	}
    652 		write(fd, buffer, samples);
    653 }
    654