1275970Scy/*
2275970Scy * tg.c generate WWV or IRIG signals for test
3275970Scy */
4275970Scy/*
5275970Scy * This program can generate audio signals that simulate the WWV/H
6275970Scy * broadcast timecode. Alternatively, it can generate the IRIG-B
7275970Scy * timecode commonly used to synchronize laboratory equipment. It is
8275970Scy * intended to test the WWV/H driver (refclock_wwv.c) and the IRIG
9275970Scy * driver (refclock_irig.c) in the NTP driver collection.
10275970Scy *
11275970Scy * Besides testing the drivers themselves, this program can be used to
12275970Scy * synchronize remote machines over audio transmission lines or program
13275970Scy * feeds. The program reads the time on the local machine and sets the
14275970Scy * initial epoch of the signal generator within one millisecond.
15275970Scy * Alernatively, the initial epoch can be set to an arbitrary time. This
16275970Scy * is useful when searching for bugs and testing for correct response to
17275970Scy * a leap second in UTC. Note however, the ultimate accuracy is limited
18275970Scy * by the intrinsic frequency error of the codec sample clock, which can
19275970Scy # reach well over 100 PPM.
20275970Scy *
21275970Scy * The default is to route generated signals to the line output
22275970Scy * jack; the s option on the command line routes these signals to the
23275970Scy * internal speaker as well. The v option controls the speaker volume
24275970Scy * over the range 0-255. The signal generator by default uses WWV
25275970Scy * format; the h option switches to WWVH format and the i option
26275970Scy * switches to IRIG-B format.
27275970Scy *
28275970Scy * Once started the program runs continuously. The default initial epoch
29275970Scy * for the signal generator is read from the computer system clock when
30275970Scy * the program starts. The y option specifies an alternate epoch using a
31275970Scy * string yydddhhmmss, where yy is the year of century, ddd the day of
32275970Scy * year, hh the hour of day and mm the minute of hour. For instance,
33275970Scy * 1946Z on 1 January 2006 is 060011946. The l option lights the leap
34275970Scy * warning bit in the WWV/H timecode, so is handy to check for correct
35275970Scy * behavior at the next leap second epoch. The remaining options are
36275970Scy * specified below under the Parse Options heading. Most of these are
37275970Scy * for testing.
38275970Scy *
39275970Scy * During operation the program displays the WWV/H timecode (9 digits)
40275970Scy * or IRIG timecode (20 digits) as each new string is constructed. The
41275970Scy * display is followed by the BCD binary bits as transmitted. Note that
42275970Scy * the transmissionorder is low-order first as the frame is processed
43275970Scy * left to right. For WWV/H The leap warning L preceeds the first bit.
44275970Scy * For IRIG the on-time marker M preceeds the first (units) bit, so its
45275970Scy * code is delayed one bit and the next digit (tens) needs only three
46275970Scy * bits.
47275970Scy *
48275970Scy * The program has been tested with the Sun Blade 1500 running Solaris
49275970Scy * 10, but not yet with other machines. It uses no special features and
50275970Scy * should be readily portable to other hardware and operating systems.
51275970Scy *
52275970Scy * $Log: tg.c,v $
53275970Scy * Revision 1.28  2007/02/12 23:57:45  dmw
54275970Scy * v0.23 2007-02-12 dmw:
55275970Scy * - Changed statistics to include calculated error
56275970Scy *   of frequency, based on number of added or removed
57275970Scy *   cycles over time.
58275970Scy *
59275970Scy * Revision 1.27  2007/02/09 02:28:59  dmw
60275970Scy * v0.22 2007-02-08 dmw:
61275970Scy * - Changed default for rate correction to "enabled", "-j" switch now disables.
62275970Scy * - Adjusted help message accordingly.
63275970Scy * - Added "2007" to modifications note at end of help message.
64275970Scy *
65275970Scy * Revision 1.26  2007/02/08 03:36:17  dmw
66275970Scy * v0.21 2007-02-07 dmw:
67275970Scy * - adjusted strings for shorten and lengthen to make
68275970Scy *   fit on smaller screen.
69275970Scy *
70275970Scy * Revision 1.25  2007/02/01 06:08:09  dmw
71275970Scy * v0.20 2007-02-01 dmw:
72275970Scy * - Added periodic display of running time along with legend on IRIG-B, allows tracking how
73275970Scy *   close IRIG output is to actual clock time.
74275970Scy *
75275970Scy * Revision 1.24  2007/01/31 19:24:11  dmw
76275970Scy * v0.19 2007-01-31 dmw:
77275970Scy * - Added tracking of how many seconds have been adjusted,
78275970Scy *   how many cycles added (actually in milliseconds), how
79275970Scy *   many cycles removed, print periodically if verbose is
80275970Scy *   active.
81275970Scy * - Corrected lack of lengthen or shorten of minute & hour
82275970Scy *   pulses for WWV format.
83275970Scy *
84275970Scy * Revision 1.23  2007/01/13 07:09:12  dmw
85275970Scy * v0.18 2007-01-13 dmw:
86275970Scy * - added -k option, which allows force of long or short
87275970Scy *   cycles, to test against IRIG-B decoder.
88275970Scy *
89275970Scy * Revision 1.22  2007/01/08 16:27:23  dmw
90275970Scy * v0.17 2007-01-08 dmw:
91275970Scy * - Changed -j option to **enable** rate correction, not disable.
92275970Scy *
93275970Scy * Revision 1.21  2007/01/08 06:22:36  dmw
94275970Scy * v0.17 2007-01-08 dmw:
95275970Scy * - Run stability check versus ongoing system clock (assume NTP correction)
96275970Scy *   and adjust time code rate to try to correct, if gets too far out of sync.
97275970Scy *   Disable this algorithm with -j option.
98275970Scy *
99275970Scy * Revision 1.20  2006/12/19 04:59:04  dmw
100275970Scy * v0.16 2006-12-18 dmw
101275970Scy * - Corrected print of setting of output frequency, always
102275970Scy *   showed 8000 samples/sec, now as specified on command line.
103275970Scy * - Modified to reflect new employer Norscan.
104275970Scy *
105275970Scy * Revision 1.19  2006/12/19 03:45:38  dmw
106275970Scy * v0.15 2006-12-18 dmw:
107275970Scy * - Added count of number of seconds to output then exit,
108275970Scy *   default zero for forever.
109275970Scy *
110275970Scy * Revision 1.18  2006/12/18 05:43:36  dmw
111275970Scy * v0.14 2006-12-17 dmw:
112275970Scy * - Corrected WWV(H) signal to leave "tick" sound off of 29th and 59th second of minute.
113275970Scy * - Adjusted verbose output format for WWV(H).
114275970Scy *
115275970Scy * Revision 1.17  2006/12/18 02:31:33  dmw
116275970Scy * v0.13 2006-12-17 dmw:
117275970Scy * - Put SPARC code back in, hopefully will work, but I don't have
118275970Scy *   a SPARC to try it on...
119275970Scy * - Reworked Verbose mode, different flag to initiate (x not v)
120275970Scy *   and actually implement turn off of verbosity when this flag used.
121275970Scy * - Re-claimed v flag for output level.
122275970Scy * - Note that you must define OSS_MODS to get OSS to compile,
123275970Scy *   otherwise will expect to compile using old SPARC options, as
124275970Scy *   it used to be.
125275970Scy *
126275970Scy * Revision 1.16  2006/10/26 19:08:43  dmw
127275970Scy * v0.12 2006-10-26 dmw:
128275970Scy * - Reversed output binary dump for IRIG, makes it easier to read the numbers.
129275970Scy *
130275970Scy * Revision 1.15  2006/10/24 15:57:09  dmw
131275970Scy * v0.11 2006-10-24 dmw:
132275970Scy * - another tweak.
133275970Scy *
134275970Scy * Revision 1.14  2006/10/24 15:55:53  dmw
135275970Scy * v0.11 2006-10-24 dmw:
136275970Scy * - Curses a fix to the fix to the fix of the usaeg.
137275970Scy *
138275970Scy * Revision 1.13  2006/10/24 15:53:25  dmw
139275970Scy * v0.11 (still) 2006-10-24 dmw:
140275970Scy * - Messed with usage message that's all.
141275970Scy *
142275970Scy * Revision 1.12  2006/10/24 15:50:05  dmw
143275970Scy * v0.11 2006-10-24 dmw:
144275970Scy * - oops, needed to note "hours" in usage of that offset.
145275970Scy *
146275970Scy * Revision 1.11  2006/10/24 15:49:09  dmw
147275970Scy * v0.11 2006-10-24 dmw:
148275970Scy * - Added ability to offset actual time sent, from the UTC time
149275970Scy *   as per the computer.
150275970Scy *
151275970Scy * Revision 1.10  2006/10/24 03:25:55  dmw
152275970Scy * v0.10 2006-10-23 dmw:
153275970Scy * - Corrected polarity of correction of offset when going into or out of DST.
154275970Scy * - Ensure that zero offset is always positive (pet peeve).
155275970Scy *
156275970Scy * Revision 1.9  2006/10/24 00:00:35  dmw
157275970Scy * v0.9 2006-10-23 dmw:
158275970Scy * - Shift time offset when DST in or out.
159275970Scy *
160275970Scy * Revision 1.8  2006/10/23 23:49:28  dmw
161275970Scy * v0.8 2006-10-23 dmw:
162275970Scy * - made offset of zero default positive.
163275970Scy *
164275970Scy * Revision 1.7  2006/10/23 23:44:13  dmw
165275970Scy * v0.7 2006-10-23 dmw:
166275970Scy * - Added unmodulated and inverted unmodulated output.
167275970Scy *
168275970Scy * Revision 1.6  2006/10/23 18:10:37  dmw
169275970Scy * v0.6 2006-10-23 dmw:
170275970Scy * - Cleaned up usage message.
171275970Scy * - Require at least one option, or prints usage message and exits.
172275970Scy *
173275970Scy * Revision 1.5  2006/10/23 16:58:10  dmw
174275970Scy * v0.5 2006-10-23 dmw:
175275970Scy * - Finally added a usage message.
176275970Scy * - Added leap second pending and DST change pending into IEEE 1344.
177275970Scy * - Default code type is now IRIG-B with IEEE 1344.
178275970Scy *
179275970Scy * Revision 1.4  2006/10/23 03:27:25  dmw
180275970Scy * v0.4 2006-10-22 dmw:
181275970Scy * - Added leap second addition and deletion.
182275970Scy * - Added DST changing forward and backward.
183275970Scy * - Changed date specification to more conventional year, month, and day of month
184275970Scy *   (rather than day of year).
185275970Scy *
186275970Scy * Revision 1.3  2006/10/22 21:04:12  dmw
187275970Scy * v0.2 2006-10-22 dmw:
188275970Scy * - Corrected format of legend line.
189275970Scy *
190275970Scy * Revision 1.2  2006/10/22 21:01:07  dmw
191275970Scy * v0.1 2006-10-22 dmw:
192275970Scy * - Added some more verbose output (as is my style)
193275970Scy * - Corrected frame format - there were markers in the
194275970Scy *   middle of frames, now correctly as "zero" bits.
195275970Scy * - Added header line to show fields of output.
196275970Scy * - Added straight binary seconds, were not implemented
197275970Scy *   before.
198275970Scy * - Added IEEE 1344 with parity.
199275970Scy *
200275970Scy *
201275970Scy */
202275970Scy#include <stdio.h>
203275970Scy#include <stdlib.h>
204275970Scy#include <time.h>
205275970Scy
206275970Scy#ifdef  HAVE_CONFIG_H
207275970Scy#include "config.h"
208275970Scy#undef VERSION		/* avoid conflict below */
209275970Scy#endif
210275970Scy
211275970Scy#ifdef  HAVE_SYS_SOUNDCARD_H
212275970Scy#include <sys/soundcard.h>
213275970Scy#else
214275970Scy# ifdef HAVE_SYS_AUDIOIO_H
215275970Scy# include <sys/audioio.h>
216275970Scy# else
217275970Scy# include <sys/audio.h>
218275970Scy# endif
219275970Scy#endif
220275970Scy
221275970Scy#include "ntp_stdlib.h"	/* for strlcat(), strlcpy() */
222275970Scy
223275970Scy#include <math.h>
224275970Scy#include <errno.h>
225275970Scy#include <sys/types.h>
226275970Scy#include <sys/stat.h>
227275970Scy#include <fcntl.h>
228275970Scy#include <string.h>
229275970Scy#include <unistd.h>
230275970Scy#include <ctype.h>
231275970Scy#include <sys/ioctl.h>
232275970Scy#include <sys/time.h>
233275970Scy
234275970Scy#define VERSION		(0)
235275970Scy#define	ISSUE		(23)
236275970Scy#define	ISSUE_DATE	"2007-02-12"
237275970Scy
238275970Scy#define	SECOND	(8000)			/* one second of 125-us samples */
239275970Scy#define BUFLNG	(400)			/* buffer size */
240275970Scy#define	DEVICE	"/dev/audio"	/* default audio device */
241275970Scy#define	WWV		(0)				/* WWV encoder */
242275970Scy#define	IRIG	(1)				/* IRIG-B encoder */
243275970Scy#define	OFF		(0)				/* zero amplitude */
244275970Scy#define	LOW		(1)				/* low amplitude */
245275970Scy#define	HIGH	(2)				/* high amplitude */
246275970Scy#define	DATA0	(200)			/* WWV/H 0 pulse */
247275970Scy#define	DATA1	(500)			/* WWV/H 1 pulse */
248275970Scy#define PI		(800)			/* WWV/H PI pulse */
249275970Scy#define	M2		(2)				/* IRIG 0 pulse */
250275970Scy#define	M5		(5)				/* IRIG 1 pulse */
251275970Scy#define	M8		(8)				/* IRIG PI pulse */
252275970Scy
253275970Scy#define	NUL		(0)
254275970Scy
255275970Scy#define	SECONDS_PER_MINUTE	(60)
256275970Scy#define SECONDS_PER_HOUR	(3600)
257275970Scy
258275970Scy#define	OUTPUT_DATA_STRING_LENGTH	(200)
259275970Scy
260275970Scy/* Attempt at unmodulated - "high" */
261275970Scyint u6000[] = {
262275970Scy	247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/*  0- 9 */
263275970Scy    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 10-19 */
264275970Scy    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 20-29 */
265275970Scy    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 30-39 */
266275970Scy    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 40-49 */
267275970Scy    247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 	/* 50-59 */
268275970Scy    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 60-69 */
269275970Scy    247, 247, 247, 247, 247, 247, 247, 247, 247, 247}; 	/* 70-79 */
270275970Scy
271275970Scy/* Attempt at unmodulated - "low" */
272275970Scyint u3000[] = {
273275970Scy	119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/*  0- 9 */
274275970Scy    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 10-19 */
275275970Scy    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 20-29 */
276275970Scy    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 30-39 */
277275970Scy    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 40-49 */
278275970Scy    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 	/* 50-59 */
279275970Scy    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 60-69 */
280275970Scy    119, 119, 119, 119, 119, 119, 119, 119, 119, 119}; 	/* 70-79 */
281275970Scy
282275970Scy/*
283275970Scy * Companded sine table amplitude 3000 units
284275970Scy */
285275970Scyint c3000[] = {1, 48, 63, 70, 78, 82, 85, 89, 92, 94,	/* 0-9 */
286275970Scy     96,  98,  99, 100, 101, 101, 102, 103, 103, 103,	/* 10-19 */
287275970Scy    103, 103, 103, 103, 102, 101, 101, 100,  99,  98,	/* 20-29 */
288275970Scy     96,  94,  92,  89,  85,  82,  78,  70,  63,  48,	/* 30-39 */
289275970Scy    129, 176, 191, 198, 206, 210, 213, 217, 220, 222,	/* 40-49 */
290275970Scy    224, 226, 227, 228, 229, 229, 230, 231, 231, 231, 	/* 50-59 */
291275970Scy    231, 231, 231, 231, 230, 229, 229, 228, 227, 226,	/* 60-69 */
292275970Scy    224, 222, 220, 217, 213, 210, 206, 198, 191, 176}; 	/* 70-79 */
293275970Scy/*
294275970Scy * Companded sine table amplitude 6000 units
295275970Scy */
296275970Scyint c6000[] = {1, 63, 78, 86, 93, 98, 101, 104, 107, 110, /* 0-9 */
297275970Scy    112, 113, 115, 116, 117, 117, 118, 118, 119, 119,	/* 10-19 */
298275970Scy    119, 119, 119, 118, 118, 117, 117, 116, 115, 113,	/* 20-29 */
299275970Scy    112, 110, 107, 104, 101,  98,  93,  86,  78,  63,	/* 30-39 */
300275970Scy    129, 191, 206, 214, 221, 226, 229, 232, 235, 238,	/* 40-49 */
301275970Scy    240, 241, 243, 244, 245, 245, 246, 246, 247, 247, 	/* 50-59 */
302275970Scy    247, 247, 247, 246, 246, 245, 245, 244, 243, 241,	/* 60-69 */
303275970Scy    240, 238, 235, 232, 229, 226, 221, 214, 206, 191}; 	/* 70-79 */
304275970Scy
305275970Scy/*
306275970Scy * Decoder operations at the end of each second are driven by a state
307275970Scy * machine. The transition matrix consists of a dispatch table indexed
308275970Scy * by second number. Each entry in the table contains a case switch
309275970Scy * number and argument.
310275970Scy */
311275970Scystruct progx {
312275970Scy	int sw;			/* case switch number */
313275970Scy	int arg;		/* argument */
314275970Scy};
315275970Scy
316275970Scy/*
317275970Scy * Case switch numbers
318275970Scy */
319275970Scy#define DATA	(0)		/* send data (0, 1, PI) */
320275970Scy#define COEF	(1)		/* send BCD bit */
321275970Scy#define	DEC		(2)		/* decrement to next digit and send PI */
322275970Scy#define	MIN		(3)		/* minute pulse */
323275970Scy#define	LEAP	(4)		/* leap warning */
324275970Scy#define	DUT1	(5)		/* DUT1 bits */
325275970Scy#define	DST1	(6)		/* DST1 bit */
326275970Scy#define	DST2	(7)		/* DST2 bit */
327275970Scy#define DECZ	(8)		/* decrement to next digit and send zero */
328275970Scy#define DECC	(9)		/* decrement to next digit and send bit */
329275970Scy#define NODEC	(10)	/* no decerement to next digit, send PI */
330275970Scy#define DECX	(11)	/* decrement to next digit, send PI, but no tick */
331275970Scy#define DATAX	(12)	/* send data (0, 1, PI), but no tick */
332275970Scy
333275970Scy/*
334275970Scy * WWV/H format (100-Hz, 9 digits, 1 m frame)
335275970Scy */
336275970Scystruct progx progx[] = {
337275970Scy	{MIN,	800},		/* 0 minute sync pulse */
338275970Scy	{DATA,	DATA0},		/* 1 */
339275970Scy	{DST2,	0},		/* 2 DST2 */
340275970Scy	{LEAP,	0},		/* 3 leap warning */
341275970Scy	{COEF,	1},		/* 4 1 year units */
342275970Scy	{COEF,	2},		/* 5 2 */
343275970Scy	{COEF,	4},		/* 6 4 */
344275970Scy	{COEF,	8},		/* 7 8 */
345275970Scy	{DEC,	DATA0},		/* 8 */
346275970Scy	{DATA,	PI},		/* 9 p1 */
347275970Scy	{COEF,	1},		/* 10 1 minute units */
348275970Scy	{COEF,	2},		/* 11 2 */
349275970Scy	{COEF,	4},		/* 12 4 */
350275970Scy	{COEF,	8},		/* 13 8 */
351275970Scy	{DEC,	DATA0},		/* 14 */
352275970Scy	{COEF,	1},		/* 15 10 minute tens */
353275970Scy	{COEF,	2},		/* 16 20 */
354275970Scy	{COEF,	4},		/* 17 40 */
355275970Scy	{COEF,	8},		/* 18 80 (not used) */
356275970Scy	{DEC,	PI},		/* 19 p2 */
357275970Scy	{COEF,	1},		/* 20 1 hour units */
358275970Scy	{COEF,	2},		/* 21 2 */
359275970Scy	{COEF,	4},		/* 22 4 */
360275970Scy	{COEF,	8},		/* 23 8 */
361275970Scy	{DEC,	DATA0},		/* 24 */
362275970Scy	{COEF,	1},		/* 25 10 hour tens */
363275970Scy	{COEF,	2},		/* 26 20 */
364275970Scy	{COEF,	4},		/* 27 40 (not used) */
365275970Scy	{COEF,	8},		/* 28 80 (not used) */
366275970Scy	{DECX,	PI},		/* 29 p3 */
367275970Scy	{COEF,	1},		/* 30 1 day units */
368275970Scy	{COEF,	2},		/* 31 2 */
369275970Scy	{COEF,	4},		/* 32 4 */
370275970Scy	{COEF,	8},		/* 33 8 */
371275970Scy	{DEC,	DATA0},		/* 34 not used */
372275970Scy	{COEF,	1},		/* 35 10 day tens */
373275970Scy	{COEF,	2},		/* 36 20 */
374275970Scy	{COEF,	4},		/* 37 40 */
375275970Scy	{COEF,	8},		/* 38 80 */
376275970Scy	{DEC,	PI},		/* 39 p4 */
377275970Scy	{COEF,	1},		/* 40 100 day hundreds */
378275970Scy	{COEF,	2},		/* 41 200 */
379275970Scy	{COEF,	4},		/* 42 400 (not used) */
380275970Scy	{COEF,	8},		/* 43 800 (not used) */
381275970Scy	{DEC,	DATA0},		/* 44 */
382275970Scy	{DATA,	DATA0},		/* 45 */
383275970Scy	{DATA,	DATA0},		/* 46 */
384275970Scy	{DATA,	DATA0},		/* 47 */
385275970Scy	{DATA,	DATA0},		/* 48 */
386275970Scy	{DATA,	PI},		/* 49 p5 */
387275970Scy	{DUT1,	8},		/* 50 DUT1 sign */
388275970Scy	{COEF,	1},		/* 51 10 year tens */
389275970Scy	{COEF,	2},		/* 52 20 */
390275970Scy	{COEF,	4},		/* 53 40 */
391275970Scy	{COEF,	8},		/* 54 80 */
392275970Scy	{DST1,	0},		/* 55 DST1 */
393275970Scy	{DUT1,	1},		/* 56 0.1 DUT1 fraction */
394275970Scy	{DUT1,	2},		/* 57 0.2 */
395275970Scy	{DUT1,	4},		/* 58 0.4 */
396275970Scy	{DATAX,	PI},		/* 59 p6 */
397275970Scy	{DATA,	DATA0},		/* 60 leap */
398275970Scy};
399275970Scy
400275970Scy/*
401275970Scy * IRIG format frames (1000 Hz, 1 second for 10 frames of data)
402275970Scy */
403275970Scy
404275970Scy/*
405275970Scy * IRIG format frame 10 - MS straight binary seconds
406275970Scy */
407275970Scystruct progx progu[] = {
408275970Scy	{COEF,	2},		/* 0 0x0 0200 seconds */
409275970Scy	{COEF,	4},		/* 1 0x0 0400 */
410275970Scy	{COEF,	8},		/* 2 0x0 0800 */
411275970Scy	{DECC,	1},		/* 3 0x0 1000 */
412275970Scy	{COEF,	2},		/* 4 0x0 2000 */
413275970Scy	{COEF,	4},		/* 6 0x0 4000 */
414275970Scy	{COEF,	8},		/* 7 0x0 8000 */
415275970Scy	{DECC,	1},		/* 8 0x1 0000 */
416275970Scy	{COEF,  2},     /* 9 0x2 0000 - but only 86,401 / 0x1 5181 seconds in a day, so always zero */
417275970Scy	{NODEC,	M8},	/* 9 PI */
418275970Scy};
419275970Scy
420275970Scy/*
421275970Scy * IRIG format frame 8 - MS control functions
422275970Scy */
423275970Scystruct progx progv[] = {
424275970Scy	{COEF,	2},		/*  0 CF # 19 */
425275970Scy	{COEF,	4},		/*  1 CF # 20 */
426275970Scy	{COEF,	8},		/*  2 CF # 21 */
427275970Scy	{DECC,	1},		/*  3 CF # 22 */
428275970Scy	{COEF,	2},		/*  4 CF # 23 */
429275970Scy	{COEF,	4},		/*  6 CF # 24 */
430275970Scy	{COEF,	8},		/*  7 CF # 25 */
431275970Scy	{DECC,	1},		/*  8 CF # 26 */
432275970Scy	{COEF,  2},		/*  9 CF # 27 */
433275970Scy	{DEC,	M8},	/* 10 PI */
434275970Scy};
435275970Scy
436275970Scy/*
437275970Scy * IRIG format frames 7 & 9 - LS control functions & LS straight binary seconds
438275970Scy */
439275970Scystruct progx progw[] = {
440275970Scy	{COEF,	1},		/*  0  CF # 10, 0x0 0001 seconds */
441275970Scy	{COEF,	2},		/*  1  CF # 11, 0x0 0002 */
442275970Scy	{COEF,	4},		/*  2  CF # 12, 0x0 0004 */
443275970Scy	{COEF,	8},		/*  3  CF # 13, 0x0 0008 */
444275970Scy	{DECC,	1},		/*  4  CF # 14, 0x0 0010 */
445275970Scy	{COEF,	2},		/*  6  CF # 15, 0x0 0020 */
446275970Scy	{COEF,	4},		/*  7  CF # 16, 0x0 0040 */
447275970Scy	{COEF,	8},		/*  8  CF # 17, 0x0 0080 */
448275970Scy	{DECC,  1},		/*  9  CF # 18, 0x0 0100 */
449275970Scy	{NODEC,	M8},	/* 10  PI */
450275970Scy};
451275970Scy
452275970Scy/*
453275970Scy * IRIG format frames 2 to 6 - minutes, hours, days, hundreds days, 2 digit years (also called control functions bits 1-9)
454275970Scy */
455275970Scystruct progx progy[] = {
456275970Scy	{COEF,	1},		/* 0 1 units, CF # 1 */
457275970Scy	{COEF,	2},		/* 1 2 units, CF # 2 */
458275970Scy	{COEF,	4},		/* 2 4 units, CF # 3 */
459275970Scy	{COEF,	8},		/* 3 8 units, CF # 4 */
460275970Scy	{DECZ,	M2},	/* 4 zero bit, CF # 5 / unused, default zero in years */
461275970Scy	{COEF,	1},		/* 5 10 tens, CF # 6 */
462275970Scy	{COEF,	2},		/* 6 20 tens, CF # 7*/
463275970Scy	{COEF,	4},		/* 7 40 tens, CF # 8*/
464275970Scy	{COEF,	8},		/* 8 80 tens, CF # 9*/
465275970Scy	{DEC,	M8},	/* 9 PI */
466275970Scy};
467275970Scy
468275970Scy/*
469275970Scy * IRIG format first frame, frame 1 - seconds
470275970Scy */
471275970Scystruct progx progz[] = {
472275970Scy	{MIN,	M8},	/* 0 PI (on-time marker for the second at zero cross of 1st cycle) */
473275970Scy	{COEF,	1},		/* 1 1 units */
474275970Scy	{COEF,	2},		/* 2 2 */
475275970Scy	{COEF,	4},		/* 3 4 */
476275970Scy	{COEF,	8},		/* 4 8 */
477275970Scy	{DECZ,	M2},	/* 5 zero bit */
478275970Scy	{COEF,	1},		/* 6 10 tens */
479275970Scy	{COEF,	2},		/* 7 20 */
480275970Scy	{COEF,	4},		/* 8 40 */
481275970Scy	{DEC,	M8},	/* 9 PI */
482275970Scy};
483275970Scy
484275970Scy/* LeapState values. */
485275970Scy#define	LEAPSTATE_NORMAL			(0)
486275970Scy#define	LEAPSTATE_DELETING			(1)
487275970Scy#define	LEAPSTATE_INSERTING			(2)
488275970Scy#define	LEAPSTATE_ZERO_AFTER_INSERT	(3)
489275970Scy
490275970Scy
491275970Scy/*
492275970Scy * Forward declarations
493275970Scy */
494275970Scyvoid	WWV_Second(int, int);		/* send second */
495275970Scyvoid	WWV_SecondNoTick(int, int);	/* send second with no tick */
496275970Scyvoid	digit(int);		/* encode digit */
497275970Scyvoid	peep(int, int, int);	/* send cycles */
498275970Scyvoid	poop(int, int, int, int); /* Generate unmodulated from similar tables */
499275970Scyvoid	delay(int);		/* delay samples */
500275970Scyint		ConvertMonthDayToDayOfYear (int, int, int);	/* Calc day of year from year month & day */
501275970Scyvoid	Help (void);	/* Usage message */
502275970Scyvoid	ReverseString(char *);
503275970Scy
504275970Scy/*
505275970Scy * Extern declarations, don't know why not in headers
506275970Scy */
507275970Scy//float	round ( float );
508275970Scy
509275970Scy/*
510275970Scy * Global variables
511275970Scy */
512275970Scychar	buffer[BUFLNG];		/* output buffer */
513275970Scyint	bufcnt = 0;		/* buffer counter */
514275970Scyint	fd;			/* audio codec file descriptor */
515275970Scyint	tone = 1000;		/* WWV sync frequency */
516275970Scyint HourTone = 1500;	/* WWV hour on-time frequency */
517275970Scyint	encode = IRIG;		/* encoder select */
518275970Scyint	leap = 0;		/* leap indicator */
519275970Scyint	DstFlag = 0;		/* winter/summer time */
520275970Scyint	dut1 = 0;		/* DUT1 correction (sign, magnitude) */
521275970Scyint	utc = 0;		/* option epoch */
522275970Scyint IrigIncludeYear = FALSE;	/* Whether to send year in first control functions area, between P5 and P6. */
523275970Scyint IrigIncludeIeee = FALSE;	/* Whether to send IEEE 1344 control functions extensions between P6 and P8. */
524275970Scyint	StraightBinarySeconds = 0;
525275970Scyint	ControlFunctions = 0;
526275970Scyint	Debug = FALSE;
527275970Scyint Verbose = TRUE;
528275970Scychar	*CommandName;
529275970Scy
530275970Scy#ifndef  HAVE_SYS_SOUNDCARD_H
531275970Scyint	level = AUDIO_MAX_GAIN / 8; /* output level */
532275970Scyint	port = AUDIO_LINE_OUT;	/* output port */
533275970Scy#endif
534275970Scy
535275970Scyint		TotalSecondsCorrected = 0;
536275970Scyint		TotalCyclesAdded = 0;
537275970Scyint		TotalCyclesRemoved = 0;
538275970Scy
539275970Scy
540275970Scy/*
541275970Scy * Main program
542275970Scy */
543275970Scyint
544275970Scymain(
545275970Scy	int		argc,		/* command line options */
546275970Scy	char	**argv		/* poiniter to list of tokens */
547275970Scy	)
548275970Scy{
549275970Scy#ifndef  HAVE_SYS_SOUNDCARD_H
550275970Scy	audio_info_t info;	/* Sun audio structure */
551275970Scy	int	rval;           /* For IOCTL calls */
552275970Scy#endif
553275970Scy
554275970Scy	struct	timeval	 TimeValue;				/* System clock at startup */
555275970Scy	time_t			 SecondsPartOfTime;		/* Sent to gmtime() for calculation of TimeStructure (can apply offset). */
556275970Scy	time_t			 BaseRealTime;			/* Base realtime so can determine seconds since starting. */
557275970Scy	time_t			 NowRealTime;			/* New realtime to can determine seconds as of now. */
558275970Scy	unsigned		 SecondsRunningRealTime;	/* Difference between NowRealTime and BaseRealTime. */
559275970Scy	unsigned		 SecondsRunningSimulationTime;	/* Time that the simulator has been running. */
560275970Scy	int				 SecondsRunningDifference;	/* Difference between what real time says we have been running */
561275970Scy												/* and what simulator says we have been running - will slowly  */
562275970Scy												/* change because of clock drift. */
563275970Scy	int				 ExpectedRunningDifference = 0;	/* Stable value that we've obtained from check at initial start-up.	*/
564275970Scy	unsigned		 StabilityCount;		/* Used to check stability of difference while starting */
565275970Scy#define	RUN_BEFORE_STABILITY_CHECK	(30)	// Must run this many seconds before even checking stability.
566275970Scy#define	MINIMUM_STABILITY_COUNT		(10)	// Number of consecutive differences that need to be within initial stability band to say we are stable.
567275970Scy#define	INITIAL_STABILITY_BAND		( 2)	// Determining initial stability for consecutive differences within +/- this value.
568275970Scy#define	RUNNING_STABILITY_BAND		( 5)	// When running, stability is defined as difference within +/- this value.
569275970Scy
570275970Scy	struct	tm		*TimeStructure = NULL;	/* Structure returned by gmtime */
571275970Scy	char	device[200];	/* audio device */
572275970Scy	char	code[200];	/* timecode */
573275970Scy	int	temp;
574275970Scy	int	arg = 0;
575275970Scy	int	sw = 0;
576275970Scy	int	ptr = 0;
577275970Scy
578275970Scy	int	Year;
579275970Scy	int	Month;
580275970Scy	int	DayOfMonth;
581275970Scy	int	Hour;
582275970Scy	int	Minute;
583275970Scy	int	Second = 0;
584275970Scy	int	DayOfYear;
585275970Scy
586275970Scy	int	BitNumber;
587275970Scy#ifdef HAVE_SYS_SOUNDCARD_H
588275970Scy	int	AudioFormat;
589275970Scy	int	MonoStereo;     /* 0=mono, 1=stereo */
590275970Scy#define	MONO	(0)
591275970Scy#define	STEREO	(1)
592275970Scy	int	SampleRate;
593275970Scy	int	SampleRateDifference;
594275970Scy#endif
595275970Scy	int	SetSampleRate;
596275970Scy	char FormatCharacter = '3';		/* Default is IRIG-B with IEEE 1344 extensions */
597275970Scy	char AsciiValue;
598275970Scy	int	HexValue;
599275970Scy	int	OldPtr = 0;
600275970Scy	int FrameNumber = 0;
601275970Scy
602275970Scy	/* Time offset for IEEE 1344 indication. */
603275970Scy	float TimeOffset = 0.0;
604275970Scy	int	OffsetSignBit = 0;
605275970Scy	int OffsetOnes = 0;
606275970Scy	int OffsetHalf = 0;
607275970Scy
608275970Scy	int	TimeQuality = 0;	/* Time quality for IEEE 1344 indication. */
609275970Scy	char ParityString[200];	/* Partial output string, to calculate parity on. */
610275970Scy	int	ParitySum = 0;
611275970Scy	int	ParityValue;
612275970Scy	char *StringPointer;
613275970Scy
614275970Scy	/* Flags to indicate requested leap second addition or deletion by command line option. */
615275970Scy	/* Should be mutually exclusive - generally ensured by code which interprets command line option. */
616275970Scy	int	InsertLeapSecond = FALSE;
617275970Scy	int	DeleteLeapSecond = FALSE;
618275970Scy
619275970Scy	/* Date and time of requested leap second addition or deletion. */
620275970Scy	int	LeapYear					= 0;
621275970Scy	int LeapMonth					= 0;
622275970Scy	int	LeapDayOfMonth				= 0;
623275970Scy	int LeapHour					= 0;
624275970Scy	int	LeapMinute					= 0;
625275970Scy	int	LeapDayOfYear				= 0;
626275970Scy
627275970Scy	/* State flag for the insertion and deletion of leap seconds, esp. deletion, */
628275970Scy	/* where the logic gets a bit tricky. */
629275970Scy	int	LeapState = LEAPSTATE_NORMAL;
630275970Scy
631275970Scy	/* Flags for indication of leap second pending and leap secod polarity in IEEE 1344 */
632275970Scy	int	LeapSecondPending = FALSE;
633275970Scy	int	LeapSecondPolarity = FALSE;
634275970Scy
635275970Scy	/* Date and time of requested switch into or out of DST by command line option. */
636275970Scy	int	DstSwitchYear				= 0;
637275970Scy	int DstSwitchMonth				= 0;
638275970Scy	int	DstSwitchDayOfMonth			= 0;
639275970Scy	int DstSwitchHour				= 0;
640275970Scy	int	DstSwitchMinute				= 0;
641275970Scy	int	DstSwitchDayOfYear			= 0;
642275970Scy
643275970Scy	/* Indicate when we have been asked to switch into or out of DST by command line option. */
644275970Scy	int	DstSwitchFlag = FALSE;
645275970Scy
646275970Scy	/* To allow predict for DstPendingFlag in IEEE 1344 */
647275970Scy	int	DstSwitchPendingYear		= 0;	/* Default value isn't valid, but I don't care. */
648275970Scy	int	DstSwitchPendingDayOfYear	= 0;
649275970Scy	int	DstSwitchPendingHour		= 0;
650275970Scy	int	DstSwitchPendingMinute		= 0;
651275970Scy
652275970Scy	/* /Flag for indication of a DST switch pending in IEEE 1344 */
653275970Scy	int	DstPendingFlag = FALSE;
654275970Scy
655275970Scy	/* Attempt at unmodulated */
656275970Scy	int	Unmodulated = FALSE;
657275970Scy	int UnmodulatedInverted = FALSE;
658275970Scy
659275970Scy	/* Offset to actual time value sent. */
660275970Scy	float	UseOffsetHoursFloat;
661275970Scy	int		UseOffsetSecondsInt = 0;
662275970Scy	float	UseOffsetSecondsFloat;
663275970Scy
664275970Scy	/* String to allow us to put out reversed data - so can read the binary numbers. */
665275970Scy	char	OutputDataString[OUTPUT_DATA_STRING_LENGTH];
666275970Scy
667275970Scy	/* Number of seconds to send before exiting.  Default = 0 = forever. */
668275970Scy	int		SecondsToSend = 0;
669275970Scy	int		CountOfSecondsSent = 0;	/* Counter of seconds */
670275970Scy
671275970Scy	/* Flags to indicate whether to add or remove a cycle for time adjustment. */
672275970Scy	int		AddCycle = FALSE;	 	// We are ahead, add cycle to slow down and get back in sync.
673275970Scy	int		RemoveCycle = FALSE;	// We are behind, remove cycle to slow down and get back in sync.
674275970Scy	int		RateCorrection;			// Aggregate flag for passing to subroutines.
675275970Scy	int		EnableRateCorrection = TRUE;
676275970Scy
677275970Scy	float	RatioError;
678275970Scy
679275970Scy
680275970Scy	CommandName = argv[0];
681275970Scy
682275970Scy	if	(argc < 1)
683275970Scy		{
684275970Scy		Help ();
685275970Scy		exit (-1);
686275970Scy		}
687275970Scy
688275970Scy	/*
689275970Scy	 * Parse options
690275970Scy	 */
691275970Scy	strlcpy(device, DEVICE, sizeof(device));
692275970Scy	Year = 0;
693275970Scy	SetSampleRate = SECOND;
694275970Scy
695275970Scy#if	HAVE_SYS_SOUNDCARD_H
696275970Scy	while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:xy:z?")) != -1) {
697275970Scy#else
698275970Scy	while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:v:xy:z?")) != -1) {
699275970Scy#endif
700275970Scy		switch (temp) {
701275970Scy
702275970Scy		case 'a':	/* specify audio device (/dev/audio) */
703275970Scy			strlcpy(device, optarg, sizeof(device));
704275970Scy			break;
705275970Scy
706275970Scy		case 'b':	/* Remove (delete) a leap second at the end of the specified minute. */
707275970Scy			sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth,
708275970Scy			    &LeapHour, &LeapMinute);
709275970Scy			InsertLeapSecond = FALSE;
710275970Scy			DeleteLeapSecond = TRUE;
711275970Scy			break;
712275970Scy
713275970Scy		case 'c':	/* specify number of seconds to send output for before exiting, 0 = forever */
714275970Scy			sscanf(optarg, "%d", &SecondsToSend);
715275970Scy			break;
716275970Scy
717275970Scy		case 'd':	/* set DST for summer (WWV/H only) / start with DST active (IRIG) */
718275970Scy			DstFlag++;
719275970Scy			break;
720275970Scy
721275970Scy		case 'f':	/* select format: i=IRIG-98 (default) 2=IRIG-2004 3-IRIG+IEEE-1344 w=WWV(H) */
722275970Scy			sscanf(optarg, "%c", &FormatCharacter);
723275970Scy			break;
724275970Scy
725275970Scy		case 'g':	/* Date and time to switch back into / out of DST active. */
726275970Scy			sscanf(optarg, "%2d%2d%2d%2d%2d", &DstSwitchYear, &DstSwitchMonth, &DstSwitchDayOfMonth,
727275970Scy			    &DstSwitchHour, &DstSwitchMinute);
728275970Scy			DstSwitchFlag = TRUE;
729275970Scy			break;
730275970Scy
731275970Scy		case 'h':
732275970Scy		case 'H':
733275970Scy		case '?':
734275970Scy			Help ();
735275970Scy			exit(-1);
736275970Scy			break;
737275970Scy
738275970Scy		case 'i':	/* Insert (add) a leap second at the end of the specified minute. */
739275970Scy			sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth,
740275970Scy			    &LeapHour, &LeapMinute);
741275970Scy			InsertLeapSecond = TRUE;
742275970Scy			DeleteLeapSecond = FALSE;
743275970Scy			break;
744275970Scy
745275970Scy		case 'j':
746275970Scy			EnableRateCorrection = FALSE;
747275970Scy			break;
748275970Scy
749275970Scy		case 'k':
750275970Scy			sscanf (optarg, "%d", &RateCorrection);
751275970Scy			EnableRateCorrection = FALSE;
752275970Scy			if  (RateCorrection < 0)
753275970Scy				{
754275970Scy				RemoveCycle = TRUE;
755275970Scy				AddCycle = FALSE;
756275970Scy
757275970Scy				if  (Verbose)
758275970Scy					printf ("\n> Forcing rate correction removal of cycle...\n");
759275970Scy				}
760275970Scy			else
761275970Scy				{
762275970Scy				if  (RateCorrection > 0)
763275970Scy					{
764275970Scy					RemoveCycle = FALSE;
765275970Scy					AddCycle = TRUE;
766275970Scy
767275970Scy					if  (Verbose)
768275970Scy						printf ("\n> Forcing rate correction addition of cycle...\n");
769275970Scy					}
770275970Scy				}
771275970Scy			break;
772275970Scy
773275970Scy		case 'l':	/* use time offset from UTC */
774275970Scy			sscanf(optarg, "%f", &UseOffsetHoursFloat);
775275970Scy			UseOffsetSecondsFloat = UseOffsetHoursFloat * (float) SECONDS_PER_HOUR;
776275970Scy			UseOffsetSecondsInt = (int) (UseOffsetSecondsFloat + 0.5);
777275970Scy			break;
778275970Scy
779275970Scy		case 'o':	/* Set IEEE 1344 time offset in hours - positive or negative, to the half hour */
780275970Scy			sscanf(optarg, "%f", &TimeOffset);
781275970Scy			if  (TimeOffset >= -0.2)
782275970Scy				{
783275970Scy				OffsetSignBit = 0;
784275970Scy
785275970Scy				if  (TimeOffset > 0)
786275970Scy					{
787275970Scy					OffsetOnes    = TimeOffset;
788275970Scy
789275970Scy					if  ( (TimeOffset - floor(TimeOffset)) >= 0.4)
790275970Scy						OffsetHalf = 1;
791275970Scy					else
792275970Scy						OffsetHalf = 0;
793275970Scy					}
794275970Scy				else
795275970Scy					{
796275970Scy					OffsetOnes    = 0;
797275970Scy					OffsetHalf    = 0;
798275970Scy					}
799275970Scy				}
800275970Scy			else
801275970Scy				{
802275970Scy				OffsetSignBit = 1;
803275970Scy				OffsetOnes    = -TimeOffset;
804275970Scy
805275970Scy				if  ( (ceil(TimeOffset) - TimeOffset) >= 0.4)
806275970Scy					OffsetHalf = 1;
807275970Scy				else
808275970Scy					OffsetHalf = 0;
809275970Scy				}
810275970Scy
811275970Scy			/*printf ("\nGot TimeOffset = %3.1f, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d...\n",
812275970Scy					TimeOffset, OffsetSignBit, OffsetOnes, OffsetHalf);
813275970Scy			*/
814275970Scy			break;
815275970Scy
816275970Scy		case 'q':	/* Hex quality code 0 to 0x0F - 0 = maximum, 0x0F = no lock */
817275970Scy			sscanf(optarg, "%x", &TimeQuality);
818275970Scy			TimeQuality &= 0x0F;
819275970Scy			/*printf ("\nGot TimeQuality = 0x%1X...\n", TimeQuality);
820275970Scy			*/
821275970Scy			break;
822275970Scy
823275970Scy		case 'r':	/* sample rate (nominally 8000, integer close to 8000 I hope) */
824275970Scy			sscanf(optarg, "%d", &SetSampleRate);
825275970Scy			break;
826275970Scy
827275970Scy		case 's':	/* set leap warning bit (WWV/H only) */
828275970Scy			leap++;
829275970Scy			break;
830275970Scy
831275970Scy		case 't':	/* select WWVH sync frequency */
832275970Scy			tone = 1200;
833275970Scy			break;
834275970Scy
835275970Scy		case 'u':	/* set DUT1 offset (-7 to +7) */
836275970Scy			sscanf(optarg, "%d", &dut1);
837275970Scy			if (dut1 < 0)
838275970Scy				dut1 = abs(dut1);
839275970Scy			else
840275970Scy				dut1 |= 0x8;
841275970Scy			break;
842275970Scy
843275970Scy#ifndef  HAVE_SYS_SOUNDCARD_H
844275970Scy		case 'v':	/* set output level (0-255) */
845275970Scy			sscanf(optarg, "%d", &level);
846275970Scy			break;
847275970Scy#endif
848275970Scy
849275970Scy		case 'x':	/* Turn off verbose output. */
850275970Scy			Verbose = FALSE;
851275970Scy			break;
852275970Scy
853275970Scy		case 'y':	/* Set initial date and time */
854275970Scy			sscanf(optarg, "%2d%2d%2d%2d%2d%2d", &Year, &Month, &DayOfMonth,
855275970Scy			    &Hour, &Minute, &Second);
856275970Scy			utc++;
857275970Scy			break;
858275970Scy
859275970Scy		case 'z':	/* Turn on Debug output (also turns on Verbose below) */
860275970Scy			Debug = TRUE;
861275970Scy			break;
862275970Scy
863275970Scy		default:
864275970Scy			printf("Invalid option \"%c\", aborting...\n", temp);
865275970Scy			exit (-1);
866275970Scy			break;
867275970Scy		}
868275970Scy	}
869275970Scy
870275970Scy	if  (Debug)
871275970Scy	    Verbose = TRUE;
872275970Scy
873275970Scy	if  (InsertLeapSecond || DeleteLeapSecond)
874275970Scy		{
875275970Scy		LeapDayOfYear = ConvertMonthDayToDayOfYear (LeapYear, LeapMonth, LeapDayOfMonth);
876275970Scy
877275970Scy		if	(Debug)
878275970Scy			{
879275970Scy			printf ("\nHave request for leap second %s at year %4d day %3d at %2.2dh%2.2d....\n",\
880275970Scy					DeleteLeapSecond ? "DELETION" : (InsertLeapSecond ? "ADDITION" : "( error ! )" ),
881275970Scy					LeapYear, LeapDayOfYear, LeapHour, LeapMinute);
882275970Scy			}
883275970Scy		}
884275970Scy
885275970Scy	if	(DstSwitchFlag)
886275970Scy		{
887275970Scy		DstSwitchDayOfYear = ConvertMonthDayToDayOfYear (DstSwitchYear, DstSwitchMonth, DstSwitchDayOfMonth);
888275970Scy
889275970Scy		/* Figure out time of minute previous to DST switch, so can put up warning flag in IEEE 1344 */
890275970Scy		DstSwitchPendingYear		= DstSwitchYear;
891275970Scy		DstSwitchPendingDayOfYear	= DstSwitchDayOfYear;
892275970Scy		DstSwitchPendingHour		= DstSwitchHour;
893275970Scy		DstSwitchPendingMinute		= DstSwitchMinute - 1;
894275970Scy		if 	(DstSwitchPendingMinute < 0)
895275970Scy			{
896275970Scy			DstSwitchPendingMinute = 59;
897275970Scy			DstSwitchPendingHour--;
898275970Scy			if	(DstSwitchPendingHour < 0)
899275970Scy				{
900275970Scy				DstSwitchPendingHour = 23;
901275970Scy				DstSwitchPendingDayOfYear--;
902275970Scy				if	(DstSwitchPendingDayOfYear < 1)
903275970Scy					{
904275970Scy					DstSwitchPendingYear--;
905275970Scy					}
906275970Scy				}
907275970Scy			}
908275970Scy
909275970Scy		if	(Debug)
910275970Scy			{
911275970Scy			printf ("\nHave DST switch request for year %4d day %3d at %2.2dh%2.2d,",
912275970Scy					DstSwitchYear, DstSwitchDayOfYear, DstSwitchHour, DstSwitchMinute);
913275970Scy			printf ("\n    so will have warning at year %4d day %3d at %2.2dh%2.2d.\n",
914275970Scy					DstSwitchPendingYear, DstSwitchPendingDayOfYear, DstSwitchPendingHour, DstSwitchPendingMinute);
915275970Scy			}
916275970Scy		}
917275970Scy
918275970Scy	switch (tolower(FormatCharacter)) {
919275970Scy	case 'i':
920275970Scy		printf ("\nFormat is IRIG-1998 (no year coded)...\n\n");
921275970Scy		encode = IRIG;
922275970Scy		IrigIncludeYear = FALSE;
923275970Scy		IrigIncludeIeee = FALSE;
924275970Scy		break;
925275970Scy
926275970Scy	case '2':
927275970Scy		printf ("\nFormat is IRIG-2004 (BCD year coded)...\n\n");
928275970Scy		encode = IRIG;
929275970Scy		IrigIncludeYear = TRUE;
930275970Scy		IrigIncludeIeee = FALSE;
931275970Scy		break;
932275970Scy
933275970Scy	case '3':
934275970Scy		printf ("\nFormat is IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
935275970Scy		encode = IRIG;
936275970Scy		IrigIncludeYear = TRUE;
937275970Scy		IrigIncludeIeee = TRUE;
938275970Scy		break;
939275970Scy
940275970Scy	case '4':
941275970Scy		printf ("\nFormat is unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
942275970Scy		encode = IRIG;
943275970Scy		IrigIncludeYear = TRUE;
944275970Scy		IrigIncludeIeee = TRUE;
945275970Scy
946275970Scy		Unmodulated = TRUE;
947275970Scy		UnmodulatedInverted = FALSE;
948275970Scy		break;
949275970Scy
950275970Scy	case '5':
951275970Scy		printf ("\nFormat is inverted unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
952275970Scy		encode = IRIG;
953275970Scy		IrigIncludeYear = TRUE;
954275970Scy		IrigIncludeIeee = TRUE;
955275970Scy
956275970Scy		Unmodulated = TRUE;
957275970Scy		UnmodulatedInverted = TRUE;
958275970Scy		break;
959275970Scy
960275970Scy	case 'w':
961275970Scy		printf ("\nFormat is WWV(H)...\n\n");
962275970Scy		encode = WWV;
963275970Scy		break;
964275970Scy
965275970Scy	default:
966275970Scy		printf ("\n\nUnexpected format value of \'%c\', cannot parse, aborting...\n\n", FormatCharacter);
967275970Scy		exit (-1);
968275970Scy		break;
969275970Scy	}
970275970Scy
971275970Scy	/*
972275970Scy	 * Open audio device and set options
973275970Scy	 */
974275970Scy	fd = open(device, O_WRONLY);
975275970Scy	if (fd <= 0) {
976275970Scy		printf("Unable to open audio device \"%s\", aborting: %s\n", device, strerror(errno));
977275970Scy		exit(1);
978275970Scy	}
979275970Scy
980275970Scy#ifdef  HAVE_SYS_SOUNDCARD_H
981275970Scy	/* First set coding type */
982275970Scy	AudioFormat = AFMT_MU_LAW;
983275970Scy	if (ioctl(fd, SNDCTL_DSP_SETFMT, &AudioFormat)==-1)
984275970Scy	{ /* Fatal error */
985275970Scy	printf ("\nUnable to set output format, aborting...\n\n");
986275970Scy	exit(-1);
987275970Scy	}
988275970Scy
989275970Scy	if  (AudioFormat != AFMT_MU_LAW)
990275970Scy	{
991275970Scy	printf ("\nUnable to set output format for mu law, aborting...\n\n");
992275970Scy	exit(-1);
993275970Scy	}
994275970Scy
995275970Scy	/* Next set number of channels */
996275970Scy	MonoStereo = MONO;	/* Mono */
997275970Scy	if (ioctl(fd, SNDCTL_DSP_STEREO, &MonoStereo)==-1)
998275970Scy	{ /* Fatal error */
999275970Scy	printf ("\nUnable to set mono/stereo, aborting...\n\n");
1000275970Scy	exit(-1);
1001275970Scy	}
1002275970Scy
1003275970Scy	if (MonoStereo != MONO)
1004275970Scy	{
1005275970Scy	printf ("\nUnable to set mono/stereo for mono, aborting...\n\n");
1006275970Scy	exit(-1);
1007275970Scy	}
1008275970Scy
1009275970Scy	/* Now set sample rate */
1010275970Scy	SampleRate = SetSampleRate;
1011275970Scy	if (ioctl(fd, SNDCTL_DSP_SPEED, &SampleRate)==-1)
1012275970Scy	{ /* Fatal error */
1013275970Scy	printf ("\nUnable to set sample rate to %d, returned %d, aborting...\n\n", SetSampleRate, SampleRate);
1014275970Scy	exit(-1);
1015275970Scy	}
1016275970Scy
1017275970Scy	SampleRateDifference = SampleRate - SetSampleRate;
1018275970Scy
1019275970Scy	if  (SampleRateDifference < 0)
1020275970Scy		SampleRateDifference = - SampleRateDifference;
1021275970Scy
1022275970Scy	/* Fixed allowable sample rate error 0.1% */
1023275970Scy	if (SampleRateDifference > (SetSampleRate/1000))
1024275970Scy	{
1025275970Scy	printf ("\nUnable to set sample rate to %d, result was %d, more than 0.1 percent, aborting...\n\n", SetSampleRate, SampleRate);
1026275970Scy	exit(-1);
1027275970Scy	}
1028275970Scy	else
1029275970Scy	{
1030275970Scy	/* printf ("\nAttempt to set sample rate to %d, actual %d...\n\n", SetSampleRate, SampleRate); */
1031275970Scy	}
1032275970Scy#else
1033275970Scy	rval = ioctl(fd, AUDIO_GETINFO, &info);
1034275970Scy	if (rval < 0) {
1035275970Scy		printf("\naudio control %s", strerror(errno));
1036275970Scy		exit(0);
1037275970Scy	}
1038275970Scy	info.play.port = port;
1039275970Scy	info.play.gain = level;
1040275970Scy	info.play.sample_rate = SetSampleRate;
1041275970Scy	info.play.channels = 1;
1042275970Scy	info.play.precision = 8;
1043275970Scy	info.play.encoding = AUDIO_ENCODING_ULAW;
1044275970Scy	printf("\nport %d gain %d rate %d chan %d prec %d encode %d\n",
1045275970Scy	    info.play.port, info.play.gain, info.play.sample_rate,
1046275970Scy	    info.play.channels, info.play.precision,
1047275970Scy	    info.play.encoding);
1048275970Scy	ioctl(fd, AUDIO_SETINFO, &info);
1049275970Scy#endif
1050275970Scy
1051275970Scy 	/*
1052275970Scy	 * Unless specified otherwise, read the system clock and
1053275970Scy	 * initialize the time.
1054275970Scy	 */
1055275970Scy	gettimeofday(&TimeValue, NULL);		// Now always read the system time to keep "real time" of operation.
1056275970Scy	NowRealTime = BaseRealTime = SecondsPartOfTime = TimeValue.tv_sec;
1057275970Scy	SecondsRunningSimulationTime = 0;	// Just starting simulation, running zero seconds as of now.
1058275970Scy	StabilityCount = 0;					// No stability yet.
1059275970Scy
1060275970Scy	if	(utc)
1061275970Scy		{
1062275970Scy		DayOfYear = ConvertMonthDayToDayOfYear (Year, Month, DayOfMonth);
1063275970Scy		}
1064275970Scy	else
1065275970Scy		{
1066275970Scy		/* Apply offset to time. */
1067275970Scy		if	(UseOffsetSecondsInt >= 0)
1068275970Scy			SecondsPartOfTime += (time_t)   UseOffsetSecondsInt;
1069275970Scy		else
1070275970Scy			SecondsPartOfTime -= (time_t) (-UseOffsetSecondsInt);
1071275970Scy
1072275970Scy		TimeStructure = gmtime(&SecondsPartOfTime);
1073275970Scy		Minute = TimeStructure->tm_min;
1074275970Scy		Hour = TimeStructure->tm_hour;
1075275970Scy		DayOfYear = TimeStructure->tm_yday + 1;
1076275970Scy		Year = TimeStructure->tm_year % 100;
1077275970Scy		Second = TimeStructure->tm_sec;
1078275970Scy
1079275970Scy		/*
1080275970Scy		 * Delay the first second so the generator is accurately
1081275970Scy		 * aligned with the system clock within one sample (125
1082275970Scy		 * microseconds ).
1083275970Scy		 */
1084275970Scy		delay(SECOND - TimeValue.tv_usec * 8 / 1000);
1085275970Scy		}
1086275970Scy
1087275970Scy	StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR);
1088275970Scy
1089275970Scy	memset(code, 0, sizeof(code));
1090275970Scy	switch (encode) {
1091275970Scy
1092275970Scy	/*
1093275970Scy	 * For WWV/H and default time, carefully set the signal
1094275970Scy	 * generator seconds number to agree with the current time.
1095275970Scy	 */
1096275970Scy	case WWV:
1097275970Scy		printf("WWV time signal, starting point:\n");
1098275970Scy		printf(" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Minute tone = %d Hz, Hour tone = %d Hz.\n",
1099275970Scy		    Year, DayOfYear, Hour, Minute, Second, tone, HourTone);
1100275970Scy		snprintf(code, sizeof(code), "%01d%03d%02d%02d%01d",
1101275970Scy		    Year / 10, DayOfYear, Hour, Minute, Year % 10);
1102275970Scy		if  (Verbose)
1103275970Scy			{
1104275970Scy		    printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s",
1105275970Scy				Year, DayOfYear, Hour, Minute, Second, code);
1106275970Scy
1107275970Scy				if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
1108275970Scy				printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
1109275970Scy			else
1110275970Scy				printf ("\n");
1111275970Scy			}
1112275970Scy
1113275970Scy		ptr = 8;
1114275970Scy		for (BitNumber = 0; BitNumber <= Second; BitNumber++) {
1115275970Scy			if (progx[BitNumber].sw == DEC)
1116275970Scy				ptr--;
1117275970Scy		}
1118275970Scy		break;
1119275970Scy
1120275970Scy	/*
1121275970Scy	 * For IRIG the signal generator runs every second, so requires
1122275970Scy	 * no additional alignment.
1123275970Scy	 */
1124275970Scy	case IRIG:
1125275970Scy		printf ("IRIG-B time signal, starting point:\n");
1126275970Scy		printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n",
1127275970Scy		    Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds);
1128275970Scy		printf ("\n");
1129275970Scy		if  (Verbose)
1130275970Scy		    {
1131275970Scy    		printf ("Codes: \".\" = marker/position indicator, \"-\" = zero dummy bit, \"0\" = zero bit, \"1\" = one bit.\n");
1132275970Scy			if  ((EnableRateCorrection) || (AddCycle) || (RemoveCycle))
1133275970Scy				{
1134275970Scy				printf ("       \"o\" = short zero, \"*\" = long zero, \"x\" = short one, \"+\" = long one.\n");
1135275970Scy				}
1136275970Scy	    	printf ("Numerical values are time order reversed in output to make it easier to read.\n");
1137275970Scy    		/*                 111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999 */
1138275970Scy	    	/*       0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 */
1139275970Scy		    printf ("\n");
1140275970Scy    		printf ("Legend of output codes:\n");
1141275970Scy	    	//printf ("\n");
1142275970Scy		    //printf ("|  StraightBinSecs  | IEEE_1344_Control |   Year  |    Day_of_Year    |  Hours  | Minutes |Seconds |\n");
1143275970Scy    		//printf ("|  ---------------  | ----------------- |   ----  |    -----------    |  -----  | ------- |------- |\n");
1144275970Scy	    	//printf ("|                   |                   |         |                   |         |         |        |\n");
1145275970Scy	    	}
1146275970Scy		break;
1147275970Scy	}
1148275970Scy
1149275970Scy	/*
1150275970Scy	 * Run the signal generator to generate new timecode strings
1151275970Scy	 * once per minute for WWV/H and once per second for IRIG.
1152275970Scy	 */
1153275970Scy	for (CountOfSecondsSent=0; ((SecondsToSend==0) || (CountOfSecondsSent<SecondsToSend)); CountOfSecondsSent++)
1154275970Scy		{
1155275970Scy		if  ((encode == IRIG) && (((Second % 20) == 0) || (CountOfSecondsSent == 0)))
1156275970Scy			{
1157275970Scy	    	printf ("\n");
1158275970Scy
1159275970Scy			printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n",
1160275970Scy			    Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds);
1161275970Scy			if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
1162275970Scy				{
1163275970Scy				printf (" CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
1164275970Scy				if  ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0)))
1165275970Scy					{
1166275970Scy					RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent);
1167275970Scy					printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n",
1168275970Scy									RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate);
1169275970Scy					}
1170275970Scy				}
1171275970Scy			else
1172275970Scy				printf ("\n");
1173275970Scy
1174275970Scy		    /* printf ("|Seconds | Minutes |  Hours  |    Day_of_Year    |   Year  | IEEE_1344_Control |  StraightBinSecs  |\n");
1175275970Scy    		printf ("|------- | ------- |  -----  |    -----------    |   ----  | ----------------- |-------------------|\n");
1176275970Scy	    	printf ("|        |         |         |                   |         |                   |                   |\n");*/
1177275970Scy		    printf ("|  StraightBinSecs  | IEEE_1344_Control |   Year  |    Day_of_Year    |  Hours  | Minutes |Seconds |\n");
1178275970Scy    		printf ("|  ---------------  | ----------------- |   ----  |    -----------    |  -----  | ------- |------- |\n");
1179275970Scy	    	printf ("|                   |                   |         |                   |         |         |        |\n");
1180275970Scy			}
1181275970Scy
1182275970Scy		if  (RemoveCycle)
1183275970Scy			{
1184275970Scy			RateCorrection = -1;
1185275970Scy			TotalSecondsCorrected ++;
1186275970Scy			}
1187275970Scy		else
1188275970Scy			{
1189275970Scy			if  (AddCycle)
1190275970Scy				{
1191275970Scy				TotalSecondsCorrected ++;
1192275970Scy				RateCorrection = +1;
1193275970Scy				}
1194275970Scy			else
1195275970Scy				RateCorrection = 0;
1196275970Scy			}
1197275970Scy
1198275970Scy		/*
1199275970Scy		 * Crank the state machine to propagate carries to the
1200275970Scy		 * year of century. Note that we delayed up to one
1201275970Scy		 * second for alignment after reading the time, so this
1202275970Scy		 * is the next second.
1203275970Scy		 */
1204275970Scy
1205275970Scy		if  (LeapState == LEAPSTATE_NORMAL)
1206275970Scy			{
1207275970Scy			/* If on the second of a leap (second 59 in the specified minute), then add or delete a second */
1208275970Scy			if  ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute))
1209275970Scy				{
1210275970Scy				/* To delete a second, which means we go from 58->60 instead of 58->59->00. */
1211275970Scy				if  ((DeleteLeapSecond) && (Second == 58))
1212275970Scy					{
1213275970Scy					LeapState = LEAPSTATE_DELETING;
1214275970Scy
1215275970Scy					if	(Debug)
1216275970Scy						printf ("\n<--- Ready to delete a leap second...\n");
1217275970Scy					}
1218275970Scy				else
1219275970Scy					{	/* Delete takes precedence over insert. */
1220275970Scy					/* To add a second, which means we go from 59->60->00 instead of 59->00. */
1221275970Scy					if  ((InsertLeapSecond) && (Second == 59))
1222275970Scy						{
1223275970Scy						LeapState = LEAPSTATE_INSERTING;
1224275970Scy
1225275970Scy						if	(Debug)
1226275970Scy							printf ("\n<--- Ready to insert a leap second...\n");
1227275970Scy						}
1228275970Scy					}
1229275970Scy				}
1230275970Scy			}
1231275970Scy
1232275970Scy		switch (LeapState)
1233275970Scy			{
1234275970Scy			case LEAPSTATE_NORMAL:
1235275970Scy				Second = (Second + 1) % 60;
1236275970Scy				break;
1237275970Scy
1238275970Scy			case LEAPSTATE_DELETING:
1239275970Scy				Second = 0;
1240275970Scy				LeapState = LEAPSTATE_NORMAL;
1241275970Scy
1242275970Scy				if	(Debug)
1243275970Scy					printf ("\n<--- Deleting a leap second...\n");
1244275970Scy				break;
1245275970Scy
1246275970Scy			case LEAPSTATE_INSERTING:
1247275970Scy				Second = 60;
1248275970Scy				LeapState = LEAPSTATE_ZERO_AFTER_INSERT;
1249275970Scy
1250275970Scy				if	(Debug)
1251275970Scy					printf ("\n<--- Inserting a leap second...\n");
1252275970Scy				break;
1253275970Scy
1254275970Scy			case LEAPSTATE_ZERO_AFTER_INSERT:
1255275970Scy				Second = 0;
1256275970Scy				LeapState = LEAPSTATE_NORMAL;
1257275970Scy
1258275970Scy				if	(Debug)
1259275970Scy					printf ("\n<--- Inserted a leap second, now back to zero...\n");
1260275970Scy				break;
1261275970Scy
1262275970Scy			default:
1263275970Scy				printf ("\n\nLeap second state invalid value of %d, aborting...", LeapState);
1264275970Scy				exit (-1);
1265275970Scy				break;
1266275970Scy			}
1267275970Scy
1268275970Scy		/* Check for second rollover, increment minutes and ripple upward if required. */
1269275970Scy		if (Second == 0) {
1270275970Scy			Minute++;
1271275970Scy			if (Minute >= 60) {
1272275970Scy				Minute = 0;
1273275970Scy				Hour++;
1274275970Scy			}
1275275970Scy
1276275970Scy			/* Check for activation of DST switch. */
1277275970Scy			/* If DST is active, this would mean that at the appointed time, we de-activate DST, */
1278275970Scy			/* which translates to going backward an hour (repeating the last hour). */
1279275970Scy			/* If DST is not active, this would mean that at the appointed time, we activate DST, */
1280275970Scy			/* which translates to going forward an hour (skipping the next hour). */
1281275970Scy			if	(DstSwitchFlag)
1282275970Scy				{
1283275970Scy				/* The actual switch happens on the zero'th second of the actual minute specified. */
1284275970Scy				if	((Year == DstSwitchYear) && (DayOfYear == DstSwitchDayOfYear) && (Hour == DstSwitchHour) && (Minute == DstSwitchMinute))
1285275970Scy					{
1286275970Scy					if  (DstFlag == 0)
1287275970Scy						{	/* DST flag is zero, not in DST, going to DST, "spring ahead", so increment hour by two instead of one. */
1288275970Scy						Hour++;
1289275970Scy						DstFlag = 1;
1290275970Scy
1291275970Scy						/* Must adjust offset to keep consistent with UTC. */
1292275970Scy						/* Here we have to increase offset by one hour.  If it goes from negative to positive, then we fix that. */
1293275970Scy						if	(OffsetSignBit == 0)
1294275970Scy							{	/* Offset is positive */
1295275970Scy							if	(OffsetOnes == 0x0F)
1296275970Scy								{
1297275970Scy								OffsetSignBit = 1;
1298275970Scy								OffsetOnes    = (OffsetHalf == 0) ? 8 : 7;
1299275970Scy								}
1300275970Scy							else
1301275970Scy								OffsetOnes++;
1302275970Scy							}
1303275970Scy						else
1304275970Scy							{	/* Offset is negative */
1305275970Scy							if  (OffsetOnes == 0)
1306275970Scy								{
1307275970Scy								OffsetSignBit = 0;
1308275970Scy								OffsetOnes    = (OffsetHalf == 0) ? 1 : 0;
1309275970Scy								}
1310275970Scy							else
1311275970Scy								OffsetOnes--;
1312275970Scy							}
1313275970Scy
1314275970Scy						if	(Debug)
1315275970Scy							printf ("\n<--- DST activated, spring ahead an hour, new offset !...\n");
1316275970Scy						}
1317275970Scy					else
1318275970Scy						{	/* DST flag is non zero, in DST, going out of DST, "fall back", so no increment of hour. */
1319275970Scy						Hour--;
1320275970Scy						DstFlag = 0;
1321275970Scy
1322275970Scy						/* Must adjust offset to keep consistent with UTC. */
1323275970Scy						/* Here we have to reduce offset by one hour.  If it goes negative, then we fix that. */
1324275970Scy						if	(OffsetSignBit == 0)
1325275970Scy							{	/* Offset is positive */
1326275970Scy							if  (OffsetOnes == 0)
1327275970Scy								{
1328275970Scy								OffsetSignBit = 1;
1329275970Scy								OffsetOnes    = (OffsetHalf == 0) ? 1 : 0;
1330275970Scy								}
1331275970Scy							else
1332275970Scy								OffsetOnes--;
1333275970Scy							}
1334275970Scy						else
1335275970Scy							{	/* Offset is negative */
1336275970Scy							if	(OffsetOnes == 0x0F)
1337275970Scy								{
1338275970Scy								OffsetSignBit = 0;
1339275970Scy								OffsetOnes    = (OffsetHalf == 0) ? 8 : 7;
1340275970Scy								}
1341275970Scy							else
1342275970Scy								OffsetOnes++;
1343275970Scy							}
1344275970Scy
1345275970Scy						if	(Debug)
1346275970Scy							printf ("\n<--- DST de-activated, fall back an hour!...\n");
1347275970Scy						}
1348275970Scy
1349275970Scy					DstSwitchFlag = FALSE;	/* One time deal, not intended to run this program past two switches... */
1350275970Scy					}
1351275970Scy				}
1352275970Scy
1353275970Scy			if (Hour >= 24) {
1354275970Scy				/* Modified, just in case dumb case where activating DST advances 23h59:59 -> 01h00:00 */
1355275970Scy				Hour = Hour % 24;
1356275970Scy				DayOfYear++;
1357275970Scy			}
1358275970Scy
1359275970Scy			/*
1360275970Scy			 * At year rollover check for leap second.
1361275970Scy			 */
1362275970Scy			if (DayOfYear >= (Year & 0x3 ? 366 : 367)) {
1363275970Scy				if (leap) {
1364275970Scy					WWV_Second(DATA0, RateCorrection);
1365275970Scy					if  (Verbose)
1366275970Scy					    printf("\nLeap!");
1367275970Scy					leap = 0;
1368275970Scy				}
1369275970Scy				DayOfYear = 1;
1370275970Scy				Year++;
1371275970Scy			}
1372275970Scy			if (encode == WWV) {
1373275970Scy				snprintf(code, sizeof(code),
1374275970Scy				    "%01d%03d%02d%02d%01d", Year / 10,
1375275970Scy				    DayOfYear, Hour, Minute, Year % 10);
1376275970Scy				if  (Verbose)
1377275970Scy				    printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s",
1378275970Scy						Year, DayOfYear, Hour, Minute, Second, code);
1379275970Scy
1380275970Scy				if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
1381275970Scy					{
1382275970Scy					printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
1383275970Scy					if  ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0)))
1384275970Scy						{
1385275970Scy						RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent);
1386275970Scy						printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n",
1387275970Scy										RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate);
1388275970Scy						}
1389275970Scy					}
1390275970Scy				else
1391275970Scy					printf ("\n");
1392275970Scy
1393275970Scy				ptr = 8;
1394275970Scy			}
1395275970Scy		}	/* End of "if  (Second == 0)" */
1396275970Scy
1397275970Scy		/* After all that, if we are in the minute just prior to a leap second, warn of leap second pending */
1398275970Scy		/* and of the polarity */
1399275970Scy		if  ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute))
1400275970Scy			{
1401275970Scy			LeapSecondPending = TRUE;
1402275970Scy			LeapSecondPolarity = DeleteLeapSecond;
1403275970Scy			}
1404275970Scy		else
1405275970Scy			{
1406275970Scy			LeapSecondPending = FALSE;
1407275970Scy			LeapSecondPolarity = FALSE;
1408275970Scy			}
1409275970Scy
1410275970Scy		/* Notification through IEEE 1344 happens during the whole minute previous to the minute specified. */
1411275970Scy		/* The time of that minute has been previously calculated. */
1412275970Scy		if	((Year == DstSwitchPendingYear) && (DayOfYear == DstSwitchPendingDayOfYear) &&
1413275970Scy					(Hour == DstSwitchPendingHour) && (Minute == DstSwitchPendingMinute))
1414275970Scy			{
1415275970Scy			DstPendingFlag = TRUE;
1416275970Scy			}
1417275970Scy		else
1418275970Scy			{
1419275970Scy			DstPendingFlag = FALSE;
1420275970Scy			}
1421275970Scy
1422275970Scy
1423275970Scy		StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR);
1424275970Scy
1425275970Scy		if (encode == IRIG) {
1426275970Scy			if  (IrigIncludeIeee)
1427275970Scy				{
1428275970Scy				if  ((OffsetOnes == 0) && (OffsetHalf == 0))
1429275970Scy					OffsetSignBit = 0;
1430275970Scy
1431275970Scy				ControlFunctions = (LeapSecondPending == 0 ? 0x00000 : 0x00001) | (LeapSecondPolarity == 0 ? 0x00000 : 0x00002)
1432275970Scy						| (DstPendingFlag == 0 ? 0x00000 : 0x00004) | (DstFlag == 0 ? 0x00000 : 0x00008)
1433275970Scy						| (OffsetSignBit == 0 ? 0x00000 : 0x00010)  | ((OffsetOnes & 0x0F) << 5)           | (OffsetHalf == 0 ? 0x00000 : 0x00200)
1434275970Scy						| ((TimeQuality & 0x0F) << 10);
1435275970Scy				/* if  (Verbose)
1436275970Scy				        printf ("\nDstFlag = %d, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d, TimeQuality = 0x%1.1X ==> ControlFunctions = 0x%5.5X...",
1437275970Scy						    DstFlag, OffsetSignBit, OffsetOnes, OffsetHalf, TimeQuality, ControlFunctions);
1438275970Scy				*/
1439275970Scy				}
1440275970Scy			else
1441275970Scy				ControlFunctions = 0;
1442275970Scy
1443275970Scy			/*
1444275970Scy						      YearDay HourMin Sec
1445275970Scy			snprintf(code, sizeof(code), "%04x%04d%06d%02d%02d%02d",
1446275970Scy				0, Year, DayOfYear, Hour, Minute, Second);
1447275970Scy			*/
1448275970Scy			if  (IrigIncludeYear) {
1449275970Scy				snprintf(ParityString, sizeof(ParityString),
1450275970Scy				    "%04X%02d%04d%02d%02d%02d",
1451275970Scy				    ControlFunctions & 0x7FFF, Year,
1452275970Scy				    DayOfYear, Hour, Minute, Second);
1453275970Scy			} else {
1454275970Scy				snprintf(ParityString, sizeof(ParityString),
1455275970Scy				    "%04X%02d%04d%02d%02d%02d",
1456275970Scy				    ControlFunctions & 0x7FFF,
1457275970Scy				    0, DayOfYear, Hour, Minute, Second);
1458275970Scy			}
1459275970Scy
1460275970Scy			if  (IrigIncludeIeee)
1461275970Scy				{
1462275970Scy				ParitySum = 0;
1463275970Scy				for (StringPointer=ParityString; *StringPointer!=NUL; StringPointer++)
1464275970Scy					{
1465275970Scy					switch (toupper(*StringPointer))
1466275970Scy						{
1467275970Scy						case '1':
1468275970Scy						case '2':
1469275970Scy						case '4':
1470275970Scy						case '8':
1471275970Scy							ParitySum += 1;
1472275970Scy							break;
1473275970Scy
1474275970Scy						case '3':
1475275970Scy						case '5':
1476275970Scy						case '6':
1477275970Scy						case '9':
1478275970Scy						case 'A':
1479275970Scy						case 'C':
1480275970Scy							ParitySum += 2;
1481275970Scy							break;
1482275970Scy
1483275970Scy						case '7':
1484275970Scy						case 'B':
1485275970Scy						case 'D':
1486275970Scy						case 'E':
1487275970Scy							ParitySum += 3;
1488275970Scy							break;
1489275970Scy
1490275970Scy						case 'F':
1491275970Scy							ParitySum += 4;
1492275970Scy							break;
1493275970Scy						}
1494275970Scy					}
1495275970Scy
1496275970Scy				if  ((ParitySum & 0x01) == 0x01)
1497275970Scy					ParityValue = 0x01;
1498275970Scy				else
1499275970Scy					ParityValue = 0;
1500275970Scy				}
1501275970Scy			else
1502275970Scy				ParityValue = 0;
1503275970Scy
1504275970Scy			ControlFunctions |= ((ParityValue & 0x01) << 14);
1505275970Scy
1506275970Scy			if  (IrigIncludeYear) {
1507275970Scy				snprintf(code, sizeof(code),
1508275970Scy				    /* YearDay HourMin Sec */
1509275970Scy				    "%05X%05X%02d%04d%02d%02d%02d",
1510275970Scy				    StraightBinarySeconds,
1511275970Scy				    ControlFunctions, Year, DayOfYear,
1512275970Scy				    Hour, Minute, Second);
1513275970Scy			} else {
1514275970Scy				snprintf(code, sizeof(code),
1515275970Scy				    /* YearDay HourMin Sec */
1516275970Scy				    "%05X%05X%02d%04d%02d%02d%02d",
1517275970Scy				    StraightBinarySeconds,
1518275970Scy				    ControlFunctions, 0, DayOfYear,
1519275970Scy				    Hour, Minute, Second);
1520275970Scy			}
1521275970Scy
1522275970Scy			if  (Debug)
1523275970Scy				printf("\nCode string: %s, ParityString = %s, ParitySum = 0x%2.2X, ParityValue = %d, DstFlag = %d...\n", code, ParityString, ParitySum, ParityValue, DstFlag);
1524275970Scy
1525275970Scy			ptr = strlen(code)-1;
1526275970Scy			OldPtr = 0;
1527275970Scy		}
1528275970Scy
1529275970Scy		/*
1530275970Scy		 * Generate data for the second
1531275970Scy		 */
1532275970Scy		switch (encode) {
1533275970Scy
1534275970Scy		/*
1535275970Scy		 * The IRIG second consists of 20 BCD digits of width-
1536275970Scy		 * modulateod pulses at 2, 5 and 8 ms and modulated 50
1537275970Scy		 * percent on the 1000-Hz carrier.
1538275970Scy		 */
1539275970Scy		case IRIG:
1540275970Scy			/* Initialize the output string */
1541275970Scy			OutputDataString[0] = '\0';
1542275970Scy
1543275970Scy			for (BitNumber = 0; BitNumber < 100; BitNumber++) {
1544275970Scy				FrameNumber = (BitNumber/10) + 1;
1545275970Scy				switch (FrameNumber)
1546275970Scy					{
1547275970Scy					case 1:
1548275970Scy						/* bits 0 to 9, first frame */
1549275970Scy						sw  = progz[BitNumber % 10].sw;
1550275970Scy						arg = progz[BitNumber % 10].arg;
1551275970Scy						break;
1552275970Scy
1553275970Scy					case 2:
1554275970Scy					case 3:
1555275970Scy					case 4:
1556275970Scy					case 5:
1557275970Scy					case 6:
1558275970Scy						/* bits 10 to 59, second to sixth frame */
1559275970Scy						sw  = progy[BitNumber % 10].sw;
1560275970Scy						arg = progy[BitNumber % 10].arg;
1561275970Scy						break;
1562275970Scy
1563275970Scy					case 7:
1564275970Scy						/* bits 60 to 69, seventh frame */
1565275970Scy						sw  = progw[BitNumber % 10].sw;
1566275970Scy						arg = progw[BitNumber % 10].arg;
1567275970Scy						break;
1568275970Scy
1569275970Scy					case 8:
1570275970Scy						/* bits 70 to 79, eighth frame */
1571275970Scy						sw  = progv[BitNumber % 10].sw;
1572275970Scy						arg = progv[BitNumber % 10].arg;
1573275970Scy						break;
1574275970Scy
1575275970Scy					case 9:
1576275970Scy						/* bits 80 to 89, ninth frame */
1577275970Scy						sw  = progw[BitNumber % 10].sw;
1578275970Scy						arg = progw[BitNumber % 10].arg;
1579275970Scy						break;
1580275970Scy
1581275970Scy					case 10:
1582275970Scy						/* bits 90 to 99, tenth frame */
1583275970Scy						sw  = progu[BitNumber % 10].sw;
1584275970Scy						arg = progu[BitNumber % 10].arg;
1585275970Scy						break;
1586275970Scy
1587275970Scy					default:
1588275970Scy						/* , Unexpected values of FrameNumber */
1589275970Scy						printf ("\n\nUnexpected value of FrameNumber = %d, cannot parse, aborting...\n\n", FrameNumber);
1590275970Scy						exit (-1);
1591275970Scy						break;
1592275970Scy					}
1593275970Scy
1594275970Scy				switch(sw) {
1595275970Scy
1596275970Scy				case DECC:	/* decrement pointer and send bit. */
1597275970Scy					ptr--;
1598275970Scy				case COEF:	/* send BCD bit */
1599275970Scy					AsciiValue = toupper(code[ptr]);
1600275970Scy					HexValue   = isdigit(AsciiValue) ? AsciiValue - '0' : (AsciiValue - 'A')+10;
1601275970Scy					/* if  (Debug) {
1602275970Scy						if  (ptr != OldPtr) {
1603275970Scy						if  (Verbose)
1604275970Scy						    printf("\n(%c->%X)", AsciiValue, HexValue);
1605275970Scy						OldPtr = ptr;
1606275970Scy						}
1607275970Scy					}
1608275970Scy					*/
1609275970Scy					// OK, adjust all unused bits in hundreds of days.
1610275970Scy					if  ((FrameNumber == 5) && ((BitNumber % 10) > 1))
1611275970Scy						{
1612275970Scy						if  (RateCorrection < 0)
1613275970Scy							{	// Need to remove cycles to catch up.
1614275970Scy							if  ((HexValue & arg) != 0)
1615275970Scy								{
1616275970Scy								if  (Unmodulated)
1617275970Scy									{
1618275970Scy									poop(M5, 1000, HIGH, UnmodulatedInverted);
1619275970Scy									poop(M5-1, 1000, LOW,  UnmodulatedInverted);
1620275970Scy
1621275970Scy									TotalCyclesRemoved += 1;
1622275970Scy									}
1623275970Scy								else
1624275970Scy									{
1625275970Scy									peep(M5, 1000, HIGH);
1626275970Scy									peep(M5-1, 1000, LOW);
1627275970Scy
1628275970Scy									TotalCyclesRemoved += 1;
1629275970Scy									}
1630275970Scy								strlcat(OutputDataString, "x", OUTPUT_DATA_STRING_LENGTH);
1631275970Scy								}
1632275970Scy							else
1633275970Scy								{
1634275970Scy								if	(Unmodulated)
1635275970Scy									{
1636275970Scy									poop(M2, 1000, HIGH, UnmodulatedInverted);
1637275970Scy									poop(M8-1, 1000, LOW,  UnmodulatedInverted);
1638275970Scy
1639275970Scy									TotalCyclesRemoved += 1;
1640275970Scy									}
1641275970Scy								else
1642275970Scy									{
1643275970Scy									peep(M2, 1000, HIGH);
1644275970Scy									peep(M8-1, 1000, LOW);
1645275970Scy
1646275970Scy									TotalCyclesRemoved += 1;
1647275970Scy									}
1648275970Scy								strlcat(OutputDataString, "o", OUTPUT_DATA_STRING_LENGTH);
1649275970Scy								}
1650275970Scy							}	// End of true clause for "if  (RateCorrection < 0)"
1651275970Scy						else
1652275970Scy							{	// Else clause for "if  (RateCorrection < 0)"
1653275970Scy							if  (RateCorrection > 0)
1654275970Scy								{	// Need to add cycles to slow back down.
1655275970Scy								if  ((HexValue & arg) != 0)
1656275970Scy									{
1657275970Scy									if  (Unmodulated)
1658275970Scy										{
1659275970Scy										poop(M5, 1000, HIGH, UnmodulatedInverted);
1660275970Scy										poop(M5+1, 1000, LOW,  UnmodulatedInverted);
1661275970Scy
1662275970Scy										TotalCyclesAdded += 1;
1663275970Scy										}
1664275970Scy									else
1665275970Scy										{
1666275970Scy										peep(M5, 1000, HIGH);
1667275970Scy										peep(M5+1, 1000, LOW);
1668275970Scy
1669275970Scy										TotalCyclesAdded += 1;
1670275970Scy										}
1671275970Scy									strlcat(OutputDataString, "+", OUTPUT_DATA_STRING_LENGTH);
1672275970Scy									}
1673275970Scy								else
1674275970Scy									{
1675275970Scy									if	(Unmodulated)
1676275970Scy										{
1677275970Scy										poop(M2, 1000, HIGH, UnmodulatedInverted);
1678275970Scy										poop(M8+1, 1000, LOW,  UnmodulatedInverted);
1679275970Scy
1680275970Scy										TotalCyclesAdded += 1;
1681275970Scy										}
1682275970Scy									else
1683275970Scy										{
1684275970Scy										peep(M2, 1000, HIGH);
1685275970Scy										peep(M8+1, 1000, LOW);
1686275970Scy
1687275970Scy										TotalCyclesAdded += 1;
1688275970Scy										}
1689275970Scy									strlcat(OutputDataString, "*", OUTPUT_DATA_STRING_LENGTH);
1690275970Scy									}
1691275970Scy								}	// End of true clause for "if  (RateCorrection > 0)"
1692275970Scy							else
1693275970Scy								{	// Else clause for "if  (RateCorrection > 0)"
1694275970Scy								// Rate is OK, just do what you feel!
1695275970Scy								if  ((HexValue & arg) != 0)
1696275970Scy									{
1697275970Scy									if  (Unmodulated)
1698275970Scy										{
1699275970Scy										poop(M5, 1000, HIGH, UnmodulatedInverted);
1700275970Scy										poop(M5, 1000, LOW,  UnmodulatedInverted);
1701275970Scy										}
1702275970Scy									else
1703275970Scy										{
1704275970Scy										peep(M5, 1000, HIGH);
1705275970Scy										peep(M5, 1000, LOW);
1706275970Scy										}
1707275970Scy									strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH);
1708275970Scy									}
1709275970Scy								else
1710275970Scy									{
1711275970Scy									if	(Unmodulated)
1712275970Scy										{
1713275970Scy										poop(M2, 1000, HIGH, UnmodulatedInverted);
1714275970Scy										poop(M8, 1000, LOW,  UnmodulatedInverted);
1715275970Scy										}
1716275970Scy									else
1717275970Scy										{
1718275970Scy										peep(M2, 1000, HIGH);
1719275970Scy										peep(M8, 1000, LOW);
1720275970Scy										}
1721275970Scy									strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH);
1722275970Scy									}
1723275970Scy								}	// End of else clause for "if  (RateCorrection > 0)"
1724275970Scy							}	// End of else claues for "if  (RateCorrection < 0)"
1725275970Scy						}	// End of true clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
1726275970Scy					else
1727275970Scy						{	// Else clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
1728275970Scy						if  ((HexValue & arg) != 0)
1729275970Scy							{
1730275970Scy							if  (Unmodulated)
1731275970Scy								{
1732275970Scy								poop(M5, 1000, HIGH, UnmodulatedInverted);
1733275970Scy								poop(M5, 1000, LOW,  UnmodulatedInverted);
1734275970Scy								}
1735275970Scy							else
1736275970Scy								{
1737275970Scy								peep(M5, 1000, HIGH);
1738275970Scy								peep(M5, 1000, LOW);
1739275970Scy								}
1740275970Scy							strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH);
1741275970Scy							}
1742275970Scy						else
1743275970Scy							{
1744275970Scy							if	(Unmodulated)
1745275970Scy								{
1746275970Scy								poop(M2, 1000, HIGH, UnmodulatedInverted);
1747275970Scy								poop(M8, 1000, LOW,  UnmodulatedInverted);
1748275970Scy								}
1749275970Scy							else
1750275970Scy								{
1751275970Scy								peep(M2, 1000, HIGH);
1752275970Scy								peep(M8, 1000, LOW);
1753275970Scy								}
1754275970Scy							strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH);
1755275970Scy							}
1756275970Scy						} // end of else clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
1757275970Scy					break;
1758275970Scy
1759275970Scy				case DECZ:	/* decrement pointer and send zero bit */
1760275970Scy					ptr--;
1761275970Scy					if	(Unmodulated)
1762275970Scy						{
1763275970Scy						poop(M2, 1000, HIGH, UnmodulatedInverted);
1764275970Scy						poop(M8, 1000, LOW,  UnmodulatedInverted);
1765275970Scy						}
1766275970Scy					else
1767275970Scy						{
1768275970Scy						peep(M2, 1000, HIGH);
1769275970Scy						peep(M8, 1000, LOW);
1770275970Scy						}
1771275970Scy					strlcat(OutputDataString, "-", OUTPUT_DATA_STRING_LENGTH);
1772275970Scy					break;
1773275970Scy
1774275970Scy				case DEC:	/* send marker/position indicator IM/PI bit */
1775275970Scy					ptr--;
1776275970Scy				case NODEC:	/* send marker/position indicator IM/PI bit but no decrement pointer */
1777275970Scy				case MIN:	/* send "second start" marker/position indicator IM/PI bit */
1778275970Scy					if  (Unmodulated)
1779275970Scy						{
1780275970Scy						poop(arg,      1000, HIGH, UnmodulatedInverted);
1781275970Scy						poop(10 - arg, 1000, LOW,  UnmodulatedInverted);
1782275970Scy						}
1783275970Scy					else
1784275970Scy						{
1785275970Scy						peep(arg,      1000, HIGH);
1786275970Scy						peep(10 - arg, 1000, LOW);
1787275970Scy						}
1788275970Scy					strlcat(OutputDataString, ".", OUTPUT_DATA_STRING_LENGTH);
1789275970Scy					break;
1790275970Scy
1791275970Scy				default:
1792275970Scy					printf ("\n\nUnknown state machine value \"%d\", unable to continue, aborting...\n\n", sw);
1793275970Scy					exit (-1);
1794275970Scy					break;
1795275970Scy				}
1796275970Scy				if (ptr < 0)
1797275970Scy					break;
1798275970Scy			}
1799275970Scy			ReverseString ( OutputDataString );
1800275970Scy			if  (Verbose)
1801275970Scy				{
1802275970Scy    			printf("%s", OutputDataString);
1803275970Scy				if  (RateCorrection > 0)
1804275970Scy					printf(" fast\n");
1805275970Scy				else
1806275970Scy					{
1807275970Scy					if  (RateCorrection < 0)
1808275970Scy						printf (" slow\n");
1809275970Scy					else
1810275970Scy						printf ("\n");
1811275970Scy					}
1812275970Scy				}
1813275970Scy			break;
1814275970Scy
1815275970Scy		/*
1816275970Scy		 * The WWV/H second consists of 9 BCD digits of width-
1817275970Scy		 * modulateod pulses 200, 500 and 800 ms at 100-Hz.
1818275970Scy		 */
1819275970Scy		case WWV:
1820275970Scy			sw = progx[Second].sw;
1821275970Scy			arg = progx[Second].arg;
1822275970Scy			switch(sw) {
1823275970Scy
1824275970Scy			case DATA:		/* send data bit */
1825275970Scy				WWV_Second(arg, RateCorrection);
1826275970Scy				if  (Verbose)
1827275970Scy					{
1828275970Scy					if  (arg == DATA0)
1829275970Scy						printf ("0");
1830275970Scy					else
1831275970Scy						{
1832275970Scy						if  (arg == DATA1)
1833275970Scy							printf ("1");
1834275970Scy						else
1835275970Scy							{
1836275970Scy							if  (arg == PI)
1837275970Scy								printf ("P");
1838275970Scy							else
1839275970Scy								printf ("?");
1840275970Scy							}
1841275970Scy						}
1842275970Scy					}
1843275970Scy				break;
1844275970Scy
1845275970Scy			case DATAX:		/* send data bit */
1846275970Scy				WWV_SecondNoTick(arg, RateCorrection);
1847275970Scy				if  (Verbose)
1848275970Scy					{
1849275970Scy					if  (arg == DATA0)
1850275970Scy						printf ("0");
1851275970Scy					else
1852275970Scy						{
1853275970Scy						if  (arg == DATA1)
1854275970Scy							printf ("1");
1855275970Scy						else
1856275970Scy							{
1857275970Scy							if  (arg == PI)
1858275970Scy								printf ("P");
1859275970Scy							else
1860275970Scy								printf ("?");
1861275970Scy							}
1862275970Scy						}
1863275970Scy					}
1864275970Scy				break;
1865275970Scy
1866275970Scy			case COEF:		/* send BCD bit */
1867275970Scy				if (code[ptr] & arg) {
1868275970Scy					WWV_Second(DATA1, RateCorrection);
1869275970Scy					if  (Verbose)
1870275970Scy					    printf("1");
1871275970Scy				} else {
1872275970Scy					WWV_Second(DATA0, RateCorrection);
1873275970Scy					if  (Verbose)
1874275970Scy					    printf("0");
1875275970Scy				}
1876275970Scy				break;
1877275970Scy
1878275970Scy			case LEAP:		/* send leap bit */
1879275970Scy				if (leap) {
1880275970Scy					WWV_Second(DATA1, RateCorrection);
1881275970Scy					if  (Verbose)
1882275970Scy					    printf("L");
1883275970Scy				} else {
1884275970Scy					WWV_Second(DATA0, RateCorrection);
1885275970Scy					if  (Verbose)
1886275970Scy					    printf("0");
1887275970Scy				}
1888275970Scy				break;
1889275970Scy
1890275970Scy			case DEC:		/* send data bit */
1891275970Scy				ptr--;
1892275970Scy				WWV_Second(arg, RateCorrection);
1893275970Scy				if  (Verbose)
1894275970Scy					{
1895275970Scy					if  (arg == DATA0)
1896275970Scy						printf ("0");
1897275970Scy					else
1898275970Scy						{
1899275970Scy						if  (arg == DATA1)
1900275970Scy							printf ("1");
1901275970Scy						else
1902275970Scy							{
1903275970Scy							if  (arg == PI)
1904275970Scy								printf ("P");
1905275970Scy							else
1906275970Scy								printf ("?");
1907275970Scy							}
1908275970Scy						}
1909275970Scy					}
1910275970Scy				break;
1911275970Scy
1912275970Scy			case DECX:		/* send data bit with no tick */
1913275970Scy				ptr--;
1914275970Scy				WWV_SecondNoTick(arg, RateCorrection);
1915275970Scy				if  (Verbose)
1916275970Scy					{
1917275970Scy					if  (arg == DATA0)
1918275970Scy						printf ("0");
1919275970Scy					else
1920275970Scy						{
1921275970Scy						if  (arg == DATA1)
1922275970Scy							printf ("1");
1923275970Scy						else
1924275970Scy							{
1925275970Scy							if  (arg == PI)
1926275970Scy								printf ("P");
1927275970Scy							else
1928275970Scy								printf ("?");
1929275970Scy							}
1930275970Scy						}
1931275970Scy					}
1932275970Scy				break;
1933275970Scy
1934275970Scy			case MIN:		/* send minute sync */
1935275970Scy				if  (Minute == 0)
1936275970Scy					{
1937275970Scy					peep(arg, HourTone, HIGH);
1938275970Scy
1939275970Scy					if  (RateCorrection < 0)
1940275970Scy						{
1941275970Scy						peep( 990 - arg, HourTone, OFF);
1942275970Scy						TotalCyclesRemoved += 10;
1943275970Scy
1944275970Scy						if  (Debug)
1945275970Scy							printf ("\n* Shorter Second: ");
1946275970Scy						}
1947275970Scy					else
1948275970Scy						{
1949275970Scy						if	(RateCorrection > 0)
1950275970Scy							{
1951275970Scy							peep(1010 - arg, HourTone, OFF);
1952275970Scy
1953275970Scy							TotalCyclesAdded += 10;
1954275970Scy
1955275970Scy							if  (Debug)
1956275970Scy								printf ("\n* Longer Second: ");
1957275970Scy							}
1958275970Scy						else
1959275970Scy							{
1960275970Scy							peep(1000 - arg, HourTone, OFF);
1961275970Scy							}
1962275970Scy						}
1963275970Scy
1964275970Scy					if  (Verbose)
1965275970Scy					    printf("H");
1966275970Scy					}
1967275970Scy				else
1968275970Scy					{
1969275970Scy					peep(arg, tone, HIGH);
1970275970Scy
1971275970Scy					if  (RateCorrection < 0)
1972275970Scy						{
1973275970Scy						peep( 990 - arg, tone, OFF);
1974275970Scy						TotalCyclesRemoved += 10;
1975275970Scy
1976275970Scy						if  (Debug)
1977275970Scy							printf ("\n* Shorter Second: ");
1978275970Scy						}
1979275970Scy					else
1980275970Scy						{
1981275970Scy						if	(RateCorrection > 0)
1982275970Scy							{
1983275970Scy							peep(1010 - arg, tone, OFF);
1984275970Scy
1985275970Scy							TotalCyclesAdded += 10;
1986275970Scy
1987275970Scy							if  (Debug)
1988275970Scy								printf ("\n* Longer Second: ");
1989275970Scy							}
1990275970Scy						else
1991275970Scy							{
1992275970Scy							peep(1000 - arg, tone, OFF);
1993275970Scy							}
1994275970Scy						}
1995275970Scy
1996275970Scy					if  (Verbose)
1997275970Scy					    printf("M");
1998275970Scy					}
1999275970Scy				break;
2000275970Scy
2001275970Scy			case DUT1:		/* send DUT1 bits */
2002275970Scy				if (dut1 & arg)
2003275970Scy					{
2004275970Scy					WWV_Second(DATA1, RateCorrection);
2005275970Scy					if  (Verbose)
2006275970Scy					    printf("1");
2007275970Scy					}
2008275970Scy				else
2009275970Scy					{
2010275970Scy					WWV_Second(DATA0, RateCorrection);
2011275970Scy					if  (Verbose)
2012275970Scy					    printf("0");
2013275970Scy					}
2014275970Scy				break;
2015275970Scy
2016275970Scy			case DST1:		/* send DST1 bit */
2017275970Scy				ptr--;
2018275970Scy				if (DstFlag)
2019275970Scy					{
2020275970Scy					WWV_Second(DATA1, RateCorrection);
2021275970Scy					if  (Verbose)
2022275970Scy					    printf("1");
2023275970Scy					}
2024275970Scy				else
2025275970Scy					{
2026275970Scy					WWV_Second(DATA0, RateCorrection);
2027275970Scy					if  (Verbose)
2028275970Scy					    printf("0");
2029275970Scy					}
2030275970Scy				break;
2031275970Scy
2032275970Scy			case DST2:		/* send DST2 bit */
2033275970Scy				if (DstFlag)
2034275970Scy					{
2035275970Scy					WWV_Second(DATA1, RateCorrection);
2036275970Scy					if  (Verbose)
2037275970Scy					    printf("1");
2038275970Scy					}
2039275970Scy				else
2040275970Scy					{
2041275970Scy					WWV_Second(DATA0, RateCorrection);
2042275970Scy					if  (Verbose)
2043275970Scy					    printf("0");
2044275970Scy					}
2045275970Scy				break;
2046275970Scy			}
2047275970Scy		}
2048275970Scy
2049275970Scy	if  (EnableRateCorrection)
2050275970Scy		{
2051275970Scy		SecondsRunningSimulationTime++;
2052275970Scy
2053275970Scy		gettimeofday(&TimeValue, NULL);
2054275970Scy		NowRealTime = TimeValue.tv_sec;
2055275970Scy
2056275970Scy		if  (NowRealTime >= BaseRealTime)		// Just in case system time corrects backwards, do not blow up.
2057275970Scy			{
2058275970Scy			SecondsRunningRealTime = (unsigned) (NowRealTime - BaseRealTime);
2059275970Scy			SecondsRunningDifference = SecondsRunningSimulationTime - SecondsRunningRealTime;
2060275970Scy
2061275970Scy			if  (Debug)
2062275970Scy				{
2063275970Scy				printf ("> NowRealTime = 0x%8.8X, BaseRealtime = 0x%8.8X, SecondsRunningRealTime = 0x%8.8X, SecondsRunningSimulationTime = 0x%8.8X.\n",
2064275970Scy							(unsigned) NowRealTime, (unsigned) BaseRealTime, SecondsRunningRealTime, SecondsRunningSimulationTime);
2065275970Scy				printf ("> SecondsRunningDifference = 0x%8.8X, ExpectedRunningDifference = 0x%8.8X.\n",
2066275970Scy							SecondsRunningDifference, ExpectedRunningDifference);
2067275970Scy				}
2068275970Scy
2069275970Scy			if  (SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK)
2070275970Scy				{
2071275970Scy				if  (StabilityCount < MINIMUM_STABILITY_COUNT)
2072275970Scy					{
2073275970Scy					if  (StabilityCount == 0)
2074275970Scy						{
2075275970Scy						ExpectedRunningDifference = SecondsRunningDifference;
2076275970Scy						StabilityCount++;
2077275970Scy						if  (Debug)
2078275970Scy							printf ("> Starting stability check.\n");
2079275970Scy						}
2080275970Scy					else
2081275970Scy						{	// Else for "if  (StabilityCount == 0)"
2082275970Scy						if  ((ExpectedRunningDifference+INITIAL_STABILITY_BAND > SecondsRunningDifference)
2083275970Scy								&& (ExpectedRunningDifference-INITIAL_STABILITY_BAND < SecondsRunningDifference))
2084275970Scy							{	// So far, still within stability band, increment count.
2085275970Scy							StabilityCount++;
2086275970Scy							if  (Debug)
2087275970Scy								printf ("> StabilityCount = %d.\n", StabilityCount);
2088275970Scy							}
2089275970Scy						else
2090275970Scy							{	// Outside of stability band, start over.
2091275970Scy							StabilityCount = 0;
2092275970Scy							if  (Debug)
2093275970Scy								printf ("> Out of stability band, start over.\n");
2094275970Scy							}
2095275970Scy						} // End of else for "if  (StabilityCount == 0)"
2096275970Scy					}	// End of true clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))"
2097275970Scy				else
2098275970Scy					{	// Else clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))" - OK, so we are supposed to be stable.
2099275970Scy					if  (AddCycle)
2100275970Scy						{
2101275970Scy						if  (ExpectedRunningDifference >= SecondsRunningDifference)
2102275970Scy							{
2103275970Scy							if  (Debug)
2104275970Scy								printf ("> Was adding cycles, ExpectedRunningDifference >= SecondsRunningDifference, can stop it now.\n");
2105275970Scy
2106275970Scy							AddCycle = FALSE;
2107275970Scy							RemoveCycle = FALSE;
2108275970Scy							}
2109275970Scy						else
2110275970Scy							{
2111275970Scy							if  (Debug)
2112275970Scy								printf ("> Was adding cycles, not done yet.\n");
2113275970Scy							}
2114275970Scy						}
2115275970Scy					else
2116275970Scy						{
2117275970Scy						if  (RemoveCycle)
2118275970Scy							{
2119275970Scy							if  (ExpectedRunningDifference <= SecondsRunningDifference)
2120275970Scy								{
2121275970Scy								if  (Debug)
2122275970Scy									printf ("> Was removing cycles, ExpectedRunningDifference <= SecondsRunningDifference, can stop it now.\n");
2123275970Scy
2124275970Scy								AddCycle = FALSE;
2125275970Scy								RemoveCycle = FALSE;
2126275970Scy								}
2127275970Scy							else
2128275970Scy								{
2129275970Scy								if  (Debug)
2130275970Scy									printf ("> Was removing cycles, not done yet.\n");
2131275970Scy								}
2132275970Scy							}
2133275970Scy						else
2134275970Scy							{
2135275970Scy							if  ((ExpectedRunningDifference+RUNNING_STABILITY_BAND > SecondsRunningDifference)
2136275970Scy									&& (ExpectedRunningDifference-RUNNING_STABILITY_BAND < SecondsRunningDifference))
2137275970Scy								{	// All is well, within tolerances.
2138275970Scy								if  (Debug)
2139275970Scy									printf ("> All is well, within tolerances.\n");
2140275970Scy								}
2141275970Scy							else
2142275970Scy								{	// Oops, outside tolerances.  Else clause of "if  ((ExpectedRunningDifference...SecondsRunningDifference)"
2143275970Scy								if  (ExpectedRunningDifference > SecondsRunningDifference)
2144275970Scy									{
2145275970Scy									if  (Debug)
2146275970Scy										printf ("> ExpectedRunningDifference > SecondsRunningDifference, running behind real time.\n");
2147275970Scy
2148275970Scy									// Behind real time, have to add a cycle to slow down and get back in sync.
2149275970Scy									AddCycle = FALSE;
2150275970Scy									RemoveCycle = TRUE;
2151275970Scy									}
2152275970Scy								else
2153275970Scy									{	// Else clause of "if  (ExpectedRunningDifference < SecondsRunningDifference)"
2154275970Scy									if  (ExpectedRunningDifference < SecondsRunningDifference)
2155275970Scy										{
2156275970Scy										if  (Debug)
2157275970Scy											printf ("> ExpectedRunningDifference < SecondsRunningDifference, running ahead of real time.\n");
2158275970Scy
2159275970Scy										// Ahead of real time, have to remove a cycle to speed up and get back in sync.
2160275970Scy										AddCycle = TRUE;
2161275970Scy										RemoveCycle = FALSE;
2162275970Scy										}
2163275970Scy									else
2164275970Scy										{
2165275970Scy										if  (Debug)
2166275970Scy											printf ("> Oops, outside tolerances, but doesn't fit the profiles, how can this be?\n");
2167275970Scy										}
2168275970Scy									}	// End of else clause of "if  (ExpectedRunningDifference > SecondsRunningDifference)"
2169275970Scy								}	// End of else clause of "if  ((ExpectedRunningDifference...SecondsRunningDifference)"
2170275970Scy							}	// End of else clause of "if  (RemoveCycle)".
2171275970Scy						}	// End of else clause of "if  (AddCycle)".
2172275970Scy					}	// End of else clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))"
2173275970Scy				}	// End of true clause for "if  ((SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK)"
2174275970Scy			}	// End of true clause for "if  (NowRealTime >= BaseRealTime)"
2175275970Scy		else
2176275970Scy			{
2177275970Scy			if  (Debug)
2178275970Scy				printf ("> Hmm, time going backwards?\n");
2179275970Scy			}
2180275970Scy		}	// End of true clause for "if  (EnableRateCorrection)"
2181275970Scy
2182275970Scy	fflush (stdout);
2183275970Scy	}
2184275970Scy
2185275970Scy
2186275970Scyprintf ("\n\n>> Completed %d seconds, exiting...\n\n", SecondsToSend);
2187275970Scyreturn (0);
2188275970Scy}
2189275970Scy
2190275970Scy
2191275970Scy/*
2192275970Scy * Generate WWV/H 0 or 1 data pulse.
2193275970Scy */
2194275970Scyvoid WWV_Second(
2195275970Scy	int	code,		/* DATA0, DATA1, PI */
2196275970Scy	int Rate		/* <0 -> do a short second, 0 -> normal second, >0 -> long second */
2197275970Scy	)
2198275970Scy{
2199275970Scy	/*
2200275970Scy	 * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
2201275970Scy	 * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
2202275970Scy	 * 100 Hz corresponding to 0, 1 or position indicator (PI),
2203275970Scy	 * respectively. Note the 100-Hz data pulses are transmitted 6
2204275970Scy	 * dB below the 1000-Hz sync pulses. Originally the data pulses
2205275970Scy	 * were transmited 10 dB below the sync pulses, but the station
2206275970Scy	 * engineers increased that to 6 dB because the Heath GC-1000
2207275970Scy	 * WWV/H radio clock worked much better.
2208275970Scy	 */
2209275970Scy	peep(5, tone, HIGH);		/* send seconds tick */
2210275970Scy	peep(25, tone, OFF);
2211275970Scy	peep(code - 30, 100, LOW);	/* send data */
2212275970Scy
2213275970Scy	/* The quiet time is shortened or lengthened to get us back on time */
2214275970Scy	if  (Rate < 0)
2215275970Scy		{
2216275970Scy		peep( 990 - code, 100, OFF);
2217275970Scy
2218275970Scy		TotalCyclesRemoved += 10;
2219275970Scy
2220275970Scy		if  (Debug)
2221275970Scy			printf ("\n* Shorter Second: ");
2222275970Scy		}
2223275970Scy	else
2224275970Scy		{
2225275970Scy		if  (Rate > 0)
2226275970Scy			{
2227275970Scy			peep(1010 - code, 100, OFF);
2228275970Scy
2229275970Scy			TotalCyclesAdded += 10;
2230275970Scy
2231275970Scy			if  (Debug)
2232275970Scy				printf ("\n* Longer Second: ");
2233275970Scy			}
2234275970Scy		else
2235275970Scy			peep(1000 - code, 100, OFF);
2236275970Scy		}
2237275970Scy}
2238275970Scy
2239275970Scy/*
2240275970Scy * Generate WWV/H 0 or 1 data pulse, with no tick, for 29th and 59th seconds
2241275970Scy */
2242275970Scyvoid WWV_SecondNoTick(
2243275970Scy	int	code,		/* DATA0, DATA1, PI */
2244275970Scy	int Rate		/* <0 -> do a short second, 0 -> normal second, >0 -> long second */
2245275970Scy	)
2246275970Scy{
2247275970Scy	/*
2248275970Scy	 * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
2249275970Scy	 * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
2250275970Scy	 * 100 Hz corresponding to 0, 1 or position indicator (PI),
2251275970Scy	 * respectively. Note the 100-Hz data pulses are transmitted 6
2252275970Scy	 * dB below the 1000-Hz sync pulses. Originally the data pulses
2253275970Scy	 * were transmited 10 dB below the sync pulses, but the station
2254275970Scy	 * engineers increased that to 6 dB because the Heath GC-1000
2255275970Scy	 * WWV/H radio clock worked much better.
2256275970Scy	 */
2257275970Scy	peep(30, tone, OFF);		/* send seconds non-tick */
2258275970Scy	peep(code - 30, 100, LOW);	/* send data */
2259275970Scy
2260275970Scy	/* The quiet time is shortened or lengthened to get us back on time */
2261275970Scy	if  (Rate < 0)
2262275970Scy		{
2263275970Scy		peep( 990 - code, 100, OFF);
2264275970Scy
2265275970Scy		TotalCyclesRemoved += 10;
2266275970Scy
2267275970Scy		if  (Debug)
2268275970Scy			printf ("\n* Shorter Second: ");
2269275970Scy		}
2270275970Scy	else
2271275970Scy		{
2272275970Scy		if  (Rate > 0)
2273275970Scy			{
2274275970Scy			peep(1010 - code, 100, OFF);
2275275970Scy
2276275970Scy			TotalCyclesAdded += 10;
2277275970Scy
2278275970Scy			if  (Debug)
2279275970Scy				printf ("\n* Longer Second: ");
2280275970Scy			}
2281275970Scy		else
2282275970Scy			peep(1000 - code, 100, OFF);
2283275970Scy		}
2284275970Scy}
2285275970Scy
2286275970Scy/*
2287275970Scy * Generate cycles of 100 Hz or any multiple of 100 Hz.
2288275970Scy */
2289275970Scyvoid peep(
2290275970Scy	int	pulse,		/* pulse length (ms) */
2291275970Scy	int	freq,		/* frequency (Hz) */
2292275970Scy	int	amp		/* amplitude */
2293275970Scy	)
2294275970Scy{
2295275970Scy	int	increm;		/* phase increment */
2296275970Scy	int	i, j;
2297275970Scy
2298275970Scy	if (amp == OFF || freq == 0)
2299275970Scy		increm = 10;
2300275970Scy	else
2301275970Scy		increm = freq / 100;
2302275970Scy	j = 0;
2303275970Scy	for (i = 0 ; i < pulse * 8; i++) {
2304275970Scy		switch (amp) {
2305275970Scy
2306275970Scy		case HIGH:
2307275970Scy			buffer[bufcnt++] = ~c6000[j];
2308275970Scy			break;
2309275970Scy
2310275970Scy		case LOW:
2311275970Scy			buffer[bufcnt++] = ~c3000[j];
2312275970Scy			break;
2313275970Scy
2314275970Scy		default:
2315275970Scy			buffer[bufcnt++] = ~0;
2316275970Scy		}
2317275970Scy		if (bufcnt >= BUFLNG) {
2318275970Scy			write(fd, buffer, BUFLNG);
2319275970Scy			bufcnt = 0;
2320275970Scy		}
2321275970Scy		j = (j + increm) % 80;
2322275970Scy	}
2323275970Scy}
2324275970Scy
2325275970Scy
2326275970Scy/*
2327275970Scy * Generate unmodulated from similar tables.
2328275970Scy */
2329275970Scyvoid poop(
2330275970Scy	int	pulse,		/* pulse length (ms) */
2331275970Scy	int	freq,		/* frequency (Hz) */
2332275970Scy	int	amp,		/* amplitude */
2333275970Scy	int inverted	/* is upside down */
2334275970Scy	)
2335275970Scy{
2336275970Scy	int	increm;		/* phase increment */
2337275970Scy	int	i, j;
2338275970Scy
2339275970Scy	if (amp == OFF || freq == 0)
2340275970Scy		increm = 10;
2341275970Scy	else
2342275970Scy		increm = freq / 100;
2343275970Scy	j = 0;
2344275970Scy	for (i = 0 ; i < pulse * 8; i++) {
2345275970Scy		switch (amp) {
2346275970Scy
2347275970Scy		case HIGH:
2348275970Scy			if  (inverted)
2349275970Scy				buffer[bufcnt++] = ~u3000[j];
2350275970Scy			else
2351275970Scy				buffer[bufcnt++] = ~u6000[j];
2352275970Scy			break;
2353275970Scy
2354275970Scy		case LOW:
2355275970Scy			if  (inverted)
2356275970Scy				buffer[bufcnt++] = ~u6000[j];
2357275970Scy			else
2358275970Scy				buffer[bufcnt++] = ~u3000[j];
2359275970Scy			break;
2360275970Scy
2361275970Scy		default:
2362275970Scy			buffer[bufcnt++] = ~0;
2363275970Scy		}
2364275970Scy		if (bufcnt >= BUFLNG) {
2365275970Scy			write(fd, buffer, BUFLNG);
2366275970Scy			bufcnt = 0;
2367275970Scy		}
2368275970Scy		j = (j + increm) % 80;
2369275970Scy	}
2370275970Scy}
2371275970Scy
2372275970Scy/*
2373275970Scy * Delay for initial phasing
2374275970Scy */
2375275970Scyvoid delay (
2376275970Scy	int	Delay		/* delay in samples */
2377275970Scy	)
2378275970Scy{
2379275970Scy	int	samples;	/* samples remaining */
2380275970Scy
2381275970Scy	samples = Delay;
2382275970Scy	memset(buffer, 0, BUFLNG);
2383275970Scy	while (samples >= BUFLNG) {
2384275970Scy		write(fd, buffer, BUFLNG);
2385275970Scy		samples -= BUFLNG;
2386275970Scy	}
2387275970Scy		write(fd, buffer, samples);
2388275970Scy}
2389275970Scy
2390275970Scy
2391275970Scy/* Calc day of year from year month & day */
2392275970Scy/* Year - 0 means 2000, 100 means 2100. */
2393275970Scy/* Month - 1 means January, 12 means December. */
2394275970Scy/* DayOfMonth - 1 is first day of month */
2395275970Scyint
2396275970ScyConvertMonthDayToDayOfYear (int YearValue, int MonthValue, int DayOfMonthValue)
2397275970Scy	{
2398275970Scy	int	ReturnValue;
2399275970Scy	int	LeapYear;
2400275970Scy	int	MonthCounter;
2401275970Scy
2402275970Scy	/* Array of days in a month.  Note that here January is zero. */
2403275970Scy	/* NB: have to add 1 to days in February in a leap year! */
2404275970Scy	int DaysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
2405275970Scy
2406275970Scy
2407275970Scy	LeapYear = FALSE;
2408275970Scy	if  ((YearValue % 4) == 0)
2409275970Scy		{
2410275970Scy		if  ((YearValue % 100) == 0)
2411275970Scy			{
2412275970Scy			if  ((YearValue % 400) == 0)
2413275970Scy				{
2414275970Scy				LeapYear = TRUE;
2415275970Scy				}
2416275970Scy			}
2417275970Scy		else
2418275970Scy			{
2419275970Scy			LeapYear = TRUE;
2420275970Scy			}
2421275970Scy		}
2422275970Scy
2423275970Scy	if  (Debug)
2424275970Scy		printf ("\nConvertMonthDayToDayOfYear(): Year %d %s a leap year.\n", YearValue+2000, LeapYear ? "is" : "is not");
2425275970Scy
2426275970Scy	/* Day of month given us starts in this algorithm. */
2427275970Scy	ReturnValue = DayOfMonthValue;
2428275970Scy
2429275970Scy	/* Add in days in month for each month past January. */
2430275970Scy	for (MonthCounter=1; MonthCounter<MonthValue; MonthCounter++)
2431275970Scy		{
2432275970Scy		ReturnValue += DaysInMonth [ MonthCounter - 1 ];
2433275970Scy		}
2434275970Scy
2435275970Scy	/* Add a day for leap years where we are past February. */
2436275970Scy	if  ((LeapYear) && (MonthValue > 2))
2437275970Scy		{
2438275970Scy		ReturnValue++;
2439275970Scy		}
2440275970Scy
2441275970Scy	if  (Debug)
2442275970Scy		printf ("\nConvertMonthDayToDayOfYear(): %4.4d-%2.2d-%2.2d represents day %3d of year.\n",
2443275970Scy				YearValue+2000, MonthValue, DayOfMonthValue, ReturnValue);
2444275970Scy
2445275970Scy	return (ReturnValue);
2446275970Scy	}
2447275970Scy
2448275970Scy
2449275970Scyvoid
2450275970ScyHelp ( void )
2451275970Scy	{
2452275970Scy	printf ("\n\nTime Code Generation - IRIG-B or WWV, v%d.%d, %s dmw", VERSION, ISSUE, ISSUE_DATE);
2453275970Scy	printf ("\n\nRCS Info:");
2454275970Scy	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 $");
2455275970Scy	printf ("\n\nUsage: %s [option]*", CommandName);
2456275970Scy	printf ("\n\nOptions: -a device_name                 Output audio device name (default /dev/audio)");
2457275970Scy	printf (  "\n         -b yymmddhhmm                  Remove leap second at end of minute specified");
2458275970Scy	printf (  "\n         -c seconds_to_send             Number of seconds to send (default 0 = forever)");
2459275970Scy	printf (  "\n         -d                             Start with IEEE 1344 DST active");
2460275970Scy	printf (  "\n         -f format_type                 i = Modulated IRIG-B 1998 (no year coded)");
2461275970Scy	printf (  "\n                                        2 = Modulated IRIG-B 2002 (year coded)");
2462275970Scy	printf (  "\n                                        3 = Modulated IRIG-B w/IEEE 1344 (year & control funcs) (default)");
2463275970Scy	printf (  "\n                                        4 = Unmodulated IRIG-B w/IEEE 1344 (year & control funcs)");
2464275970Scy	printf (  "\n                                        5 = Inverted unmodulated IRIG-B w/IEEE 1344 (year & control funcs)");
2465275970Scy	printf (  "\n                                        w = WWV(H)");
2466275970Scy	printf (  "\n         -g yymmddhhmm                  Switch into/out of DST at beginning of minute specified");
2467275970Scy	printf (  "\n         -i yymmddhhmm                  Insert leap second at end of minute specified");
2468275970Scy	printf (  "\n         -j                             Disable time rate correction against system clock (default enabled)");
2469275970Scy	printf (  "\n         -k nn                          Force rate correction for testing (+1 = add cycle, -1 = remove cycle)");
2470275970Scy	printf (  "\n         -l time_offset                 Set offset of time sent to UTC as per computer, +/- float hours");
2471275970Scy	printf (  "\n         -o time_offset                 Set IEEE 1344 time offset, +/-, to 0.5 hour (default 0)");
2472275970Scy	printf (  "\n         -q quality_code_hex            Set IEEE 1344 quality code (default 0)");
2473275970Scy	printf (  "\n         -r sample_rate                 Audio sample rate (default 8000)");
2474275970Scy	printf (  "\n         -s                             Set leap warning bit (WWV[H] only)");
2475275970Scy	printf (  "\n         -t sync_frequency              WWV(H) on-time pulse tone frequency (default 1200)");
2476275970Scy	printf (  "\n         -u DUT1_offset                 Set WWV(H) DUT1 offset -7 to +7 (default 0)");
2477275970Scy#ifndef  HAVE_SYS_SOUNDCARD_H
2478275970Scy	printf (  "\n         -v initial_output_level        Set initial output level (default %d, must be 0 to 255)", AUDIO_MAX_GAIN/8);
2479275970Scy#endif
2480275970Scy	printf (  "\n         -x                             Turn off verbose output (default on)");
2481275970Scy	printf (  "\n         -y yymmddhhmmss                Set initial date and time as specified (default system time)");
2482275970Scy	printf ("\n\nThis software licenced under the GPL, modifications performed 2006 & 2007 by Dean Weiten");
2483275970Scy	printf (  "\nContact: Dean Weiten, Norscan Instruments Ltd., Winnipeg, MB, Canada, ph (204)-233-9138, E-mail dmw@norscan.com");
2484275970Scy	printf ("\n\n");
2485275970Scy	}
2486275970Scy
2487275970Scy/* Reverse string order for nicer print. */
2488275970Scyvoid
2489275970ScyReverseString(char *str)
2490275970Scy	{
2491275970Scy	int		StringLength;
2492275970Scy	int		IndexCounter;
2493275970Scy	int		CentreOfString;
2494275970Scy	char	TemporaryCharacter;
2495275970Scy
2496275970Scy
2497275970Scy	StringLength	= strlen(str);
2498275970Scy	CentreOfString	= (StringLength/2)+1;
2499275970Scy	for (IndexCounter = StringLength; IndexCounter >= CentreOfString; IndexCounter--)
2500275970Scy		{
2501275970Scy		TemporaryCharacter				= str[IndexCounter-1];
2502275970Scy		str[IndexCounter-1]				= str[StringLength-IndexCounter];
2503275970Scy		str[StringLength-IndexCounter]	= TemporaryCharacter;
2504275970Scy		}
2505275970Scy	}
2506275970Scy
2507