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