xref: /freebsd/contrib/ntp/util/tg2.c (revision 2008043f386721d58158e37e0d7e50df8095942d)
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  * $Log: tg.c,v $
53  * Revision 1.28  2007/02/12 23:57:45  dmw
54  * v0.23 2007-02-12 dmw:
55  * - Changed statistics to include calculated error
56  *   of frequency, based on number of added or removed
57  *   cycles over time.
58  *
59  * Revision 1.27  2007/02/09 02:28:59  dmw
60  * v0.22 2007-02-08 dmw:
61  * - Changed default for rate correction to "enabled", "-j" switch now disables.
62  * - Adjusted help message accordingly.
63  * - Added "2007" to modifications note at end of help message.
64  *
65  * Revision 1.26  2007/02/08 03:36:17  dmw
66  * v0.21 2007-02-07 dmw:
67  * - adjusted strings for shorten and lengthen to make
68  *   fit on smaller screen.
69  *
70  * Revision 1.25  2007/02/01 06:08:09  dmw
71  * v0.20 2007-02-01 dmw:
72  * - Added periodic display of running time along with legend on IRIG-B, allows tracking how
73  *   close IRIG output is to actual clock time.
74  *
75  * Revision 1.24  2007/01/31 19:24:11  dmw
76  * v0.19 2007-01-31 dmw:
77  * - Added tracking of how many seconds have been adjusted,
78  *   how many cycles added (actually in milliseconds), how
79  *   many cycles removed, print periodically if verbose is
80  *   active.
81  * - Corrected lack of lengthen or shorten of minute & hour
82  *   pulses for WWV format.
83  *
84  * Revision 1.23  2007/01/13 07:09:12  dmw
85  * v0.18 2007-01-13 dmw:
86  * - added -k option, which allows force of long or short
87  *   cycles, to test against IRIG-B decoder.
88  *
89  * Revision 1.22  2007/01/08 16:27:23  dmw
90  * v0.17 2007-01-08 dmw:
91  * - Changed -j option to **enable** rate correction, not disable.
92  *
93  * Revision 1.21  2007/01/08 06:22:36  dmw
94  * v0.17 2007-01-08 dmw:
95  * - Run stability check versus ongoing system clock (assume NTP correction)
96  *   and adjust time code rate to try to correct, if gets too far out of sync.
97  *   Disable this algorithm with -j option.
98  *
99  * Revision 1.20  2006/12/19 04:59:04  dmw
100  * v0.16 2006-12-18 dmw
101  * - Corrected print of setting of output frequency, always
102  *   showed 8000 samples/sec, now as specified on command line.
103  * - Modified to reflect new employer Norscan.
104  *
105  * Revision 1.19  2006/12/19 03:45:38  dmw
106  * v0.15 2006-12-18 dmw:
107  * - Added count of number of seconds to output then exit,
108  *   default zero for forever.
109  *
110  * Revision 1.18  2006/12/18 05:43:36  dmw
111  * v0.14 2006-12-17 dmw:
112  * - Corrected WWV(H) signal to leave "tick" sound off of 29th and 59th second of minute.
113  * - Adjusted verbose output format for WWV(H).
114  *
115  * Revision 1.17  2006/12/18 02:31:33  dmw
116  * v0.13 2006-12-17 dmw:
117  * - Put SPARC code back in, hopefully will work, but I don't have
118  *   a SPARC to try it on...
119  * - Reworked Verbose mode, different flag to initiate (x not v)
120  *   and actually implement turn off of verbosity when this flag used.
121  * - Re-claimed v flag for output level.
122  * - Note that you must define OSS_MODS to get OSS to compile,
123  *   otherwise will expect to compile using old SPARC options, as
124  *   it used to be.
125  *
126  * Revision 1.16  2006/10/26 19:08:43  dmw
127  * v0.12 2006-10-26 dmw:
128  * - Reversed output binary dump for IRIG, makes it easier to read the numbers.
129  *
130  * Revision 1.15  2006/10/24 15:57:09  dmw
131  * v0.11 2006-10-24 dmw:
132  * - another tweak.
133  *
134  * Revision 1.14  2006/10/24 15:55:53  dmw
135  * v0.11 2006-10-24 dmw:
136  * - Curses a fix to the fix to the fix of the usaeg.
137  *
138  * Revision 1.13  2006/10/24 15:53:25  dmw
139  * v0.11 (still) 2006-10-24 dmw:
140  * - Messed with usage message that's all.
141  *
142  * Revision 1.12  2006/10/24 15:50:05  dmw
143  * v0.11 2006-10-24 dmw:
144  * - oops, needed to note "hours" in usage of that offset.
145  *
146  * Revision 1.11  2006/10/24 15:49:09  dmw
147  * v0.11 2006-10-24 dmw:
148  * - Added ability to offset actual time sent, from the UTC time
149  *   as per the computer.
150  *
151  * Revision 1.10  2006/10/24 03:25:55  dmw
152  * v0.10 2006-10-23 dmw:
153  * - Corrected polarity of correction of offset when going into or out of DST.
154  * - Ensure that zero offset is always positive (pet peeve).
155  *
156  * Revision 1.9  2006/10/24 00:00:35  dmw
157  * v0.9 2006-10-23 dmw:
158  * - Shift time offset when DST in or out.
159  *
160  * Revision 1.8  2006/10/23 23:49:28  dmw
161  * v0.8 2006-10-23 dmw:
162  * - made offset of zero default positive.
163  *
164  * Revision 1.7  2006/10/23 23:44:13  dmw
165  * v0.7 2006-10-23 dmw:
166  * - Added unmodulated and inverted unmodulated output.
167  *
168  * Revision 1.6  2006/10/23 18:10:37  dmw
169  * v0.6 2006-10-23 dmw:
170  * - Cleaned up usage message.
171  * - Require at least one option, or prints usage message and exits.
172  *
173  * Revision 1.5  2006/10/23 16:58:10  dmw
174  * v0.5 2006-10-23 dmw:
175  * - Finally added a usage message.
176  * - Added leap second pending and DST change pending into IEEE 1344.
177  * - Default code type is now IRIG-B with IEEE 1344.
178  *
179  * Revision 1.4  2006/10/23 03:27:25  dmw
180  * v0.4 2006-10-22 dmw:
181  * - Added leap second addition and deletion.
182  * - Added DST changing forward and backward.
183  * - Changed date specification to more conventional year, month, and day of month
184  *   (rather than day of year).
185  *
186  * Revision 1.3  2006/10/22 21:04:12  dmw
187  * v0.2 2006-10-22 dmw:
188  * - Corrected format of legend line.
189  *
190  * Revision 1.2  2006/10/22 21:01:07  dmw
191  * v0.1 2006-10-22 dmw:
192  * - Added some more verbose output (as is my style)
193  * - Corrected frame format - there were markers in the
194  *   middle of frames, now correctly as "zero" bits.
195  * - Added header line to show fields of output.
196  * - Added straight binary seconds, were not implemented
197  *   before.
198  * - Added IEEE 1344 with parity.
199  *
200  *
201  */
202 #include <stdio.h>
203 #include <stdlib.h>
204 #include <time.h>
205 
206 #ifdef  HAVE_CONFIG_H
207 #include "config.h"
208 #undef VERSION		/* avoid conflict below */
209 #endif
210 
211 #ifdef  HAVE_SYS_SOUNDCARD_H
212 #include <sys/soundcard.h>
213 #else
214 # ifdef HAVE_SYS_AUDIOIO_H
215 # include <sys/audioio.h>
216 # else
217 # include <sys/audio.h>
218 # endif
219 #endif
220 
221 #include "ntp_stdlib.h"	/* for strlcat(), strlcpy() */
222 
223 #include <math.h>
224 #include <errno.h>
225 #include <sys/types.h>
226 #include <sys/stat.h>
227 #include <fcntl.h>
228 #include <string.h>
229 #include <unistd.h>
230 #include <ctype.h>
231 #include <sys/ioctl.h>
232 #include <sys/time.h>
233 
234 #define VERSION		(0)
235 #define	ISSUE		(23)
236 #define	ISSUE_DATE	"2007-02-12"
237 
238 #define	SECOND	(8000)			/* one second of 125-us samples */
239 #define BUFLNG	(400)			/* buffer size */
240 #define	DEVICE	"/dev/audio"	/* default audio device */
241 #define	WWV		(0)				/* WWV encoder */
242 #define	IRIG	(1)				/* IRIG-B encoder */
243 #define	OFF		(0)				/* zero amplitude */
244 #define	LOW		(1)				/* low amplitude */
245 #define	HIGH	(2)				/* high amplitude */
246 #define	DATA0	(200)			/* WWV/H 0 pulse */
247 #define	DATA1	(500)			/* WWV/H 1 pulse */
248 #define PI		(800)			/* WWV/H PI pulse */
249 #define	M2		(2)				/* IRIG 0 pulse */
250 #define	M5		(5)				/* IRIG 1 pulse */
251 #define	M8		(8)				/* IRIG PI pulse */
252 
253 #define	NUL		(0)
254 
255 #define	SECONDS_PER_MINUTE	(60)
256 #define SECONDS_PER_HOUR	(3600)
257 
258 #define	OUTPUT_DATA_STRING_LENGTH	(200)
259 
260 /* Attempt at unmodulated - "high" */
261 int u6000[] = {
262 	247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/*  0- 9 */
263     247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 10-19 */
264     247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 20-29 */
265     247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 30-39 */
266     247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 40-49 */
267     247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 	/* 50-59 */
268     247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 60-69 */
269     247, 247, 247, 247, 247, 247, 247, 247, 247, 247}; 	/* 70-79 */
270 
271 /* Attempt at unmodulated - "low" */
272 int u3000[] = {
273 	119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/*  0- 9 */
274     119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 10-19 */
275     119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 20-29 */
276     119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 30-39 */
277     119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 40-49 */
278     119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 	/* 50-59 */
279     119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 60-69 */
280     119, 119, 119, 119, 119, 119, 119, 119, 119, 119}; 	/* 70-79 */
281 
282 /*
283  * Companded sine table amplitude 3000 units
284  */
285 int c3000[] = {1, 48, 63, 70, 78, 82, 85, 89, 92, 94,	/* 0-9 */
286      96,  98,  99, 100, 101, 101, 102, 103, 103, 103,	/* 10-19 */
287     103, 103, 103, 103, 102, 101, 101, 100,  99,  98,	/* 20-29 */
288      96,  94,  92,  89,  85,  82,  78,  70,  63,  48,	/* 30-39 */
289     129, 176, 191, 198, 206, 210, 213, 217, 220, 222,	/* 40-49 */
290     224, 226, 227, 228, 229, 229, 230, 231, 231, 231, 	/* 50-59 */
291     231, 231, 231, 231, 230, 229, 229, 228, 227, 226,	/* 60-69 */
292     224, 222, 220, 217, 213, 210, 206, 198, 191, 176}; 	/* 70-79 */
293 /*
294  * Companded sine table amplitude 6000 units
295  */
296 int c6000[] = {1, 63, 78, 86, 93, 98, 101, 104, 107, 110, /* 0-9 */
297     112, 113, 115, 116, 117, 117, 118, 118, 119, 119,	/* 10-19 */
298     119, 119, 119, 118, 118, 117, 117, 116, 115, 113,	/* 20-29 */
299     112, 110, 107, 104, 101,  98,  93,  86,  78,  63,	/* 30-39 */
300     129, 191, 206, 214, 221, 226, 229, 232, 235, 238,	/* 40-49 */
301     240, 241, 243, 244, 245, 245, 246, 246, 247, 247, 	/* 50-59 */
302     247, 247, 247, 246, 246, 245, 245, 244, 243, 241,	/* 60-69 */
303     240, 238, 235, 232, 229, 226, 221, 214, 206, 191}; 	/* 70-79 */
304 
305 /*
306  * Decoder operations at the end of each second are driven by a state
307  * machine. The transition matrix consists of a dispatch table indexed
308  * by second number. Each entry in the table contains a case switch
309  * number and argument.
310  */
311 struct progx {
312 	int sw;			/* case switch number */
313 	int arg;		/* argument */
314 };
315 
316 /*
317  * Case switch numbers
318  */
319 #define DATA	(0)		/* send data (0, 1, PI) */
320 #define COEF	(1)		/* send BCD bit */
321 #define	DEC		(2)		/* decrement to next digit and send PI */
322 #define	MIN		(3)		/* minute pulse */
323 #define	LEAP	(4)		/* leap warning */
324 #define	DUT1	(5)		/* DUT1 bits */
325 #define	DST1	(6)		/* DST1 bit */
326 #define	DST2	(7)		/* DST2 bit */
327 #define DECZ	(8)		/* decrement to next digit and send zero */
328 #define DECC	(9)		/* decrement to next digit and send bit */
329 #define NODEC	(10)	/* no decerement to next digit, send PI */
330 #define DECX	(11)	/* decrement to next digit, send PI, but no tick */
331 #define DATAX	(12)	/* send data (0, 1, PI), but no tick */
332 
333 /*
334  * WWV/H format (100-Hz, 9 digits, 1 m frame)
335  */
336 struct progx progx[] = {
337 	{MIN,	800},		/* 0 minute sync pulse */
338 	{DATA,	DATA0},		/* 1 */
339 	{DST2,	0},		/* 2 DST2 */
340 	{LEAP,	0},		/* 3 leap warning */
341 	{COEF,	1},		/* 4 1 year units */
342 	{COEF,	2},		/* 5 2 */
343 	{COEF,	4},		/* 6 4 */
344 	{COEF,	8},		/* 7 8 */
345 	{DEC,	DATA0},		/* 8 */
346 	{DATA,	PI},		/* 9 p1 */
347 	{COEF,	1},		/* 10 1 minute units */
348 	{COEF,	2},		/* 11 2 */
349 	{COEF,	4},		/* 12 4 */
350 	{COEF,	8},		/* 13 8 */
351 	{DEC,	DATA0},		/* 14 */
352 	{COEF,	1},		/* 15 10 minute tens */
353 	{COEF,	2},		/* 16 20 */
354 	{COEF,	4},		/* 17 40 */
355 	{COEF,	8},		/* 18 80 (not used) */
356 	{DEC,	PI},		/* 19 p2 */
357 	{COEF,	1},		/* 20 1 hour units */
358 	{COEF,	2},		/* 21 2 */
359 	{COEF,	4},		/* 22 4 */
360 	{COEF,	8},		/* 23 8 */
361 	{DEC,	DATA0},		/* 24 */
362 	{COEF,	1},		/* 25 10 hour tens */
363 	{COEF,	2},		/* 26 20 */
364 	{COEF,	4},		/* 27 40 (not used) */
365 	{COEF,	8},		/* 28 80 (not used) */
366 	{DECX,	PI},		/* 29 p3 */
367 	{COEF,	1},		/* 30 1 day units */
368 	{COEF,	2},		/* 31 2 */
369 	{COEF,	4},		/* 32 4 */
370 	{COEF,	8},		/* 33 8 */
371 	{DEC,	DATA0},		/* 34 not used */
372 	{COEF,	1},		/* 35 10 day tens */
373 	{COEF,	2},		/* 36 20 */
374 	{COEF,	4},		/* 37 40 */
375 	{COEF,	8},		/* 38 80 */
376 	{DEC,	PI},		/* 39 p4 */
377 	{COEF,	1},		/* 40 100 day hundreds */
378 	{COEF,	2},		/* 41 200 */
379 	{COEF,	4},		/* 42 400 (not used) */
380 	{COEF,	8},		/* 43 800 (not used) */
381 	{DEC,	DATA0},		/* 44 */
382 	{DATA,	DATA0},		/* 45 */
383 	{DATA,	DATA0},		/* 46 */
384 	{DATA,	DATA0},		/* 47 */
385 	{DATA,	DATA0},		/* 48 */
386 	{DATA,	PI},		/* 49 p5 */
387 	{DUT1,	8},		/* 50 DUT1 sign */
388 	{COEF,	1},		/* 51 10 year tens */
389 	{COEF,	2},		/* 52 20 */
390 	{COEF,	4},		/* 53 40 */
391 	{COEF,	8},		/* 54 80 */
392 	{DST1,	0},		/* 55 DST1 */
393 	{DUT1,	1},		/* 56 0.1 DUT1 fraction */
394 	{DUT1,	2},		/* 57 0.2 */
395 	{DUT1,	4},		/* 58 0.4 */
396 	{DATAX,	PI},		/* 59 p6 */
397 	{DATA,	DATA0},		/* 60 leap */
398 };
399 
400 /*
401  * IRIG format frames (1000 Hz, 1 second for 10 frames of data)
402  */
403 
404 /*
405  * IRIG format frame 10 - MS straight binary seconds
406  */
407 struct progx progu[] = {
408 	{COEF,	2},		/* 0 0x0 0200 seconds */
409 	{COEF,	4},		/* 1 0x0 0400 */
410 	{COEF,	8},		/* 2 0x0 0800 */
411 	{DECC,	1},		/* 3 0x0 1000 */
412 	{COEF,	2},		/* 4 0x0 2000 */
413 	{COEF,	4},		/* 6 0x0 4000 */
414 	{COEF,	8},		/* 7 0x0 8000 */
415 	{DECC,	1},		/* 8 0x1 0000 */
416 	{COEF,  2},     /* 9 0x2 0000 - but only 86,401 / 0x1 5181 seconds in a day, so always zero */
417 	{NODEC,	M8},	/* 9 PI */
418 };
419 
420 /*
421  * IRIG format frame 8 - MS control functions
422  */
423 struct progx progv[] = {
424 	{COEF,	2},		/*  0 CF # 19 */
425 	{COEF,	4},		/*  1 CF # 20 */
426 	{COEF,	8},		/*  2 CF # 21 */
427 	{DECC,	1},		/*  3 CF # 22 */
428 	{COEF,	2},		/*  4 CF # 23 */
429 	{COEF,	4},		/*  6 CF # 24 */
430 	{COEF,	8},		/*  7 CF # 25 */
431 	{DECC,	1},		/*  8 CF # 26 */
432 	{COEF,  2},		/*  9 CF # 27 */
433 	{DEC,	M8},	/* 10 PI */
434 };
435 
436 /*
437  * IRIG format frames 7 & 9 - LS control functions & LS straight binary seconds
438  */
439 struct progx progw[] = {
440 	{COEF,	1},		/*  0  CF # 10, 0x0 0001 seconds */
441 	{COEF,	2},		/*  1  CF # 11, 0x0 0002 */
442 	{COEF,	4},		/*  2  CF # 12, 0x0 0004 */
443 	{COEF,	8},		/*  3  CF # 13, 0x0 0008 */
444 	{DECC,	1},		/*  4  CF # 14, 0x0 0010 */
445 	{COEF,	2},		/*  6  CF # 15, 0x0 0020 */
446 	{COEF,	4},		/*  7  CF # 16, 0x0 0040 */
447 	{COEF,	8},		/*  8  CF # 17, 0x0 0080 */
448 	{DECC,  1},		/*  9  CF # 18, 0x0 0100 */
449 	{NODEC,	M8},	/* 10  PI */
450 };
451 
452 /*
453  * IRIG format frames 2 to 6 - minutes, hours, days, hundreds days, 2 digit years (also called control functions bits 1-9)
454  */
455 struct progx progy[] = {
456 	{COEF,	1},		/* 0 1 units, CF # 1 */
457 	{COEF,	2},		/* 1 2 units, CF # 2 */
458 	{COEF,	4},		/* 2 4 units, CF # 3 */
459 	{COEF,	8},		/* 3 8 units, CF # 4 */
460 	{DECZ,	M2},	/* 4 zero bit, CF # 5 / unused, default zero in years */
461 	{COEF,	1},		/* 5 10 tens, CF # 6 */
462 	{COEF,	2},		/* 6 20 tens, CF # 7*/
463 	{COEF,	4},		/* 7 40 tens, CF # 8*/
464 	{COEF,	8},		/* 8 80 tens, CF # 9*/
465 	{DEC,	M8},	/* 9 PI */
466 };
467 
468 /*
469  * IRIG format first frame, frame 1 - seconds
470  */
471 struct progx progz[] = {
472 	{MIN,	M8},	/* 0 PI (on-time marker for the second at zero cross of 1st cycle) */
473 	{COEF,	1},		/* 1 1 units */
474 	{COEF,	2},		/* 2 2 */
475 	{COEF,	4},		/* 3 4 */
476 	{COEF,	8},		/* 4 8 */
477 	{DECZ,	M2},	/* 5 zero bit */
478 	{COEF,	1},		/* 6 10 tens */
479 	{COEF,	2},		/* 7 20 */
480 	{COEF,	4},		/* 8 40 */
481 	{DEC,	M8},	/* 9 PI */
482 };
483 
484 /* LeapState values. */
485 #define	LEAPSTATE_NORMAL			(0)
486 #define	LEAPSTATE_DELETING			(1)
487 #define	LEAPSTATE_INSERTING			(2)
488 #define	LEAPSTATE_ZERO_AFTER_INSERT	(3)
489 
490 
491 /*
492  * Forward declarations
493  */
494 void	WWV_Second(int, int);		/* send second */
495 void	WWV_SecondNoTick(int, int);	/* send second with no tick */
496 void	digit(int);		/* encode digit */
497 void	peep(int, int, int);	/* send cycles */
498 void	poop(int, int, int, int); /* Generate unmodulated from similar tables */
499 void	delay(int);		/* delay samples */
500 int		ConvertMonthDayToDayOfYear (int, int, int);	/* Calc day of year from year month & day */
501 void	Help (void);	/* Usage message */
502 void	ReverseString(char *);
503 
504 /*
505  * Extern declarations, don't know why not in headers
506  */
507 //float	round ( float );
508 
509 /*
510  * Global variables
511  */
512 char	buffer[BUFLNG];		/* output buffer */
513 int	bufcnt = 0;		/* buffer counter */
514 int	fd;			/* audio codec file descriptor */
515 int	tone = 1000;		/* WWV sync frequency */
516 int HourTone = 1500;	/* WWV hour on-time frequency */
517 int	encode = IRIG;		/* encoder select */
518 int	leap = 0;		/* leap indicator */
519 int	DstFlag = 0;		/* winter/summer time */
520 int	dut1 = 0;		/* DUT1 correction (sign, magnitude) */
521 int	utc = 0;		/* option epoch */
522 int IrigIncludeYear = FALSE;	/* Whether to send year in first control functions area, between P5 and P6. */
523 int IrigIncludeIeee = FALSE;	/* Whether to send IEEE 1344 control functions extensions between P6 and P8. */
524 int	StraightBinarySeconds = 0;
525 int	ControlFunctions = 0;
526 int	Debug = FALSE;
527 int Verbose = TRUE;
528 char	*CommandName;
529 
530 #ifndef  HAVE_SYS_SOUNDCARD_H
531 int	level = AUDIO_MAX_GAIN / 8; /* output level */
532 int	port = AUDIO_LINE_OUT;	/* output port */
533 #endif
534 
535 int		TotalSecondsCorrected = 0;
536 int		TotalCyclesAdded = 0;
537 int		TotalCyclesRemoved = 0;
538 
539 
540 /*
541  * Main program
542  */
543 int
544 main(
545 	int		argc,		/* command line options */
546 	char	**argv		/* poiniter to list of tokens */
547 	)
548 {
549 #ifndef  HAVE_SYS_SOUNDCARD_H
550 	audio_info_t info;	/* Sun audio structure */
551 	int	rval;           /* For IOCTL calls */
552 #endif
553 
554 	struct	timeval	 TimeValue;				/* System clock at startup */
555 	time_t			 SecondsPartOfTime;		/* Sent to gmtime() for calculation of TimeStructure (can apply offset). */
556 	time_t			 BaseRealTime;			/* Base realtime so can determine seconds since starting. */
557 	time_t			 NowRealTime;			/* New realtime to can determine seconds as of now. */
558 	unsigned		 SecondsRunningRealTime;	/* Difference between NowRealTime and BaseRealTime. */
559 	unsigned		 SecondsRunningSimulationTime;	/* Time that the simulator has been running. */
560 	int				 SecondsRunningDifference;	/* Difference between what real time says we have been running */
561 												/* and what simulator says we have been running - will slowly  */
562 												/* change because of clock drift. */
563 	int				 ExpectedRunningDifference = 0;	/* Stable value that we've obtained from check at initial start-up.	*/
564 	unsigned		 StabilityCount;		/* Used to check stability of difference while starting */
565 #define	RUN_BEFORE_STABILITY_CHECK	(30)	// Must run this many seconds before even checking stability.
566 #define	MINIMUM_STABILITY_COUNT		(10)	// Number of consecutive differences that need to be within initial stability band to say we are stable.
567 #define	INITIAL_STABILITY_BAND		( 2)	// Determining initial stability for consecutive differences within +/- this value.
568 #define	RUNNING_STABILITY_BAND		( 5)	// When running, stability is defined as difference within +/- this value.
569 
570 	struct	tm		*TimeStructure = NULL;	/* Structure returned by gmtime */
571 	char	device[200];	/* audio device */
572 	char	code[200];	/* timecode */
573 	int	temp;
574 	int	arg = 0;
575 	int	sw = 0;
576 	int	ptr = 0;
577 
578 	int	Year;
579 	int	Month;
580 	int	DayOfMonth;
581 	int	Hour;
582 	int	Minute;
583 	int	Second = 0;
584 	int	DayOfYear;
585 
586 	int	BitNumber;
587 #ifdef HAVE_SYS_SOUNDCARD_H
588 	int	AudioFormat;
589 	int	MonoStereo;     /* 0=mono, 1=stereo */
590 #define	MONO	(0)
591 #define	STEREO	(1)
592 	int	SampleRate;
593 	int	SampleRateDifference;
594 #endif
595 	int	SetSampleRate;
596 	char FormatCharacter = '3';		/* Default is IRIG-B with IEEE 1344 extensions */
597 	char AsciiValue;
598 	int	HexValue;
599 	int	OldPtr = 0;
600 	int FrameNumber = 0;
601 
602 	/* Time offset for IEEE 1344 indication. */
603 	float TimeOffset = 0.0;
604 	int	OffsetSignBit = 0;
605 	int OffsetOnes = 0;
606 	int OffsetHalf = 0;
607 
608 	int	TimeQuality = 0;	/* Time quality for IEEE 1344 indication. */
609 	char ParityString[200];	/* Partial output string, to calculate parity on. */
610 	int	ParitySum = 0;
611 	int	ParityValue;
612 	char *StringPointer;
613 
614 	/* Flags to indicate requested leap second addition or deletion by command line option. */
615 	/* Should be mutually exclusive - generally ensured by code which interprets command line option. */
616 	int	InsertLeapSecond = FALSE;
617 	int	DeleteLeapSecond = FALSE;
618 
619 	/* Date and time of requested leap second addition or deletion. */
620 	int	LeapYear					= 0;
621 	int LeapMonth					= 0;
622 	int	LeapDayOfMonth				= 0;
623 	int LeapHour					= 0;
624 	int	LeapMinute					= 0;
625 	int	LeapDayOfYear				= 0;
626 
627 	/* State flag for the insertion and deletion of leap seconds, esp. deletion, */
628 	/* where the logic gets a bit tricky. */
629 	int	LeapState = LEAPSTATE_NORMAL;
630 
631 	/* Flags for indication of leap second pending and leap secod polarity in IEEE 1344 */
632 	int	LeapSecondPending = FALSE;
633 	int	LeapSecondPolarity = FALSE;
634 
635 	/* Date and time of requested switch into or out of DST by command line option. */
636 	int	DstSwitchYear				= 0;
637 	int DstSwitchMonth				= 0;
638 	int	DstSwitchDayOfMonth			= 0;
639 	int DstSwitchHour				= 0;
640 	int	DstSwitchMinute				= 0;
641 	int	DstSwitchDayOfYear			= 0;
642 
643 	/* Indicate when we have been asked to switch into or out of DST by command line option. */
644 	int	DstSwitchFlag = FALSE;
645 
646 	/* To allow predict for DstPendingFlag in IEEE 1344 */
647 	int	DstSwitchPendingYear		= 0;	/* Default value isn't valid, but I don't care. */
648 	int	DstSwitchPendingDayOfYear	= 0;
649 	int	DstSwitchPendingHour		= 0;
650 	int	DstSwitchPendingMinute		= 0;
651 
652 	/* /Flag for indication of a DST switch pending in IEEE 1344 */
653 	int	DstPendingFlag = FALSE;
654 
655 	/* Attempt at unmodulated */
656 	int	Unmodulated = FALSE;
657 	int UnmodulatedInverted = FALSE;
658 
659 	/* Offset to actual time value sent. */
660 	float	UseOffsetHoursFloat;
661 	int		UseOffsetSecondsInt = 0;
662 	float	UseOffsetSecondsFloat;
663 
664 	/* String to allow us to put out reversed data - so can read the binary numbers. */
665 	char	OutputDataString[OUTPUT_DATA_STRING_LENGTH];
666 
667 	/* Number of seconds to send before exiting.  Default = 0 = forever. */
668 	int		SecondsToSend = 0;
669 	int		CountOfSecondsSent = 0;	/* Counter of seconds */
670 
671 	/* Flags to indicate whether to add or remove a cycle for time adjustment. */
672 	int		AddCycle = FALSE;	 	// We are ahead, add cycle to slow down and get back in sync.
673 	int		RemoveCycle = FALSE;	// We are behind, remove cycle to slow down and get back in sync.
674 	int		RateCorrection;			// Aggregate flag for passing to subroutines.
675 	int		EnableRateCorrection = TRUE;
676 
677 	float	RatioError;
678 
679 
680 	CommandName = argv[0];
681 
682 	if	(argc < 1)
683 		{
684 		Help ();
685 		exit (-1);
686 		}
687 
688 	/*
689 	 * Parse options
690 	 */
691 	strlcpy(device, DEVICE, sizeof(device));
692 	Year = 0;
693 	SetSampleRate = SECOND;
694 
695 #if	HAVE_SYS_SOUNDCARD_H
696 	while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:xy:z?")) != -1) {
697 #else
698 	while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:v:xy:z?")) != -1) {
699 #endif
700 		switch (temp) {
701 
702 		case 'a':	/* specify audio device (/dev/audio) */
703 			strlcpy(device, optarg, sizeof(device));
704 			break;
705 
706 		case 'b':	/* Remove (delete) a leap second at the end of the specified minute. */
707 			sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth,
708 			    &LeapHour, &LeapMinute);
709 			InsertLeapSecond = FALSE;
710 			DeleteLeapSecond = TRUE;
711 			break;
712 
713 		case 'c':	/* specify number of seconds to send output for before exiting, 0 = forever */
714 			sscanf(optarg, "%d", &SecondsToSend);
715 			break;
716 
717 		case 'd':	/* set DST for summer (WWV/H only) / start with DST active (IRIG) */
718 			DstFlag++;
719 			break;
720 
721 		case 'f':	/* select format: i=IRIG-98 (default) 2=IRIG-2004 3-IRIG+IEEE-1344 w=WWV(H) */
722 			sscanf(optarg, "%c", &FormatCharacter);
723 			break;
724 
725 		case 'g':	/* Date and time to switch back into / out of DST active. */
726 			sscanf(optarg, "%2d%2d%2d%2d%2d", &DstSwitchYear, &DstSwitchMonth, &DstSwitchDayOfMonth,
727 			    &DstSwitchHour, &DstSwitchMinute);
728 			DstSwitchFlag = TRUE;
729 			break;
730 
731 		case 'h':
732 		case 'H':
733 		case '?':
734 			Help ();
735 			exit(-1);
736 			break;
737 
738 		case 'i':	/* Insert (add) a leap second at the end of the specified minute. */
739 			sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth,
740 			    &LeapHour, &LeapMinute);
741 			InsertLeapSecond = TRUE;
742 			DeleteLeapSecond = FALSE;
743 			break;
744 
745 		case 'j':
746 			EnableRateCorrection = FALSE;
747 			break;
748 
749 		case 'k':
750 			sscanf (optarg, "%d", &RateCorrection);
751 			EnableRateCorrection = FALSE;
752 			if  (RateCorrection < 0)
753 				{
754 				RemoveCycle = TRUE;
755 				AddCycle = FALSE;
756 
757 				if  (Verbose)
758 					printf ("\n> Forcing rate correction removal of cycle...\n");
759 				}
760 			else
761 				{
762 				if  (RateCorrection > 0)
763 					{
764 					RemoveCycle = FALSE;
765 					AddCycle = TRUE;
766 
767 					if  (Verbose)
768 						printf ("\n> Forcing rate correction addition of cycle...\n");
769 					}
770 				}
771 			break;
772 
773 		case 'l':	/* use time offset from UTC */
774 			sscanf(optarg, "%f", &UseOffsetHoursFloat);
775 			UseOffsetSecondsFloat = UseOffsetHoursFloat * (float) SECONDS_PER_HOUR;
776 			UseOffsetSecondsInt = (int) (UseOffsetSecondsFloat + 0.5);
777 			break;
778 
779 		case 'o':	/* Set IEEE 1344 time offset in hours - positive or negative, to the half hour */
780 			sscanf(optarg, "%f", &TimeOffset);
781 			if  (TimeOffset >= -0.2)
782 				{
783 				OffsetSignBit = 0;
784 
785 				if  (TimeOffset > 0)
786 					{
787 					OffsetOnes    = TimeOffset;
788 
789 					if  ( (TimeOffset - floor(TimeOffset)) >= 0.4)
790 						OffsetHalf = 1;
791 					else
792 						OffsetHalf = 0;
793 					}
794 				else
795 					{
796 					OffsetOnes    = 0;
797 					OffsetHalf    = 0;
798 					}
799 				}
800 			else
801 				{
802 				OffsetSignBit = 1;
803 				OffsetOnes    = -TimeOffset;
804 
805 				if  ( (ceil(TimeOffset) - TimeOffset) >= 0.4)
806 					OffsetHalf = 1;
807 				else
808 					OffsetHalf = 0;
809 				}
810 
811 			/*printf ("\nGot TimeOffset = %3.1f, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d...\n",
812 					TimeOffset, OffsetSignBit, OffsetOnes, OffsetHalf);
813 			*/
814 			break;
815 
816 		case 'q':	/* Hex quality code 0 to 0x0F - 0 = maximum, 0x0F = no lock */
817 			sscanf(optarg, "%x", &TimeQuality);
818 			TimeQuality &= 0x0F;
819 			/*printf ("\nGot TimeQuality = 0x%1X...\n", TimeQuality);
820 			*/
821 			break;
822 
823 		case 'r':	/* sample rate (nominally 8000, integer close to 8000 I hope) */
824 			sscanf(optarg, "%d", &SetSampleRate);
825 			break;
826 
827 		case 's':	/* set leap warning bit (WWV/H only) */
828 			leap++;
829 			break;
830 
831 		case 't':	/* select WWVH sync frequency */
832 			tone = 1200;
833 			break;
834 
835 		case 'u':	/* set DUT1 offset (-7 to +7) */
836 			sscanf(optarg, "%d", &dut1);
837 			if (dut1 < 0)
838 				dut1 = abs(dut1);
839 			else
840 				dut1 |= 0x8;
841 			break;
842 
843 #ifndef  HAVE_SYS_SOUNDCARD_H
844 		case 'v':	/* set output level (0-255) */
845 			sscanf(optarg, "%d", &level);
846 			break;
847 #endif
848 
849 		case 'x':	/* Turn off verbose output. */
850 			Verbose = FALSE;
851 			break;
852 
853 		case 'y':	/* Set initial date and time */
854 			sscanf(optarg, "%2d%2d%2d%2d%2d%2d", &Year, &Month, &DayOfMonth,
855 			    &Hour, &Minute, &Second);
856 			utc++;
857 			break;
858 
859 		case 'z':	/* Turn on Debug output (also turns on Verbose below) */
860 			Debug = TRUE;
861 			break;
862 
863 		default:
864 			printf("Invalid option \"%c\", aborting...\n", temp);
865 			exit (-1);
866 			break;
867 		}
868 	}
869 
870 	if  (Debug)
871 	    Verbose = TRUE;
872 
873 	if  (InsertLeapSecond || DeleteLeapSecond)
874 		{
875 		LeapDayOfYear = ConvertMonthDayToDayOfYear (LeapYear, LeapMonth, LeapDayOfMonth);
876 
877 		if	(Debug)
878 			{
879 			printf ("\nHave request for leap second %s at year %4d day %3d at %2.2dh%2.2d....\n",\
880 					DeleteLeapSecond ? "DELETION" : (InsertLeapSecond ? "ADDITION" : "( error ! )" ),
881 					LeapYear, LeapDayOfYear, LeapHour, LeapMinute);
882 			}
883 		}
884 
885 	if	(DstSwitchFlag)
886 		{
887 		DstSwitchDayOfYear = ConvertMonthDayToDayOfYear (DstSwitchYear, DstSwitchMonth, DstSwitchDayOfMonth);
888 
889 		/* Figure out time of minute previous to DST switch, so can put up warning flag in IEEE 1344 */
890 		DstSwitchPendingYear		= DstSwitchYear;
891 		DstSwitchPendingDayOfYear	= DstSwitchDayOfYear;
892 		DstSwitchPendingHour		= DstSwitchHour;
893 		DstSwitchPendingMinute		= DstSwitchMinute - 1;
894 		if 	(DstSwitchPendingMinute < 0)
895 			{
896 			DstSwitchPendingMinute = 59;
897 			DstSwitchPendingHour--;
898 			if	(DstSwitchPendingHour < 0)
899 				{
900 				DstSwitchPendingHour = 23;
901 				DstSwitchPendingDayOfYear--;
902 				if	(DstSwitchPendingDayOfYear < 1)
903 					{
904 					DstSwitchPendingYear--;
905 					}
906 				}
907 			}
908 
909 		if	(Debug)
910 			{
911 			printf ("\nHave DST switch request for year %4d day %3d at %2.2dh%2.2d,",
912 					DstSwitchYear, DstSwitchDayOfYear, DstSwitchHour, DstSwitchMinute);
913 			printf ("\n    so will have warning at year %4d day %3d at %2.2dh%2.2d.\n",
914 					DstSwitchPendingYear, DstSwitchPendingDayOfYear, DstSwitchPendingHour, DstSwitchPendingMinute);
915 			}
916 		}
917 
918 	switch (tolower(FormatCharacter)) {
919 	case 'i':
920 		printf ("\nFormat is IRIG-1998 (no year coded)...\n\n");
921 		encode = IRIG;
922 		IrigIncludeYear = FALSE;
923 		IrigIncludeIeee = FALSE;
924 		break;
925 
926 	case '2':
927 		printf ("\nFormat is IRIG-2004 (BCD year coded)...\n\n");
928 		encode = IRIG;
929 		IrigIncludeYear = TRUE;
930 		IrigIncludeIeee = FALSE;
931 		break;
932 
933 	case '3':
934 		printf ("\nFormat is IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
935 		encode = IRIG;
936 		IrigIncludeYear = TRUE;
937 		IrigIncludeIeee = TRUE;
938 		break;
939 
940 	case '4':
941 		printf ("\nFormat is unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
942 		encode = IRIG;
943 		IrigIncludeYear = TRUE;
944 		IrigIncludeIeee = TRUE;
945 
946 		Unmodulated = TRUE;
947 		UnmodulatedInverted = FALSE;
948 		break;
949 
950 	case '5':
951 		printf ("\nFormat is inverted unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
952 		encode = IRIG;
953 		IrigIncludeYear = TRUE;
954 		IrigIncludeIeee = TRUE;
955 
956 		Unmodulated = TRUE;
957 		UnmodulatedInverted = TRUE;
958 		break;
959 
960 	case 'w':
961 		printf ("\nFormat is WWV(H)...\n\n");
962 		encode = WWV;
963 		break;
964 
965 	default:
966 		printf ("\n\nUnexpected format value of \'%c\', cannot parse, aborting...\n\n", FormatCharacter);
967 		exit (-1);
968 		break;
969 	}
970 
971 	/*
972 	 * Open audio device and set options
973 	 */
974 	fd = open(device, O_WRONLY);
975 	if (fd <= 0) {
976 		printf("Unable to open audio device \"%s\", aborting: %s\n", device, strerror(errno));
977 		exit(1);
978 	}
979 
980 #ifdef  HAVE_SYS_SOUNDCARD_H
981 	/* First set coding type */
982 	AudioFormat = AFMT_MU_LAW;
983 	if (ioctl(fd, SNDCTL_DSP_SETFMT, &AudioFormat)==-1)
984 	{ /* Fatal error */
985 	printf ("\nUnable to set output format, aborting...\n\n");
986 	exit(-1);
987 	}
988 
989 	if  (AudioFormat != AFMT_MU_LAW)
990 	{
991 	printf ("\nUnable to set output format for mu law, aborting...\n\n");
992 	exit(-1);
993 	}
994 
995 	/* Next set number of channels */
996 	MonoStereo = MONO;	/* Mono */
997 	if (ioctl(fd, SNDCTL_DSP_STEREO, &MonoStereo)==-1)
998 	{ /* Fatal error */
999 	printf ("\nUnable to set mono/stereo, aborting...\n\n");
1000 	exit(-1);
1001 	}
1002 
1003 	if (MonoStereo != MONO)
1004 	{
1005 	printf ("\nUnable to set mono/stereo for mono, aborting...\n\n");
1006 	exit(-1);
1007 	}
1008 
1009 	/* Now set sample rate */
1010 	SampleRate = SetSampleRate;
1011 	if (ioctl(fd, SNDCTL_DSP_SPEED, &SampleRate)==-1)
1012 	{ /* Fatal error */
1013 	printf ("\nUnable to set sample rate to %d, returned %d, aborting...\n\n", SetSampleRate, SampleRate);
1014 	exit(-1);
1015 	}
1016 
1017 	SampleRateDifference = SampleRate - SetSampleRate;
1018 
1019 	if  (SampleRateDifference < 0)
1020 		SampleRateDifference = - SampleRateDifference;
1021 
1022 	/* Fixed allowable sample rate error 0.1% */
1023 	if (SampleRateDifference > (SetSampleRate/1000))
1024 	{
1025 	printf ("\nUnable to set sample rate to %d, result was %d, more than 0.1 percent, aborting...\n\n", SetSampleRate, SampleRate);
1026 	exit(-1);
1027 	}
1028 	else
1029 	{
1030 	/* printf ("\nAttempt to set sample rate to %d, actual %d...\n\n", SetSampleRate, SampleRate); */
1031 	}
1032 #else
1033 	rval = ioctl(fd, AUDIO_GETINFO, &info);
1034 	if (rval < 0) {
1035 		printf("\naudio control %s", strerror(errno));
1036 		exit(0);
1037 	}
1038 	info.play.port = port;
1039 	info.play.gain = level;
1040 	info.play.sample_rate = SetSampleRate;
1041 	info.play.channels = 1;
1042 	info.play.precision = 8;
1043 	info.play.encoding = AUDIO_ENCODING_ULAW;
1044 	printf("\nport %d gain %d rate %d chan %d prec %d encode %d\n",
1045 	    info.play.port, info.play.gain, info.play.sample_rate,
1046 	    info.play.channels, info.play.precision,
1047 	    info.play.encoding);
1048 	ioctl(fd, AUDIO_SETINFO, &info);
1049 #endif
1050 
1051  	/*
1052 	 * Unless specified otherwise, read the system clock and
1053 	 * initialize the time.
1054 	 */
1055 	gettimeofday(&TimeValue, NULL);		// Now always read the system time to keep "real time" of operation.
1056 	NowRealTime = BaseRealTime = SecondsPartOfTime = TimeValue.tv_sec;
1057 	SecondsRunningSimulationTime = 0;	// Just starting simulation, running zero seconds as of now.
1058 	StabilityCount = 0;					// No stability yet.
1059 
1060 	if	(utc)
1061 		{
1062 		DayOfYear = ConvertMonthDayToDayOfYear (Year, Month, DayOfMonth);
1063 		}
1064 	else
1065 		{
1066 		/* Apply offset to time. */
1067 		if	(UseOffsetSecondsInt >= 0)
1068 			SecondsPartOfTime += (time_t)   UseOffsetSecondsInt;
1069 		else
1070 			SecondsPartOfTime -= (time_t) (-UseOffsetSecondsInt);
1071 
1072 		TimeStructure = gmtime(&SecondsPartOfTime);
1073 		Minute = TimeStructure->tm_min;
1074 		Hour = TimeStructure->tm_hour;
1075 		DayOfYear = TimeStructure->tm_yday + 1;
1076 		Year = TimeStructure->tm_year % 100;
1077 		Second = TimeStructure->tm_sec;
1078 
1079 		/*
1080 		 * Delay the first second so the generator is accurately
1081 		 * aligned with the system clock within one sample (125
1082 		 * microseconds ).
1083 		 */
1084 		delay(SECOND - TimeValue.tv_usec * 8 / 1000);
1085 		}
1086 
1087 	StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR);
1088 
1089 	memset(code, 0, sizeof(code));
1090 	switch (encode) {
1091 
1092 	/*
1093 	 * For WWV/H and default time, carefully set the signal
1094 	 * generator seconds number to agree with the current time.
1095 	 */
1096 	case WWV:
1097 		printf("WWV time signal, starting point:\n");
1098 		printf(" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Minute tone = %d Hz, Hour tone = %d Hz.\n",
1099 		    Year, DayOfYear, Hour, Minute, Second, tone, HourTone);
1100 		snprintf(code, sizeof(code), "%01d%03d%02d%02d%01d",
1101 		    Year / 10, DayOfYear, Hour, Minute, Year % 10);
1102 		if  (Verbose)
1103 			{
1104 		    printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s",
1105 				Year, DayOfYear, Hour, Minute, Second, code);
1106 
1107 				if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
1108 				printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
1109 			else
1110 				printf ("\n");
1111 			}
1112 
1113 		ptr = 8;
1114 		for (BitNumber = 0; BitNumber <= Second; BitNumber++) {
1115 			if (progx[BitNumber].sw == DEC)
1116 				ptr--;
1117 		}
1118 		break;
1119 
1120 	/*
1121 	 * For IRIG the signal generator runs every second, so requires
1122 	 * no additional alignment.
1123 	 */
1124 	case IRIG:
1125 		printf ("IRIG-B time signal, starting point:\n");
1126 		printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n",
1127 		    Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds);
1128 		printf ("\n");
1129 		if  (Verbose)
1130 		    {
1131     		printf ("Codes: \".\" = marker/position indicator, \"-\" = zero dummy bit, \"0\" = zero bit, \"1\" = one bit.\n");
1132 			if  ((EnableRateCorrection) || (AddCycle) || (RemoveCycle))
1133 				{
1134 				printf ("       \"o\" = short zero, \"*\" = long zero, \"x\" = short one, \"+\" = long one.\n");
1135 				}
1136 	    	printf ("Numerical values are time order reversed in output to make it easier to read.\n");
1137     		/*                 111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999 */
1138 	    	/*       0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 */
1139 		    printf ("\n");
1140     		printf ("Legend of output codes:\n");
1141 	    	//printf ("\n");
1142 		    //printf ("|  StraightBinSecs  | IEEE_1344_Control |   Year  |    Day_of_Year    |  Hours  | Minutes |Seconds |\n");
1143     		//printf ("|  ---------------  | ----------------- |   ----  |    -----------    |  -----  | ------- |------- |\n");
1144 	    	//printf ("|                   |                   |         |                   |         |         |        |\n");
1145 	    	}
1146 		break;
1147 	}
1148 
1149 	/*
1150 	 * Run the signal generator to generate new timecode strings
1151 	 * once per minute for WWV/H and once per second for IRIG.
1152 	 */
1153 	for (CountOfSecondsSent=0; ((SecondsToSend==0) || (CountOfSecondsSent<SecondsToSend)); CountOfSecondsSent++)
1154 		{
1155 		if  ((encode == IRIG) && (((Second % 20) == 0) || (CountOfSecondsSent == 0)))
1156 			{
1157 	    	printf ("\n");
1158 
1159 			printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n",
1160 			    Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds);
1161 			if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
1162 				{
1163 				printf (" CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
1164 				if  ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0)))
1165 					{
1166 					RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent);
1167 					printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n",
1168 									RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate);
1169 					}
1170 				}
1171 			else
1172 				printf ("\n");
1173 
1174 		    /* printf ("|Seconds | Minutes |  Hours  |    Day_of_Year    |   Year  | IEEE_1344_Control |  StraightBinSecs  |\n");
1175     		printf ("|------- | ------- |  -----  |    -----------    |   ----  | ----------------- |-------------------|\n");
1176 	    	printf ("|        |         |         |                   |         |                   |                   |\n");*/
1177 		    printf ("|  StraightBinSecs  | IEEE_1344_Control |   Year  |    Day_of_Year    |  Hours  | Minutes |Seconds |\n");
1178     		printf ("|  ---------------  | ----------------- |   ----  |    -----------    |  -----  | ------- |------- |\n");
1179 	    	printf ("|                   |                   |         |                   |         |         |        |\n");
1180 			}
1181 
1182 		if  (RemoveCycle)
1183 			{
1184 			RateCorrection = -1;
1185 			TotalSecondsCorrected ++;
1186 			}
1187 		else
1188 			{
1189 			if  (AddCycle)
1190 				{
1191 				TotalSecondsCorrected ++;
1192 				RateCorrection = +1;
1193 				}
1194 			else
1195 				RateCorrection = 0;
1196 			}
1197 
1198 		/*
1199 		 * Crank the state machine to propagate carries to the
1200 		 * year of century. Note that we delayed up to one
1201 		 * second for alignment after reading the time, so this
1202 		 * is the next second.
1203 		 */
1204 
1205 		if  (LeapState == LEAPSTATE_NORMAL)
1206 			{
1207 			/* If on the second of a leap (second 59 in the specified minute), then add or delete a second */
1208 			if  ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute))
1209 				{
1210 				/* To delete a second, which means we go from 58->60 instead of 58->59->00. */
1211 				if  ((DeleteLeapSecond) && (Second == 58))
1212 					{
1213 					LeapState = LEAPSTATE_DELETING;
1214 
1215 					if	(Debug)
1216 						printf ("\n<--- Ready to delete a leap second...\n");
1217 					}
1218 				else
1219 					{	/* Delete takes precedence over insert. */
1220 					/* To add a second, which means we go from 59->60->00 instead of 59->00. */
1221 					if  ((InsertLeapSecond) && (Second == 59))
1222 						{
1223 						LeapState = LEAPSTATE_INSERTING;
1224 
1225 						if	(Debug)
1226 							printf ("\n<--- Ready to insert a leap second...\n");
1227 						}
1228 					}
1229 				}
1230 			}
1231 
1232 		switch (LeapState)
1233 			{
1234 			case LEAPSTATE_NORMAL:
1235 				Second = (Second + 1) % 60;
1236 				break;
1237 
1238 			case LEAPSTATE_DELETING:
1239 				Second = 0;
1240 				LeapState = LEAPSTATE_NORMAL;
1241 
1242 				if	(Debug)
1243 					printf ("\n<--- Deleting a leap second...\n");
1244 				break;
1245 
1246 			case LEAPSTATE_INSERTING:
1247 				Second = 60;
1248 				LeapState = LEAPSTATE_ZERO_AFTER_INSERT;
1249 
1250 				if	(Debug)
1251 					printf ("\n<--- Inserting a leap second...\n");
1252 				break;
1253 
1254 			case LEAPSTATE_ZERO_AFTER_INSERT:
1255 				Second = 0;
1256 				LeapState = LEAPSTATE_NORMAL;
1257 
1258 				if	(Debug)
1259 					printf ("\n<--- Inserted a leap second, now back to zero...\n");
1260 				break;
1261 
1262 			default:
1263 				printf ("\n\nLeap second state invalid value of %d, aborting...", LeapState);
1264 				exit (-1);
1265 				break;
1266 			}
1267 
1268 		/* Check for second rollover, increment minutes and ripple upward if required. */
1269 		if (Second == 0) {
1270 			Minute++;
1271 			if (Minute >= 60) {
1272 				Minute = 0;
1273 				Hour++;
1274 			}
1275 
1276 			/* Check for activation of DST switch. */
1277 			/* If DST is active, this would mean that at the appointed time, we de-activate DST, */
1278 			/* which translates to going backward an hour (repeating the last hour). */
1279 			/* If DST is not active, this would mean that at the appointed time, we activate DST, */
1280 			/* which translates to going forward an hour (skipping the next hour). */
1281 			if	(DstSwitchFlag)
1282 				{
1283 				/* The actual switch happens on the zero'th second of the actual minute specified. */
1284 				if	((Year == DstSwitchYear) && (DayOfYear == DstSwitchDayOfYear) && (Hour == DstSwitchHour) && (Minute == DstSwitchMinute))
1285 					{
1286 					if  (DstFlag == 0)
1287 						{	/* DST flag is zero, not in DST, going to DST, "spring ahead", so increment hour by two instead of one. */
1288 						Hour++;
1289 						DstFlag = 1;
1290 
1291 						/* Must adjust offset to keep consistent with UTC. */
1292 						/* Here we have to increase offset by one hour.  If it goes from negative to positive, then we fix that. */
1293 						if	(OffsetSignBit == 0)
1294 							{	/* Offset is positive */
1295 							if	(OffsetOnes == 0x0F)
1296 								{
1297 								OffsetSignBit = 1;
1298 								OffsetOnes    = (OffsetHalf == 0) ? 8 : 7;
1299 								}
1300 							else
1301 								OffsetOnes++;
1302 							}
1303 						else
1304 							{	/* Offset is negative */
1305 							if  (OffsetOnes == 0)
1306 								{
1307 								OffsetSignBit = 0;
1308 								OffsetOnes    = (OffsetHalf == 0) ? 1 : 0;
1309 								}
1310 							else
1311 								OffsetOnes--;
1312 							}
1313 
1314 						if	(Debug)
1315 							printf ("\n<--- DST activated, spring ahead an hour, new offset !...\n");
1316 						}
1317 					else
1318 						{	/* DST flag is non zero, in DST, going out of DST, "fall back", so no increment of hour. */
1319 						Hour--;
1320 						DstFlag = 0;
1321 
1322 						/* Must adjust offset to keep consistent with UTC. */
1323 						/* Here we have to reduce offset by one hour.  If it goes negative, then we fix that. */
1324 						if	(OffsetSignBit == 0)
1325 							{	/* Offset is positive */
1326 							if  (OffsetOnes == 0)
1327 								{
1328 								OffsetSignBit = 1;
1329 								OffsetOnes    = (OffsetHalf == 0) ? 1 : 0;
1330 								}
1331 							else
1332 								OffsetOnes--;
1333 							}
1334 						else
1335 							{	/* Offset is negative */
1336 							if	(OffsetOnes == 0x0F)
1337 								{
1338 								OffsetSignBit = 0;
1339 								OffsetOnes    = (OffsetHalf == 0) ? 8 : 7;
1340 								}
1341 							else
1342 								OffsetOnes++;
1343 							}
1344 
1345 						if	(Debug)
1346 							printf ("\n<--- DST de-activated, fall back an hour!...\n");
1347 						}
1348 
1349 					DstSwitchFlag = FALSE;	/* One time deal, not intended to run this program past two switches... */
1350 					}
1351 				}
1352 
1353 			if (Hour >= 24) {
1354 				/* Modified, just in case dumb case where activating DST advances 23h59:59 -> 01h00:00 */
1355 				Hour = Hour % 24;
1356 				DayOfYear++;
1357 			}
1358 
1359 			/*
1360 			 * At year rollover check for leap second.
1361 			 */
1362 			if (DayOfYear >= (Year & 0x3 ? 366 : 367)) {
1363 				if (leap) {
1364 					WWV_Second(DATA0, RateCorrection);
1365 					if  (Verbose)
1366 					    printf("\nLeap!");
1367 					leap = 0;
1368 				}
1369 				DayOfYear = 1;
1370 				Year++;
1371 			}
1372 			if (encode == WWV) {
1373 				snprintf(code, sizeof(code),
1374 				    "%01d%03d%02d%02d%01d", Year / 10,
1375 				    DayOfYear, Hour, Minute, Year % 10);
1376 				if  (Verbose)
1377 				    printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s",
1378 						Year, DayOfYear, Hour, Minute, Second, code);
1379 
1380 				if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
1381 					{
1382 					printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
1383 					if  ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0)))
1384 						{
1385 						RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent);
1386 						printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n",
1387 										RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate);
1388 						}
1389 					}
1390 				else
1391 					printf ("\n");
1392 
1393 				ptr = 8;
1394 			}
1395 		}	/* End of "if  (Second == 0)" */
1396 
1397 		/* After all that, if we are in the minute just prior to a leap second, warn of leap second pending */
1398 		/* and of the polarity */
1399 		if  ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute))
1400 			{
1401 			LeapSecondPending = TRUE;
1402 			LeapSecondPolarity = DeleteLeapSecond;
1403 			}
1404 		else
1405 			{
1406 			LeapSecondPending = FALSE;
1407 			LeapSecondPolarity = FALSE;
1408 			}
1409 
1410 		/* Notification through IEEE 1344 happens during the whole minute previous to the minute specified. */
1411 		/* The time of that minute has been previously calculated. */
1412 		if	((Year == DstSwitchPendingYear) && (DayOfYear == DstSwitchPendingDayOfYear) &&
1413 					(Hour == DstSwitchPendingHour) && (Minute == DstSwitchPendingMinute))
1414 			{
1415 			DstPendingFlag = TRUE;
1416 			}
1417 		else
1418 			{
1419 			DstPendingFlag = FALSE;
1420 			}
1421 
1422 
1423 		StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR);
1424 
1425 		if (encode == IRIG) {
1426 			if  (IrigIncludeIeee)
1427 				{
1428 				if  ((OffsetOnes == 0) && (OffsetHalf == 0))
1429 					OffsetSignBit = 0;
1430 
1431 				ControlFunctions = (LeapSecondPending == 0 ? 0x00000 : 0x00001) | (LeapSecondPolarity == 0 ? 0x00000 : 0x00002)
1432 						| (DstPendingFlag == 0 ? 0x00000 : 0x00004) | (DstFlag == 0 ? 0x00000 : 0x00008)
1433 						| (OffsetSignBit == 0 ? 0x00000 : 0x00010)  | ((OffsetOnes & 0x0F) << 5)           | (OffsetHalf == 0 ? 0x00000 : 0x00200)
1434 						| ((TimeQuality & 0x0F) << 10);
1435 				/* if  (Verbose)
1436 				        printf ("\nDstFlag = %d, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d, TimeQuality = 0x%1.1X ==> ControlFunctions = 0x%5.5X...",
1437 						    DstFlag, OffsetSignBit, OffsetOnes, OffsetHalf, TimeQuality, ControlFunctions);
1438 				*/
1439 				}
1440 			else
1441 				ControlFunctions = 0;
1442 
1443 			/*
1444 						      YearDay HourMin Sec
1445 			snprintf(code, sizeof(code), "%04x%04d%06d%02d%02d%02d",
1446 				0, Year, DayOfYear, Hour, Minute, Second);
1447 			*/
1448 			if  (IrigIncludeYear) {
1449 				snprintf(ParityString, sizeof(ParityString),
1450 				    "%04X%02d%04d%02d%02d%02d",
1451 				    ControlFunctions & 0x7FFF, Year,
1452 				    DayOfYear, Hour, Minute, Second);
1453 			} else {
1454 				snprintf(ParityString, sizeof(ParityString),
1455 				    "%04X%02d%04d%02d%02d%02d",
1456 				    ControlFunctions & 0x7FFF,
1457 				    0, DayOfYear, Hour, Minute, Second);
1458 			}
1459 
1460 			if  (IrigIncludeIeee)
1461 				{
1462 				ParitySum = 0;
1463 				for (StringPointer=ParityString; *StringPointer!=NUL; StringPointer++)
1464 					{
1465 					switch (toupper(*StringPointer))
1466 						{
1467 						case '1':
1468 						case '2':
1469 						case '4':
1470 						case '8':
1471 							ParitySum += 1;
1472 							break;
1473 
1474 						case '3':
1475 						case '5':
1476 						case '6':
1477 						case '9':
1478 						case 'A':
1479 						case 'C':
1480 							ParitySum += 2;
1481 							break;
1482 
1483 						case '7':
1484 						case 'B':
1485 						case 'D':
1486 						case 'E':
1487 							ParitySum += 3;
1488 							break;
1489 
1490 						case 'F':
1491 							ParitySum += 4;
1492 							break;
1493 						}
1494 					}
1495 
1496 				if  ((ParitySum & 0x01) == 0x01)
1497 					ParityValue = 0x01;
1498 				else
1499 					ParityValue = 0;
1500 				}
1501 			else
1502 				ParityValue = 0;
1503 
1504 			ControlFunctions |= ((ParityValue & 0x01) << 14);
1505 
1506 			if  (IrigIncludeYear) {
1507 				snprintf(code, sizeof(code),
1508 				    /* YearDay HourMin Sec */
1509 				    "%05X%05X%02d%04d%02d%02d%02d",
1510 				    StraightBinarySeconds,
1511 				    ControlFunctions, Year, DayOfYear,
1512 				    Hour, Minute, Second);
1513 			} else {
1514 				snprintf(code, sizeof(code),
1515 				    /* YearDay HourMin Sec */
1516 				    "%05X%05X%02d%04d%02d%02d%02d",
1517 				    StraightBinarySeconds,
1518 				    ControlFunctions, 0, DayOfYear,
1519 				    Hour, Minute, Second);
1520 			}
1521 
1522 			if  (Debug)
1523 				printf("\nCode string: %s, ParityString = %s, ParitySum = 0x%2.2X, ParityValue = %d, DstFlag = %d...\n", code, ParityString, ParitySum, ParityValue, DstFlag);
1524 
1525 			ptr = strlen(code)-1;
1526 			OldPtr = 0;
1527 		}
1528 
1529 		/*
1530 		 * Generate data for the second
1531 		 */
1532 		switch (encode) {
1533 
1534 		/*
1535 		 * The IRIG second consists of 20 BCD digits of width-
1536 		 * modulateod pulses at 2, 5 and 8 ms and modulated 50
1537 		 * percent on the 1000-Hz carrier.
1538 		 */
1539 		case IRIG:
1540 			/* Initialize the output string */
1541 			OutputDataString[0] = '\0';
1542 
1543 			for (BitNumber = 0; BitNumber < 100; BitNumber++) {
1544 				FrameNumber = (BitNumber/10) + 1;
1545 				switch (FrameNumber)
1546 					{
1547 					case 1:
1548 						/* bits 0 to 9, first frame */
1549 						sw  = progz[BitNumber % 10].sw;
1550 						arg = progz[BitNumber % 10].arg;
1551 						break;
1552 
1553 					case 2:
1554 					case 3:
1555 					case 4:
1556 					case 5:
1557 					case 6:
1558 						/* bits 10 to 59, second to sixth frame */
1559 						sw  = progy[BitNumber % 10].sw;
1560 						arg = progy[BitNumber % 10].arg;
1561 						break;
1562 
1563 					case 7:
1564 						/* bits 60 to 69, seventh frame */
1565 						sw  = progw[BitNumber % 10].sw;
1566 						arg = progw[BitNumber % 10].arg;
1567 						break;
1568 
1569 					case 8:
1570 						/* bits 70 to 79, eighth frame */
1571 						sw  = progv[BitNumber % 10].sw;
1572 						arg = progv[BitNumber % 10].arg;
1573 						break;
1574 
1575 					case 9:
1576 						/* bits 80 to 89, ninth frame */
1577 						sw  = progw[BitNumber % 10].sw;
1578 						arg = progw[BitNumber % 10].arg;
1579 						break;
1580 
1581 					case 10:
1582 						/* bits 90 to 99, tenth frame */
1583 						sw  = progu[BitNumber % 10].sw;
1584 						arg = progu[BitNumber % 10].arg;
1585 						break;
1586 
1587 					default:
1588 						/* , Unexpected values of FrameNumber */
1589 						printf ("\n\nUnexpected value of FrameNumber = %d, cannot parse, aborting...\n\n", FrameNumber);
1590 						exit (-1);
1591 						break;
1592 					}
1593 
1594 				switch(sw) {
1595 
1596 				case DECC:	/* decrement pointer and send bit. */
1597 					ptr--;
1598 				case COEF:	/* send BCD bit */
1599 					AsciiValue = toupper(code[ptr]);
1600 					HexValue   = isdigit(AsciiValue) ? AsciiValue - '0' : (AsciiValue - 'A')+10;
1601 					/* if  (Debug) {
1602 						if  (ptr != OldPtr) {
1603 						if  (Verbose)
1604 						    printf("\n(%c->%X)", AsciiValue, HexValue);
1605 						OldPtr = ptr;
1606 						}
1607 					}
1608 					*/
1609 					// OK, adjust all unused bits in hundreds of days.
1610 					if  ((FrameNumber == 5) && ((BitNumber % 10) > 1))
1611 						{
1612 						if  (RateCorrection < 0)
1613 							{	// Need to remove cycles to catch up.
1614 							if  ((HexValue & arg) != 0)
1615 								{
1616 								if  (Unmodulated)
1617 									{
1618 									poop(M5, 1000, HIGH, UnmodulatedInverted);
1619 									poop(M5-1, 1000, LOW,  UnmodulatedInverted);
1620 
1621 									TotalCyclesRemoved += 1;
1622 									}
1623 								else
1624 									{
1625 									peep(M5, 1000, HIGH);
1626 									peep(M5-1, 1000, LOW);
1627 
1628 									TotalCyclesRemoved += 1;
1629 									}
1630 								strlcat(OutputDataString, "x", OUTPUT_DATA_STRING_LENGTH);
1631 								}
1632 							else
1633 								{
1634 								if	(Unmodulated)
1635 									{
1636 									poop(M2, 1000, HIGH, UnmodulatedInverted);
1637 									poop(M8-1, 1000, LOW,  UnmodulatedInverted);
1638 
1639 									TotalCyclesRemoved += 1;
1640 									}
1641 								else
1642 									{
1643 									peep(M2, 1000, HIGH);
1644 									peep(M8-1, 1000, LOW);
1645 
1646 									TotalCyclesRemoved += 1;
1647 									}
1648 								strlcat(OutputDataString, "o", OUTPUT_DATA_STRING_LENGTH);
1649 								}
1650 							}	// End of true clause for "if  (RateCorrection < 0)"
1651 						else
1652 							{	// Else clause for "if  (RateCorrection < 0)"
1653 							if  (RateCorrection > 0)
1654 								{	// Need to add cycles to slow back down.
1655 								if  ((HexValue & arg) != 0)
1656 									{
1657 									if  (Unmodulated)
1658 										{
1659 										poop(M5, 1000, HIGH, UnmodulatedInverted);
1660 										poop(M5+1, 1000, LOW,  UnmodulatedInverted);
1661 
1662 										TotalCyclesAdded += 1;
1663 										}
1664 									else
1665 										{
1666 										peep(M5, 1000, HIGH);
1667 										peep(M5+1, 1000, LOW);
1668 
1669 										TotalCyclesAdded += 1;
1670 										}
1671 									strlcat(OutputDataString, "+", OUTPUT_DATA_STRING_LENGTH);
1672 									}
1673 								else
1674 									{
1675 									if	(Unmodulated)
1676 										{
1677 										poop(M2, 1000, HIGH, UnmodulatedInverted);
1678 										poop(M8+1, 1000, LOW,  UnmodulatedInverted);
1679 
1680 										TotalCyclesAdded += 1;
1681 										}
1682 									else
1683 										{
1684 										peep(M2, 1000, HIGH);
1685 										peep(M8+1, 1000, LOW);
1686 
1687 										TotalCyclesAdded += 1;
1688 										}
1689 									strlcat(OutputDataString, "*", OUTPUT_DATA_STRING_LENGTH);
1690 									}
1691 								}	// End of true clause for "if  (RateCorrection > 0)"
1692 							else
1693 								{	// Else clause for "if  (RateCorrection > 0)"
1694 								// Rate is OK, just do what you feel!
1695 								if  ((HexValue & arg) != 0)
1696 									{
1697 									if  (Unmodulated)
1698 										{
1699 										poop(M5, 1000, HIGH, UnmodulatedInverted);
1700 										poop(M5, 1000, LOW,  UnmodulatedInverted);
1701 										}
1702 									else
1703 										{
1704 										peep(M5, 1000, HIGH);
1705 										peep(M5, 1000, LOW);
1706 										}
1707 									strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH);
1708 									}
1709 								else
1710 									{
1711 									if	(Unmodulated)
1712 										{
1713 										poop(M2, 1000, HIGH, UnmodulatedInverted);
1714 										poop(M8, 1000, LOW,  UnmodulatedInverted);
1715 										}
1716 									else
1717 										{
1718 										peep(M2, 1000, HIGH);
1719 										peep(M8, 1000, LOW);
1720 										}
1721 									strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH);
1722 									}
1723 								}	// End of else clause for "if  (RateCorrection > 0)"
1724 							}	// End of else claues for "if  (RateCorrection < 0)"
1725 						}	// End of true clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
1726 					else
1727 						{	// Else clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
1728 						if  ((HexValue & arg) != 0)
1729 							{
1730 							if  (Unmodulated)
1731 								{
1732 								poop(M5, 1000, HIGH, UnmodulatedInverted);
1733 								poop(M5, 1000, LOW,  UnmodulatedInverted);
1734 								}
1735 							else
1736 								{
1737 								peep(M5, 1000, HIGH);
1738 								peep(M5, 1000, LOW);
1739 								}
1740 							strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH);
1741 							}
1742 						else
1743 							{
1744 							if	(Unmodulated)
1745 								{
1746 								poop(M2, 1000, HIGH, UnmodulatedInverted);
1747 								poop(M8, 1000, LOW,  UnmodulatedInverted);
1748 								}
1749 							else
1750 								{
1751 								peep(M2, 1000, HIGH);
1752 								peep(M8, 1000, LOW);
1753 								}
1754 							strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH);
1755 							}
1756 						} // end of else clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
1757 					break;
1758 
1759 				case DECZ:	/* decrement pointer and send zero bit */
1760 					ptr--;
1761 					if	(Unmodulated)
1762 						{
1763 						poop(M2, 1000, HIGH, UnmodulatedInverted);
1764 						poop(M8, 1000, LOW,  UnmodulatedInverted);
1765 						}
1766 					else
1767 						{
1768 						peep(M2, 1000, HIGH);
1769 						peep(M8, 1000, LOW);
1770 						}
1771 					strlcat(OutputDataString, "-", OUTPUT_DATA_STRING_LENGTH);
1772 					break;
1773 
1774 				case DEC:	/* send marker/position indicator IM/PI bit */
1775 					ptr--;
1776 				case NODEC:	/* send marker/position indicator IM/PI bit but no decrement pointer */
1777 				case MIN:	/* send "second start" marker/position indicator IM/PI bit */
1778 					if  (Unmodulated)
1779 						{
1780 						poop(arg,      1000, HIGH, UnmodulatedInverted);
1781 						poop(10 - arg, 1000, LOW,  UnmodulatedInverted);
1782 						}
1783 					else
1784 						{
1785 						peep(arg,      1000, HIGH);
1786 						peep(10 - arg, 1000, LOW);
1787 						}
1788 					strlcat(OutputDataString, ".", OUTPUT_DATA_STRING_LENGTH);
1789 					break;
1790 
1791 				default:
1792 					printf ("\n\nUnknown state machine value \"%d\", unable to continue, aborting...\n\n", sw);
1793 					exit (-1);
1794 					break;
1795 				}
1796 				if (ptr < 0)
1797 					break;
1798 			}
1799 			ReverseString ( OutputDataString );
1800 			if  (Verbose)
1801 				{
1802     			printf("%s", OutputDataString);
1803 				if  (RateCorrection > 0)
1804 					printf(" fast\n");
1805 				else
1806 					{
1807 					if  (RateCorrection < 0)
1808 						printf (" slow\n");
1809 					else
1810 						printf ("\n");
1811 					}
1812 				}
1813 			break;
1814 
1815 		/*
1816 		 * The WWV/H second consists of 9 BCD digits of width-
1817 		 * modulateod pulses 200, 500 and 800 ms at 100-Hz.
1818 		 */
1819 		case WWV:
1820 			sw = progx[Second].sw;
1821 			arg = progx[Second].arg;
1822 			switch(sw) {
1823 
1824 			case DATA:		/* send data bit */
1825 				WWV_Second(arg, RateCorrection);
1826 				if  (Verbose)
1827 					{
1828 					if  (arg == DATA0)
1829 						printf ("0");
1830 					else
1831 						{
1832 						if  (arg == DATA1)
1833 							printf ("1");
1834 						else
1835 							{
1836 							if  (arg == PI)
1837 								printf ("P");
1838 							else
1839 								printf ("?");
1840 							}
1841 						}
1842 					}
1843 				break;
1844 
1845 			case DATAX:		/* send data bit */
1846 				WWV_SecondNoTick(arg, RateCorrection);
1847 				if  (Verbose)
1848 					{
1849 					if  (arg == DATA0)
1850 						printf ("0");
1851 					else
1852 						{
1853 						if  (arg == DATA1)
1854 							printf ("1");
1855 						else
1856 							{
1857 							if  (arg == PI)
1858 								printf ("P");
1859 							else
1860 								printf ("?");
1861 							}
1862 						}
1863 					}
1864 				break;
1865 
1866 			case COEF:		/* send BCD bit */
1867 				if (code[ptr] & arg) {
1868 					WWV_Second(DATA1, RateCorrection);
1869 					if  (Verbose)
1870 					    printf("1");
1871 				} else {
1872 					WWV_Second(DATA0, RateCorrection);
1873 					if  (Verbose)
1874 					    printf("0");
1875 				}
1876 				break;
1877 
1878 			case LEAP:		/* send leap bit */
1879 				if (leap) {
1880 					WWV_Second(DATA1, RateCorrection);
1881 					if  (Verbose)
1882 					    printf("L");
1883 				} else {
1884 					WWV_Second(DATA0, RateCorrection);
1885 					if  (Verbose)
1886 					    printf("0");
1887 				}
1888 				break;
1889 
1890 			case DEC:		/* send data bit */
1891 				ptr--;
1892 				WWV_Second(arg, RateCorrection);
1893 				if  (Verbose)
1894 					{
1895 					if  (arg == DATA0)
1896 						printf ("0");
1897 					else
1898 						{
1899 						if  (arg == DATA1)
1900 							printf ("1");
1901 						else
1902 							{
1903 							if  (arg == PI)
1904 								printf ("P");
1905 							else
1906 								printf ("?");
1907 							}
1908 						}
1909 					}
1910 				break;
1911 
1912 			case DECX:		/* send data bit with no tick */
1913 				ptr--;
1914 				WWV_SecondNoTick(arg, RateCorrection);
1915 				if  (Verbose)
1916 					{
1917 					if  (arg == DATA0)
1918 						printf ("0");
1919 					else
1920 						{
1921 						if  (arg == DATA1)
1922 							printf ("1");
1923 						else
1924 							{
1925 							if  (arg == PI)
1926 								printf ("P");
1927 							else
1928 								printf ("?");
1929 							}
1930 						}
1931 					}
1932 				break;
1933 
1934 			case MIN:		/* send minute sync */
1935 				if  (Minute == 0)
1936 					{
1937 					peep(arg, HourTone, HIGH);
1938 
1939 					if  (RateCorrection < 0)
1940 						{
1941 						peep( 990 - arg, HourTone, OFF);
1942 						TotalCyclesRemoved += 10;
1943 
1944 						if  (Debug)
1945 							printf ("\n* Shorter Second: ");
1946 						}
1947 					else
1948 						{
1949 						if	(RateCorrection > 0)
1950 							{
1951 							peep(1010 - arg, HourTone, OFF);
1952 
1953 							TotalCyclesAdded += 10;
1954 
1955 							if  (Debug)
1956 								printf ("\n* Longer Second: ");
1957 							}
1958 						else
1959 							{
1960 							peep(1000 - arg, HourTone, OFF);
1961 							}
1962 						}
1963 
1964 					if  (Verbose)
1965 					    printf("H");
1966 					}
1967 				else
1968 					{
1969 					peep(arg, tone, HIGH);
1970 
1971 					if  (RateCorrection < 0)
1972 						{
1973 						peep( 990 - arg, tone, OFF);
1974 						TotalCyclesRemoved += 10;
1975 
1976 						if  (Debug)
1977 							printf ("\n* Shorter Second: ");
1978 						}
1979 					else
1980 						{
1981 						if	(RateCorrection > 0)
1982 							{
1983 							peep(1010 - arg, tone, OFF);
1984 
1985 							TotalCyclesAdded += 10;
1986 
1987 							if  (Debug)
1988 								printf ("\n* Longer Second: ");
1989 							}
1990 						else
1991 							{
1992 							peep(1000 - arg, tone, OFF);
1993 							}
1994 						}
1995 
1996 					if  (Verbose)
1997 					    printf("M");
1998 					}
1999 				break;
2000 
2001 			case DUT1:		/* send DUT1 bits */
2002 				if (dut1 & arg)
2003 					{
2004 					WWV_Second(DATA1, RateCorrection);
2005 					if  (Verbose)
2006 					    printf("1");
2007 					}
2008 				else
2009 					{
2010 					WWV_Second(DATA0, RateCorrection);
2011 					if  (Verbose)
2012 					    printf("0");
2013 					}
2014 				break;
2015 
2016 			case DST1:		/* send DST1 bit */
2017 				ptr--;
2018 				if (DstFlag)
2019 					{
2020 					WWV_Second(DATA1, RateCorrection);
2021 					if  (Verbose)
2022 					    printf("1");
2023 					}
2024 				else
2025 					{
2026 					WWV_Second(DATA0, RateCorrection);
2027 					if  (Verbose)
2028 					    printf("0");
2029 					}
2030 				break;
2031 
2032 			case DST2:		/* send DST2 bit */
2033 				if (DstFlag)
2034 					{
2035 					WWV_Second(DATA1, RateCorrection);
2036 					if  (Verbose)
2037 					    printf("1");
2038 					}
2039 				else
2040 					{
2041 					WWV_Second(DATA0, RateCorrection);
2042 					if  (Verbose)
2043 					    printf("0");
2044 					}
2045 				break;
2046 			}
2047 		}
2048 
2049 	if  (EnableRateCorrection)
2050 		{
2051 		SecondsRunningSimulationTime++;
2052 
2053 		gettimeofday(&TimeValue, NULL);
2054 		NowRealTime = TimeValue.tv_sec;
2055 
2056 		if  (NowRealTime >= BaseRealTime)		// Just in case system time corrects backwards, do not blow up.
2057 			{
2058 			SecondsRunningRealTime = (unsigned) (NowRealTime - BaseRealTime);
2059 			SecondsRunningDifference = SecondsRunningSimulationTime - SecondsRunningRealTime;
2060 
2061 			if  (Debug)
2062 				{
2063 				printf ("> NowRealTime = 0x%8.8X, BaseRealtime = 0x%8.8X, SecondsRunningRealTime = 0x%8.8X, SecondsRunningSimulationTime = 0x%8.8X.\n",
2064 							(unsigned) NowRealTime, (unsigned) BaseRealTime, SecondsRunningRealTime, SecondsRunningSimulationTime);
2065 				printf ("> SecondsRunningDifference = 0x%8.8X, ExpectedRunningDifference = 0x%8.8X.\n",
2066 							SecondsRunningDifference, ExpectedRunningDifference);
2067 				}
2068 
2069 			if  (SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK)
2070 				{
2071 				if  (StabilityCount < MINIMUM_STABILITY_COUNT)
2072 					{
2073 					if  (StabilityCount == 0)
2074 						{
2075 						ExpectedRunningDifference = SecondsRunningDifference;
2076 						StabilityCount++;
2077 						if  (Debug)
2078 							printf ("> Starting stability check.\n");
2079 						}
2080 					else
2081 						{	// Else for "if  (StabilityCount == 0)"
2082 						if  ((ExpectedRunningDifference+INITIAL_STABILITY_BAND > SecondsRunningDifference)
2083 								&& (ExpectedRunningDifference-INITIAL_STABILITY_BAND < SecondsRunningDifference))
2084 							{	// So far, still within stability band, increment count.
2085 							StabilityCount++;
2086 							if  (Debug)
2087 								printf ("> StabilityCount = %d.\n", StabilityCount);
2088 							}
2089 						else
2090 							{	// Outside of stability band, start over.
2091 							StabilityCount = 0;
2092 							if  (Debug)
2093 								printf ("> Out of stability band, start over.\n");
2094 							}
2095 						} // End of else for "if  (StabilityCount == 0)"
2096 					}	// End of true clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))"
2097 				else
2098 					{	// Else clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))" - OK, so we are supposed to be stable.
2099 					if  (AddCycle)
2100 						{
2101 						if  (ExpectedRunningDifference >= SecondsRunningDifference)
2102 							{
2103 							if  (Debug)
2104 								printf ("> Was adding cycles, ExpectedRunningDifference >= SecondsRunningDifference, can stop it now.\n");
2105 
2106 							AddCycle = FALSE;
2107 							RemoveCycle = FALSE;
2108 							}
2109 						else
2110 							{
2111 							if  (Debug)
2112 								printf ("> Was adding cycles, not done yet.\n");
2113 							}
2114 						}
2115 					else
2116 						{
2117 						if  (RemoveCycle)
2118 							{
2119 							if  (ExpectedRunningDifference <= SecondsRunningDifference)
2120 								{
2121 								if  (Debug)
2122 									printf ("> Was removing cycles, ExpectedRunningDifference <= SecondsRunningDifference, can stop it now.\n");
2123 
2124 								AddCycle = FALSE;
2125 								RemoveCycle = FALSE;
2126 								}
2127 							else
2128 								{
2129 								if  (Debug)
2130 									printf ("> Was removing cycles, not done yet.\n");
2131 								}
2132 							}
2133 						else
2134 							{
2135 							if  ((ExpectedRunningDifference+RUNNING_STABILITY_BAND > SecondsRunningDifference)
2136 									&& (ExpectedRunningDifference-RUNNING_STABILITY_BAND < SecondsRunningDifference))
2137 								{	// All is well, within tolerances.
2138 								if  (Debug)
2139 									printf ("> All is well, within tolerances.\n");
2140 								}
2141 							else
2142 								{	// Oops, outside tolerances.  Else clause of "if  ((ExpectedRunningDifference...SecondsRunningDifference)"
2143 								if  (ExpectedRunningDifference > SecondsRunningDifference)
2144 									{
2145 									if  (Debug)
2146 										printf ("> ExpectedRunningDifference > SecondsRunningDifference, running behind real time.\n");
2147 
2148 									// Behind real time, have to add a cycle to slow down and get back in sync.
2149 									AddCycle = FALSE;
2150 									RemoveCycle = TRUE;
2151 									}
2152 								else
2153 									{	// Else clause of "if  (ExpectedRunningDifference < SecondsRunningDifference)"
2154 									if  (ExpectedRunningDifference < SecondsRunningDifference)
2155 										{
2156 										if  (Debug)
2157 											printf ("> ExpectedRunningDifference < SecondsRunningDifference, running ahead of real time.\n");
2158 
2159 										// Ahead of real time, have to remove a cycle to speed up and get back in sync.
2160 										AddCycle = TRUE;
2161 										RemoveCycle = FALSE;
2162 										}
2163 									else
2164 										{
2165 										if  (Debug)
2166 											printf ("> Oops, outside tolerances, but doesn't fit the profiles, how can this be?\n");
2167 										}
2168 									}	// End of else clause of "if  (ExpectedRunningDifference > SecondsRunningDifference)"
2169 								}	// End of else clause of "if  ((ExpectedRunningDifference...SecondsRunningDifference)"
2170 							}	// End of else clause of "if  (RemoveCycle)".
2171 						}	// End of else clause of "if  (AddCycle)".
2172 					}	// End of else clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))"
2173 				}	// End of true clause for "if  ((SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK)"
2174 			}	// End of true clause for "if  (NowRealTime >= BaseRealTime)"
2175 		else
2176 			{
2177 			if  (Debug)
2178 				printf ("> Hmm, time going backwards?\n");
2179 			}
2180 		}	// End of true clause for "if  (EnableRateCorrection)"
2181 
2182 	fflush (stdout);
2183 	}
2184 
2185 
2186 printf ("\n\n>> Completed %d seconds, exiting...\n\n", SecondsToSend);
2187 return (0);
2188 }
2189 
2190 
2191 /*
2192  * Generate WWV/H 0 or 1 data pulse.
2193  */
2194 void WWV_Second(
2195 	int	code,		/* DATA0, DATA1, PI */
2196 	int Rate		/* <0 -> do a short second, 0 -> normal second, >0 -> long second */
2197 	)
2198 {
2199 	/*
2200 	 * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
2201 	 * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
2202 	 * 100 Hz corresponding to 0, 1 or position indicator (PI),
2203 	 * respectively. Note the 100-Hz data pulses are transmitted 6
2204 	 * dB below the 1000-Hz sync pulses. Originally the data pulses
2205 	 * were transmited 10 dB below the sync pulses, but the station
2206 	 * engineers increased that to 6 dB because the Heath GC-1000
2207 	 * WWV/H radio clock worked much better.
2208 	 */
2209 	peep(5, tone, HIGH);		/* send seconds tick */
2210 	peep(25, tone, OFF);
2211 	peep(code - 30, 100, LOW);	/* send data */
2212 
2213 	/* The quiet time is shortened or lengthened to get us back on time */
2214 	if  (Rate < 0)
2215 		{
2216 		peep( 990 - code, 100, OFF);
2217 
2218 		TotalCyclesRemoved += 10;
2219 
2220 		if  (Debug)
2221 			printf ("\n* Shorter Second: ");
2222 		}
2223 	else
2224 		{
2225 		if  (Rate > 0)
2226 			{
2227 			peep(1010 - code, 100, OFF);
2228 
2229 			TotalCyclesAdded += 10;
2230 
2231 			if  (Debug)
2232 				printf ("\n* Longer Second: ");
2233 			}
2234 		else
2235 			peep(1000 - code, 100, OFF);
2236 		}
2237 }
2238 
2239 /*
2240  * Generate WWV/H 0 or 1 data pulse, with no tick, for 29th and 59th seconds
2241  */
2242 void WWV_SecondNoTick(
2243 	int	code,		/* DATA0, DATA1, PI */
2244 	int Rate		/* <0 -> do a short second, 0 -> normal second, >0 -> long second */
2245 	)
2246 {
2247 	/*
2248 	 * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
2249 	 * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
2250 	 * 100 Hz corresponding to 0, 1 or position indicator (PI),
2251 	 * respectively. Note the 100-Hz data pulses are transmitted 6
2252 	 * dB below the 1000-Hz sync pulses. Originally the data pulses
2253 	 * were transmited 10 dB below the sync pulses, but the station
2254 	 * engineers increased that to 6 dB because the Heath GC-1000
2255 	 * WWV/H radio clock worked much better.
2256 	 */
2257 	peep(30, tone, OFF);		/* send seconds non-tick */
2258 	peep(code - 30, 100, LOW);	/* send data */
2259 
2260 	/* The quiet time is shortened or lengthened to get us back on time */
2261 	if  (Rate < 0)
2262 		{
2263 		peep( 990 - code, 100, OFF);
2264 
2265 		TotalCyclesRemoved += 10;
2266 
2267 		if  (Debug)
2268 			printf ("\n* Shorter Second: ");
2269 		}
2270 	else
2271 		{
2272 		if  (Rate > 0)
2273 			{
2274 			peep(1010 - code, 100, OFF);
2275 
2276 			TotalCyclesAdded += 10;
2277 
2278 			if  (Debug)
2279 				printf ("\n* Longer Second: ");
2280 			}
2281 		else
2282 			peep(1000 - code, 100, OFF);
2283 		}
2284 }
2285 
2286 /*
2287  * Generate cycles of 100 Hz or any multiple of 100 Hz.
2288  */
2289 void peep(
2290 	int	pulse,		/* pulse length (ms) */
2291 	int	freq,		/* frequency (Hz) */
2292 	int	amp		/* amplitude */
2293 	)
2294 {
2295 	int	increm;		/* phase increment */
2296 	int	i, j;
2297 
2298 	if (amp == OFF || freq == 0)
2299 		increm = 10;
2300 	else
2301 		increm = freq / 100;
2302 	j = 0;
2303 	for (i = 0 ; i < pulse * 8; i++) {
2304 		switch (amp) {
2305 
2306 		case HIGH:
2307 			buffer[bufcnt++] = ~c6000[j];
2308 			break;
2309 
2310 		case LOW:
2311 			buffer[bufcnt++] = ~c3000[j];
2312 			break;
2313 
2314 		default:
2315 			buffer[bufcnt++] = ~0;
2316 		}
2317 		if (bufcnt >= BUFLNG) {
2318 			write(fd, buffer, BUFLNG);
2319 			bufcnt = 0;
2320 		}
2321 		j = (j + increm) % 80;
2322 	}
2323 }
2324 
2325 
2326 /*
2327  * Generate unmodulated from similar tables.
2328  */
2329 void poop(
2330 	int	pulse,		/* pulse length (ms) */
2331 	int	freq,		/* frequency (Hz) */
2332 	int	amp,		/* amplitude */
2333 	int inverted	/* is upside down */
2334 	)
2335 {
2336 	int	increm;		/* phase increment */
2337 	int	i, j;
2338 
2339 	if (amp == OFF || freq == 0)
2340 		increm = 10;
2341 	else
2342 		increm = freq / 100;
2343 	j = 0;
2344 	for (i = 0 ; i < pulse * 8; i++) {
2345 		switch (amp) {
2346 
2347 		case HIGH:
2348 			if  (inverted)
2349 				buffer[bufcnt++] = ~u3000[j];
2350 			else
2351 				buffer[bufcnt++] = ~u6000[j];
2352 			break;
2353 
2354 		case LOW:
2355 			if  (inverted)
2356 				buffer[bufcnt++] = ~u6000[j];
2357 			else
2358 				buffer[bufcnt++] = ~u3000[j];
2359 			break;
2360 
2361 		default:
2362 			buffer[bufcnt++] = ~0;
2363 		}
2364 		if (bufcnt >= BUFLNG) {
2365 			write(fd, buffer, BUFLNG);
2366 			bufcnt = 0;
2367 		}
2368 		j = (j + increm) % 80;
2369 	}
2370 }
2371 
2372 /*
2373  * Delay for initial phasing
2374  */
2375 void delay (
2376 	int	Delay		/* delay in samples */
2377 	)
2378 {
2379 	int	samples;	/* samples remaining */
2380 
2381 	samples = Delay;
2382 	memset(buffer, 0, BUFLNG);
2383 	while (samples >= BUFLNG) {
2384 		write(fd, buffer, BUFLNG);
2385 		samples -= BUFLNG;
2386 	}
2387 		write(fd, buffer, samples);
2388 }
2389 
2390 
2391 /* Calc day of year from year month & day */
2392 /* Year - 0 means 2000, 100 means 2100. */
2393 /* Month - 1 means January, 12 means December. */
2394 /* DayOfMonth - 1 is first day of month */
2395 int
2396 ConvertMonthDayToDayOfYear (int YearValue, int MonthValue, int DayOfMonthValue)
2397 	{
2398 	int	ReturnValue;
2399 	int	LeapYear;
2400 	int	MonthCounter;
2401 
2402 	/* Array of days in a month.  Note that here January is zero. */
2403 	/* NB: have to add 1 to days in February in a leap year! */
2404 	int DaysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
2405 
2406 
2407 	LeapYear = FALSE;
2408 	if  ((YearValue % 4) == 0)
2409 		{
2410 		if  ((YearValue % 100) == 0)
2411 			{
2412 			if  ((YearValue % 400) == 0)
2413 				{
2414 				LeapYear = TRUE;
2415 				}
2416 			}
2417 		else
2418 			{
2419 			LeapYear = TRUE;
2420 			}
2421 		}
2422 
2423 	if  (Debug)
2424 		printf ("\nConvertMonthDayToDayOfYear(): Year %d %s a leap year.\n", YearValue+2000, LeapYear ? "is" : "is not");
2425 
2426 	/* Day of month given us starts in this algorithm. */
2427 	ReturnValue = DayOfMonthValue;
2428 
2429 	/* Add in days in month for each month past January. */
2430 	for (MonthCounter=1; MonthCounter<MonthValue; MonthCounter++)
2431 		{
2432 		ReturnValue += DaysInMonth [ MonthCounter - 1 ];
2433 		}
2434 
2435 	/* Add a day for leap years where we are past February. */
2436 	if  ((LeapYear) && (MonthValue > 2))
2437 		{
2438 		ReturnValue++;
2439 		}
2440 
2441 	if  (Debug)
2442 		printf ("\nConvertMonthDayToDayOfYear(): %4.4d-%2.2d-%2.2d represents day %3d of year.\n",
2443 				YearValue+2000, MonthValue, DayOfMonthValue, ReturnValue);
2444 
2445 	return (ReturnValue);
2446 	}
2447 
2448 
2449 void
2450 Help ( void )
2451 	{
2452 	printf ("\n\nTime Code Generation - IRIG-B or WWV, v%d.%d, %s dmw", VERSION, ISSUE, ISSUE_DATE);
2453 	printf ("\n\nRCS Info:");
2454 	printf (  "\n  $Header: /home/dmw/src/IRIG_generation/ntp-4.2.2p3/util/RCS/tg.c,v 1.28 2007/02/12 23:57:45 dmw Exp $");
2455 	printf ("\n\nUsage: %s [option]*", CommandName);
2456 	printf ("\n\nOptions: -a device_name                 Output audio device name (default /dev/audio)");
2457 	printf (  "\n         -b yymmddhhmm                  Remove leap second at end of minute specified");
2458 	printf (  "\n         -c seconds_to_send             Number of seconds to send (default 0 = forever)");
2459 	printf (  "\n         -d                             Start with IEEE 1344 DST active");
2460 	printf (  "\n         -f format_type                 i = Modulated IRIG-B 1998 (no year coded)");
2461 	printf (  "\n                                        2 = Modulated IRIG-B 2002 (year coded)");
2462 	printf (  "\n                                        3 = Modulated IRIG-B w/IEEE 1344 (year & control funcs) (default)");
2463 	printf (  "\n                                        4 = Unmodulated IRIG-B w/IEEE 1344 (year & control funcs)");
2464 	printf (  "\n                                        5 = Inverted unmodulated IRIG-B w/IEEE 1344 (year & control funcs)");
2465 	printf (  "\n                                        w = WWV(H)");
2466 	printf (  "\n         -g yymmddhhmm                  Switch into/out of DST at beginning of minute specified");
2467 	printf (  "\n         -i yymmddhhmm                  Insert leap second at end of minute specified");
2468 	printf (  "\n         -j                             Disable time rate correction against system clock (default enabled)");
2469 	printf (  "\n         -k nn                          Force rate correction for testing (+1 = add cycle, -1 = remove cycle)");
2470 	printf (  "\n         -l time_offset                 Set offset of time sent to UTC as per computer, +/- float hours");
2471 	printf (  "\n         -o time_offset                 Set IEEE 1344 time offset, +/-, to 0.5 hour (default 0)");
2472 	printf (  "\n         -q quality_code_hex            Set IEEE 1344 quality code (default 0)");
2473 	printf (  "\n         -r sample_rate                 Audio sample rate (default 8000)");
2474 	printf (  "\n         -s                             Set leap warning bit (WWV[H] only)");
2475 	printf (  "\n         -t sync_frequency              WWV(H) on-time pulse tone frequency (default 1200)");
2476 	printf (  "\n         -u DUT1_offset                 Set WWV(H) DUT1 offset -7 to +7 (default 0)");
2477 #ifndef  HAVE_SYS_SOUNDCARD_H
2478 	printf (  "\n         -v initial_output_level        Set initial output level (default %d, must be 0 to 255)", AUDIO_MAX_GAIN/8);
2479 #endif
2480 	printf (  "\n         -x                             Turn off verbose output (default on)");
2481 	printf (  "\n         -y yymmddhhmmss                Set initial date and time as specified (default system time)");
2482 	printf ("\n\nThis software licenced under the GPL, modifications performed 2006 & 2007 by Dean Weiten");
2483 	printf (  "\nContact: Dean Weiten, Norscan Instruments Ltd., Winnipeg, MB, Canada, ph (204)-233-9138, E-mail dmw@norscan.com");
2484 	printf ("\n\n");
2485 	}
2486 
2487 /* Reverse string order for nicer print. */
2488 void
2489 ReverseString(char *str)
2490 	{
2491 	int		StringLength;
2492 	int		IndexCounter;
2493 	int		CentreOfString;
2494 	char	TemporaryCharacter;
2495 
2496 
2497 	StringLength	= strlen(str);
2498 	CentreOfString	= (StringLength/2)+1;
2499 	for (IndexCounter = StringLength; IndexCounter >= CentreOfString; IndexCounter--)
2500 		{
2501 		TemporaryCharacter				= str[IndexCounter-1];
2502 		str[IndexCounter-1]				= str[StringLength-IndexCounter];
2503 		str[StringLength-IndexCounter]	= TemporaryCharacter;
2504 		}
2505 	}
2506 
2507