File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / util / tg.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>