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" */
261int 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" */
272int 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 */
285int 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 */
296int 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 */
311struct 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 */
336struct 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 */
407struct 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 */
423struct 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 */
439struct 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 */
455struct 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 */
471struct 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 */
494void	WWV_Second(int, int);		/* send second */
495void	WWV_SecondNoTick(int, int);	/* send second with no tick */
496void	digit(int);		/* encode digit */
497void	peep(int, int, int);	/* send cycles */
498void	poop(int, int, int, int); /* Generate unmodulated from similar tables */
499void	delay(int);		/* delay samples */
500int		ConvertMonthDayToDayOfYear (int, int, int);	/* Calc day of year from year month & day */
501void	Help (void);	/* Usage message */
502void	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 */
512char	buffer[BUFLNG];		/* output buffer */
513int	bufcnt = 0;		/* buffer counter */
514int	fd;			/* audio codec file descriptor */
515int	tone = 1000;		/* WWV sync frequency */
516int HourTone = 1500;	/* WWV hour on-time frequency */
517int	encode = IRIG;		/* encoder select */
518int	leap = 0;		/* leap indicator */
519int	DstFlag = 0;		/* winter/summer time */
520int	dut1 = 0;		/* DUT1 correction (sign, magnitude) */
521int	utc = 0;		/* option epoch */
522int IrigIncludeYear = FALSE;	/* Whether to send year in first control functions area, between P5 and P6. */
523int IrigIncludeIeee = FALSE;	/* Whether to send IEEE 1344 control functions extensions between P6 and P8. */
524int	StraightBinarySeconds = 0;
525int	ControlFunctions = 0;
526int	Debug = FALSE;
527int Verbose = TRUE;
528char	*CommandName;
529
530#ifndef  HAVE_SYS_SOUNDCARD_H
531int	level = AUDIO_MAX_GAIN / 8; /* output level */
532int	port = AUDIO_LINE_OUT;	/* output port */
533#endif
534
535int		TotalSecondsCorrected = 0;
536int		TotalCyclesAdded = 0;
537int		TotalCyclesRemoved = 0;
538
539
540/*
541 * Main program
542 */
543int
544main(
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
2186printf ("\n\n>> Completed %d seconds, exiting...\n\n", SecondsToSend);
2187return (0);
2188}
2189
2190
2191/*
2192 * Generate WWV/H 0 or 1 data pulse.
2193 */
2194void 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 */
2242void 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 */
2289void 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 */
2329void 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 */
2375void 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 */
2395int
2396ConvertMonthDayToDayOfYear (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
2449void
2450Help ( 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. */
2488void
2489ReverseString(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