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