tg2.c   [plain text]


/*
 * tg.c generate WWV or IRIG signals for test
 */
/*
 * This program can generate audio signals that simulate the WWV/H
 * broadcast timecode. Alternatively, it can generate the IRIG-B
 * timecode commonly used to synchronize laboratory equipment. It is
 * intended to test the WWV/H driver (refclock_wwv.c) and the IRIG
 * driver (refclock_irig.c) in the NTP driver collection.
 *
 * Besides testing the drivers themselves, this program can be used to
 * synchronize remote machines over audio transmission lines or program
 * feeds. The program reads the time on the local machine and sets the
 * initial epoch of the signal generator within one millisecond.
 * Alernatively, the initial epoch can be set to an arbitrary time. This
 * is useful when searching for bugs and testing for correct response to
 * a leap second in UTC. Note however, the ultimate accuracy is limited
 * by the intrinsic frequency error of the codec sample clock, which can
 # reach well over 100 PPM.
 *
 * The default is to route generated signals to the line output
 * jack; the s option on the command line routes these signals to the
 * internal speaker as well. The v option controls the speaker volume
 * over the range 0-255. The signal generator by default uses WWV
 * format; the h option switches to WWVH format and the i option
 * switches to IRIG-B format.
 *
 * Once started the program runs continuously. The default initial epoch
 * for the signal generator is read from the computer system clock when
 * the program starts. The y option specifies an alternate epoch using a
 * string yydddhhmmss, where yy is the year of century, ddd the day of
 * year, hh the hour of day and mm the minute of hour. For instance,
 * 1946Z on 1 January 2006 is 060011946. The l option lights the leap
 * warning bit in the WWV/H timecode, so is handy to check for correct
 * behavior at the next leap second epoch. The remaining options are
 * specified below under the Parse Options heading. Most of these are
 * for testing.
 *
 * During operation the program displays the WWV/H timecode (9 digits)
 * or IRIG timecode (20 digits) as each new string is constructed. The
 * display is followed by the BCD binary bits as transmitted. Note that
 * the transmissionorder is low-order first as the frame is processed
 * left to right. For WWV/H The leap warning L preceeds the first bit.
 * For IRIG the on-time marker M preceeds the first (units) bit, so its
 * code is delayed one bit and the next digit (tens) needs only three
 * bits.
 *
 * The program has been tested with the Sun Blade 1500 running Solaris
 * 10, but not yet with other machines. It uses no special features and
 * should be readily portable to other hardware and operating systems.
 *
 * $Log: tg.c,v $
 * Revision 1.28  2007/02/12 23:57:45  dmw
 * v0.23 2007-02-12 dmw:
 * - Changed statistics to include calculated error
 *   of frequency, based on number of added or removed
 *   cycles over time.
 *
 * Revision 1.27  2007/02/09 02:28:59  dmw
 * v0.22 2007-02-08 dmw:
 * - Changed default for rate correction to "enabled", "-j" switch now disables.
 * - Adjusted help message accordingly.
 * - Added "2007" to modifications note at end of help message.
 *
 * Revision 1.26  2007/02/08 03:36:17  dmw
 * v0.21 2007-02-07 dmw:
 * - adjusted strings for shorten and lengthen to make
 *   fit on smaller screen.
 *
 * Revision 1.25  2007/02/01 06:08:09  dmw
 * v0.20 2007-02-01 dmw:
 * - Added periodic display of running time along with legend on IRIG-B, allows tracking how
 *   close IRIG output is to actual clock time.
 *
 * Revision 1.24  2007/01/31 19:24:11  dmw
 * v0.19 2007-01-31 dmw:
 * - Added tracking of how many seconds have been adjusted,
 *   how many cycles added (actually in milliseconds), how
 *   many cycles removed, print periodically if verbose is
 *   active.
 * - Corrected lack of lengthen or shorten of minute & hour
 *   pulses for WWV format.
 *
 * Revision 1.23  2007/01/13 07:09:12  dmw
 * v0.18 2007-01-13 dmw:
 * - added -k option, which allows force of long or short
 *   cycles, to test against IRIG-B decoder.
 *
 * Revision 1.22  2007/01/08 16:27:23  dmw
 * v0.17 2007-01-08 dmw:
 * - Changed -j option to **enable** rate correction, not disable.
 *
 * Revision 1.21  2007/01/08 06:22:36  dmw
 * v0.17 2007-01-08 dmw:
 * - Run stability check versus ongoing system clock (assume NTP correction)
 *   and adjust time code rate to try to correct, if gets too far out of sync.
 *   Disable this algorithm with -j option.
 *
 * Revision 1.20  2006/12/19 04:59:04  dmw
 * v0.16 2006-12-18 dmw
 * - Corrected print of setting of output frequency, always
 *   showed 8000 samples/sec, now as specified on command line.
 * - Modified to reflect new employer Norscan.
 *
 * Revision 1.19  2006/12/19 03:45:38  dmw
 * v0.15 2006-12-18 dmw:
 * - Added count of number of seconds to output then exit,
 *   default zero for forever.
 *
 * Revision 1.18  2006/12/18 05:43:36  dmw
 * v0.14 2006-12-17 dmw:
 * - Corrected WWV(H) signal to leave "tick" sound off of 29th and 59th second of minute.
 * - Adjusted verbose output format for WWV(H).
 *
 * Revision 1.17  2006/12/18 02:31:33  dmw
 * v0.13 2006-12-17 dmw:
 * - Put SPARC code back in, hopefully will work, but I don't have
 *   a SPARC to try it on...
 * - Reworked Verbose mode, different flag to initiate (x not v)
 *   and actually implement turn off of verbosity when this flag used.
 * - Re-claimed v flag for output level.
 * - Note that you must define OSS_MODS to get OSS to compile,
 *   otherwise will expect to compile using old SPARC options, as
 *   it used to be.
 *
 * Revision 1.16  2006/10/26 19:08:43  dmw
 * v0.12 2006-10-26 dmw:
 * - Reversed output binary dump for IRIG, makes it easier to read the numbers.
 *
 * Revision 1.15  2006/10/24 15:57:09  dmw
 * v0.11 2006-10-24 dmw:
 * - another tweak.
 *
 * Revision 1.14  2006/10/24 15:55:53  dmw
 * v0.11 2006-10-24 dmw:
 * - Curses a fix to the fix to the fix of the usaeg.
 *
 * Revision 1.13  2006/10/24 15:53:25  dmw
 * v0.11 (still) 2006-10-24 dmw:
 * - Messed with usage message that's all.
 *
 * Revision 1.12  2006/10/24 15:50:05  dmw
 * v0.11 2006-10-24 dmw:
 * - oops, needed to note "hours" in usage of that offset.
 *
 * Revision 1.11  2006/10/24 15:49:09  dmw
 * v0.11 2006-10-24 dmw:
 * - Added ability to offset actual time sent, from the UTC time
 *   as per the computer.
 *
 * Revision 1.10  2006/10/24 03:25:55  dmw
 * v0.10 2006-10-23 dmw:
 * - Corrected polarity of correction of offset when going into or out of DST.
 * - Ensure that zero offset is always positive (pet peeve).
 *
 * Revision 1.9  2006/10/24 00:00:35  dmw
 * v0.9 2006-10-23 dmw:
 * - Shift time offset when DST in or out.
 *
 * Revision 1.8  2006/10/23 23:49:28  dmw
 * v0.8 2006-10-23 dmw:
 * - made offset of zero default positive.
 *
 * Revision 1.7  2006/10/23 23:44:13  dmw
 * v0.7 2006-10-23 dmw:
 * - Added unmodulated and inverted unmodulated output.
 *
 * Revision 1.6  2006/10/23 18:10:37  dmw
 * v0.6 2006-10-23 dmw:
 * - Cleaned up usage message.
 * - Require at least one option, or prints usage message and exits.
 *
 * Revision 1.5  2006/10/23 16:58:10  dmw
 * v0.5 2006-10-23 dmw:
 * - Finally added a usage message.
 * - Added leap second pending and DST change pending into IEEE 1344.
 * - Default code type is now IRIG-B with IEEE 1344.
 *
 * Revision 1.4  2006/10/23 03:27:25  dmw
 * v0.4 2006-10-22 dmw:
 * - Added leap second addition and deletion.
 * - Added DST changing forward and backward.
 * - Changed date specification to more conventional year, month, and day of month
 *   (rather than day of year).
 *
 * Revision 1.3  2006/10/22 21:04:12  dmw
 * v0.2 2006-10-22 dmw:
 * - Corrected format of legend line.
 *
 * Revision 1.2  2006/10/22 21:01:07  dmw
 * v0.1 2006-10-22 dmw:
 * - Added some more verbose output (as is my style)
 * - Corrected frame format - there were markers in the
 *   middle of frames, now correctly as "zero" bits.
 * - Added header line to show fields of output.
 * - Added straight binary seconds, were not implemented
 *   before.
 * - Added IEEE 1344 with parity.
 *
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef  HAVE_CONFIG_H
#include "config.h"
#undef VERSION		/* avoid conflict below */
#endif

#ifdef  HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h>
#else
# ifdef HAVE_SYS_AUDIOIO_H
# include <sys/audioio.h>
# else
# include <sys/audio.h>
# endif
#endif

#include "ntp_stdlib.h"	/* for strlcat(), strlcpy() */

#include <math.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#define VERSION		(0)
#define	ISSUE		(23)
#define	ISSUE_DATE	"2007-02-12"

#define	SECOND	(8000)			/* one second of 125-us samples */
#define BUFLNG	(400)			/* buffer size */
#define	DEVICE	"/dev/audio"	/* default audio device */
#define	WWV		(0)				/* WWV encoder */
#define	IRIG	(1)				/* IRIG-B encoder */
#define	OFF		(0)				/* zero amplitude */
#define	LOW		(1)				/* low amplitude */
#define	HIGH	(2)				/* high amplitude */
#define	DATA0	(200)			/* WWV/H 0 pulse */
#define	DATA1	(500)			/* WWV/H 1 pulse */
#define PI		(800)			/* WWV/H PI pulse */
#define	M2		(2)				/* IRIG 0 pulse */
#define	M5		(5)				/* IRIG 1 pulse */
#define	M8		(8)				/* IRIG PI pulse */

#define	NUL		(0)

#define	SECONDS_PER_MINUTE	(60)
#define SECONDS_PER_HOUR	(3600)

#define	OUTPUT_DATA_STRING_LENGTH	(200)

/* Attempt at unmodulated - "high" */
int u6000[] = {
	247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/*  0- 9 */
    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 10-19 */
    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 20-29 */
    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 30-39 */
    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 40-49 */
    247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 	/* 50-59 */
    247, 247, 247, 247, 247, 247, 247, 247, 247, 247,	/* 60-69 */
    247, 247, 247, 247, 247, 247, 247, 247, 247, 247}; 	/* 70-79 */

/* Attempt at unmodulated - "low" */
int u3000[] = {
	119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/*  0- 9 */
    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 10-19 */
    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 20-29 */
    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 30-39 */
    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 40-49 */
    119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 	/* 50-59 */
    119, 119, 119, 119, 119, 119, 119, 119, 119, 119,	/* 60-69 */
    119, 119, 119, 119, 119, 119, 119, 119, 119, 119}; 	/* 70-79 */

/*
 * Companded sine table amplitude 3000 units
 */
int c3000[] = {1, 48, 63, 70, 78, 82, 85, 89, 92, 94,	/* 0-9 */
     96,  98,  99, 100, 101, 101, 102, 103, 103, 103,	/* 10-19 */
    103, 103, 103, 103, 102, 101, 101, 100,  99,  98,	/* 20-29 */
     96,  94,  92,  89,  85,  82,  78,  70,  63,  48,	/* 30-39 */
    129, 176, 191, 198, 206, 210, 213, 217, 220, 222,	/* 40-49 */
    224, 226, 227, 228, 229, 229, 230, 231, 231, 231, 	/* 50-59 */
    231, 231, 231, 231, 230, 229, 229, 228, 227, 226,	/* 60-69 */
    224, 222, 220, 217, 213, 210, 206, 198, 191, 176}; 	/* 70-79 */
/*
 * Companded sine table amplitude 6000 units
 */
int c6000[] = {1, 63, 78, 86, 93, 98, 101, 104, 107, 110, /* 0-9 */
    112, 113, 115, 116, 117, 117, 118, 118, 119, 119,	/* 10-19 */
    119, 119, 119, 118, 118, 117, 117, 116, 115, 113,	/* 20-29 */
    112, 110, 107, 104, 101,  98,  93,  86,  78,  63,	/* 30-39 */
    129, 191, 206, 214, 221, 226, 229, 232, 235, 238,	/* 40-49 */
    240, 241, 243, 244, 245, 245, 246, 246, 247, 247, 	/* 50-59 */
    247, 247, 247, 246, 246, 245, 245, 244, 243, 241,	/* 60-69 */
    240, 238, 235, 232, 229, 226, 221, 214, 206, 191}; 	/* 70-79 */

/*
 * Decoder operations at the end of each second are driven by a state
 * machine. The transition matrix consists of a dispatch table indexed
 * by second number. Each entry in the table contains a case switch
 * number and argument.
 */
struct progx {
	int sw;			/* case switch number */
	int arg;		/* argument */
};

/*
 * Case switch numbers
 */
#define DATA	(0)		/* send data (0, 1, PI) */
#define COEF	(1)		/* send BCD bit */
#define	DEC		(2)		/* decrement to next digit and send PI */
#define	MIN		(3)		/* minute pulse */
#define	LEAP	(4)		/* leap warning */
#define	DUT1	(5)		/* DUT1 bits */
#define	DST1	(6)		/* DST1 bit */
#define	DST2	(7)		/* DST2 bit */
#define DECZ	(8)		/* decrement to next digit and send zero */
#define DECC	(9)		/* decrement to next digit and send bit */
#define NODEC	(10)	/* no decerement to next digit, send PI */
#define DECX	(11)	/* decrement to next digit, send PI, but no tick */
#define DATAX	(12)	/* send data (0, 1, PI), but no tick */

/*
 * WWV/H format (100-Hz, 9 digits, 1 m frame)
 */
struct progx progx[] = {
	{MIN,	800},		/* 0 minute sync pulse */
	{DATA,	DATA0},		/* 1 */
	{DST2,	0},		/* 2 DST2 */
	{LEAP,	0},		/* 3 leap warning */
	{COEF,	1},		/* 4 1 year units */
	{COEF,	2},		/* 5 2 */
	{COEF,	4},		/* 6 4 */
	{COEF,	8},		/* 7 8 */
	{DEC,	DATA0},		/* 8 */
	{DATA,	PI},		/* 9 p1 */
	{COEF,	1},		/* 10 1 minute units */
	{COEF,	2},		/* 11 2 */
	{COEF,	4},		/* 12 4 */
	{COEF,	8},		/* 13 8 */
	{DEC,	DATA0},		/* 14 */
	{COEF,	1},		/* 15 10 minute tens */
	{COEF,	2},		/* 16 20 */
	{COEF,	4},		/* 17 40 */
	{COEF,	8},		/* 18 80 (not used) */
	{DEC,	PI},		/* 19 p2 */
	{COEF,	1},		/* 20 1 hour units */
	{COEF,	2},		/* 21 2 */
	{COEF,	4},		/* 22 4 */
	{COEF,	8},		/* 23 8 */
	{DEC,	DATA0},		/* 24 */
	{COEF,	1},		/* 25 10 hour tens */
	{COEF,	2},		/* 26 20 */
	{COEF,	4},		/* 27 40 (not used) */
	{COEF,	8},		/* 28 80 (not used) */
	{DECX,	PI},		/* 29 p3 */
	{COEF,	1},		/* 30 1 day units */
	{COEF,	2},		/* 31 2 */
	{COEF,	4},		/* 32 4 */
	{COEF,	8},		/* 33 8 */
	{DEC,	DATA0},		/* 34 not used */
	{COEF,	1},		/* 35 10 day tens */
	{COEF,	2},		/* 36 20 */
	{COEF,	4},		/* 37 40 */
	{COEF,	8},		/* 38 80 */
	{DEC,	PI},		/* 39 p4 */
	{COEF,	1},		/* 40 100 day hundreds */
	{COEF,	2},		/* 41 200 */
	{COEF,	4},		/* 42 400 (not used) */
	{COEF,	8},		/* 43 800 (not used) */
	{DEC,	DATA0},		/* 44 */
	{DATA,	DATA0},		/* 45 */
	{DATA,	DATA0},		/* 46 */
	{DATA,	DATA0},		/* 47 */
	{DATA,	DATA0},		/* 48 */
	{DATA,	PI},		/* 49 p5 */
	{DUT1,	8},		/* 50 DUT1 sign */
	{COEF,	1},		/* 51 10 year tens */
	{COEF,	2},		/* 52 20 */
	{COEF,	4},		/* 53 40 */
	{COEF,	8},		/* 54 80 */
	{DST1,	0},		/* 55 DST1 */
	{DUT1,	1},		/* 56 0.1 DUT1 fraction */
	{DUT1,	2},		/* 57 0.2 */
	{DUT1,	4},		/* 58 0.4 */
	{DATAX,	PI},		/* 59 p6 */
	{DATA,	DATA0},		/* 60 leap */
};

/*
 * IRIG format frames (1000 Hz, 1 second for 10 frames of data)
 */

/*
 * IRIG format frame 10 - MS straight binary seconds
 */
struct progx progu[] = {
	{COEF,	2},		/* 0 0x0 0200 seconds */
	{COEF,	4},		/* 1 0x0 0400 */
	{COEF,	8},		/* 2 0x0 0800 */
	{DECC,	1},		/* 3 0x0 1000 */
	{COEF,	2},		/* 4 0x0 2000 */
	{COEF,	4},		/* 6 0x0 4000 */
	{COEF,	8},		/* 7 0x0 8000 */
	{DECC,	1},		/* 8 0x1 0000 */
	{COEF,  2},     /* 9 0x2 0000 - but only 86,401 / 0x1 5181 seconds in a day, so always zero */
	{NODEC,	M8},	/* 9 PI */
};

/*
 * IRIG format frame 8 - MS control functions
 */
struct progx progv[] = {
	{COEF,	2},		/*  0 CF # 19 */
	{COEF,	4},		/*  1 CF # 20 */
	{COEF,	8},		/*  2 CF # 21 */
	{DECC,	1},		/*  3 CF # 22 */
	{COEF,	2},		/*  4 CF # 23 */
	{COEF,	4},		/*  6 CF # 24 */
	{COEF,	8},		/*  7 CF # 25 */
	{DECC,	1},		/*  8 CF # 26 */
	{COEF,  2},		/*  9 CF # 27 */
	{DEC,	M8},	/* 10 PI */
};

/*
 * IRIG format frames 7 & 9 - LS control functions & LS straight binary seconds
 */
struct progx progw[] = {
	{COEF,	1},		/*  0  CF # 10, 0x0 0001 seconds */
	{COEF,	2},		/*  1  CF # 11, 0x0 0002 */
	{COEF,	4},		/*  2  CF # 12, 0x0 0004 */
	{COEF,	8},		/*  3  CF # 13, 0x0 0008 */
	{DECC,	1},		/*  4  CF # 14, 0x0 0010 */
	{COEF,	2},		/*  6  CF # 15, 0x0 0020 */
	{COEF,	4},		/*  7  CF # 16, 0x0 0040 */
	{COEF,	8},		/*  8  CF # 17, 0x0 0080 */
	{DECC,  1},		/*  9  CF # 18, 0x0 0100 */
	{NODEC,	M8},	/* 10  PI */
};

/*
 * IRIG format frames 2 to 6 - minutes, hours, days, hundreds days, 2 digit years (also called control functions bits 1-9)
 */
struct progx progy[] = {
	{COEF,	1},		/* 0 1 units, CF # 1 */
	{COEF,	2},		/* 1 2 units, CF # 2 */
	{COEF,	4},		/* 2 4 units, CF # 3 */
	{COEF,	8},		/* 3 8 units, CF # 4 */
	{DECZ,	M2},	/* 4 zero bit, CF # 5 / unused, default zero in years */
	{COEF,	1},		/* 5 10 tens, CF # 6 */
	{COEF,	2},		/* 6 20 tens, CF # 7*/
	{COEF,	4},		/* 7 40 tens, CF # 8*/
	{COEF,	8},		/* 8 80 tens, CF # 9*/
	{DEC,	M8},	/* 9 PI */
};

/*
 * IRIG format first frame, frame 1 - seconds
 */
struct progx progz[] = {
	{MIN,	M8},	/* 0 PI (on-time marker for the second at zero cross of 1st cycle) */
	{COEF,	1},		/* 1 1 units */
	{COEF,	2},		/* 2 2 */
	{COEF,	4},		/* 3 4 */
	{COEF,	8},		/* 4 8 */
	{DECZ,	M2},	/* 5 zero bit */
	{COEF,	1},		/* 6 10 tens */
	{COEF,	2},		/* 7 20 */
	{COEF,	4},		/* 8 40 */
	{DEC,	M8},	/* 9 PI */
};

/* LeapState values. */
#define	LEAPSTATE_NORMAL			(0)
#define	LEAPSTATE_DELETING			(1)
#define	LEAPSTATE_INSERTING			(2)
#define	LEAPSTATE_ZERO_AFTER_INSERT	(3)


/*
 * Forward declarations
 */
void	WWV_Second(int, int);		/* send second */
void	WWV_SecondNoTick(int, int);	/* send second with no tick */
void	digit(int);		/* encode digit */
void	peep(int, int, int);	/* send cycles */
void	poop(int, int, int, int); /* Generate unmodulated from similar tables */
void	delay(int);		/* delay samples */
int		ConvertMonthDayToDayOfYear (int, int, int);	/* Calc day of year from year month & day */
void	Help (void);	/* Usage message */
void	ReverseString(char *);

/*
 * Extern declarations, don't know why not in headers
 */
//float	round ( float );

/*
 * Global variables
 */
char	buffer[BUFLNG];		/* output buffer */
int	bufcnt = 0;		/* buffer counter */
int	fd;			/* audio codec file descriptor */
int	tone = 1000;		/* WWV sync frequency */
int HourTone = 1500;	/* WWV hour on-time frequency */
int	encode = IRIG;		/* encoder select */
int	leap = 0;		/* leap indicator */
int	DstFlag = 0;		/* winter/summer time */
int	dut1 = 0;		/* DUT1 correction (sign, magnitude) */
int	utc = 0;		/* option epoch */
int IrigIncludeYear = FALSE;	/* Whether to send year in first control functions area, between P5 and P6. */
int IrigIncludeIeee = FALSE;	/* Whether to send IEEE 1344 control functions extensions between P6 and P8. */
int	StraightBinarySeconds = 0;
int	ControlFunctions = 0;
int	Debug = FALSE;
int Verbose = TRUE;
char	*CommandName;

#ifndef  HAVE_SYS_SOUNDCARD_H
int	level = AUDIO_MAX_GAIN / 8; /* output level */
int	port = AUDIO_LINE_OUT;	/* output port */
#endif

int		TotalSecondsCorrected = 0;
int		TotalCyclesAdded = 0;
int		TotalCyclesRemoved = 0;


/*
 * Main program
 */
int
main(
	int		argc,		/* command line options */
	char	**argv		/* poiniter to list of tokens */
	)
{
#ifndef  HAVE_SYS_SOUNDCARD_H
	audio_info_t info;	/* Sun audio structure */
	int	rval;           /* For IOCTL calls */
#endif

	struct	timeval	 TimeValue;				/* System clock at startup */
	time_t			 SecondsPartOfTime;		/* Sent to gmtime() for calculation of TimeStructure (can apply offset). */
	time_t			 BaseRealTime;			/* Base realtime so can determine seconds since starting. */
	time_t			 NowRealTime;			/* New realtime to can determine seconds as of now. */
	unsigned		 SecondsRunningRealTime;	/* Difference between NowRealTime and BaseRealTime. */
	unsigned		 SecondsRunningSimulationTime;	/* Time that the simulator has been running. */
	int				 SecondsRunningDifference;	/* Difference between what real time says we have been running */
												/* and what simulator says we have been running - will slowly  */
												/* change because of clock drift. */
	int				 ExpectedRunningDifference = 0;	/* Stable value that we've obtained from check at initial start-up.	*/
	unsigned		 StabilityCount;		/* Used to check stability of difference while starting */
#define	RUN_BEFORE_STABILITY_CHECK	(30)	// Must run this many seconds before even checking stability.
#define	MINIMUM_STABILITY_COUNT		(10)	// Number of consecutive differences that need to be within initial stability band to say we are stable.
#define	INITIAL_STABILITY_BAND		( 2)	// Determining initial stability for consecutive differences within +/- this value.
#define	RUNNING_STABILITY_BAND		( 5)	// When running, stability is defined as difference within +/- this value.

	struct	tm		*TimeStructure = NULL;	/* Structure returned by gmtime */
	char	device[200];	/* audio device */
	char	code[200];	/* timecode */
	int	temp;
	int	arg = 0;
	int	sw = 0;
	int	ptr = 0;

	int	Year;
	int	Month;
	int	DayOfMonth;
	int	Hour;
	int	Minute;
	int	Second = 0;
	int	DayOfYear;

	int	BitNumber;
#ifdef HAVE_SYS_SOUNDCARD_H
	int	AudioFormat;
	int	MonoStereo;     /* 0=mono, 1=stereo */
#define	MONO	(0)
#define	STEREO	(1)
	int	SampleRate;
	int	SampleRateDifference;
#endif
	int	SetSampleRate;
	char FormatCharacter = '3';		/* Default is IRIG-B with IEEE 1344 extensions */
	char AsciiValue;
	int	HexValue;
	int	OldPtr = 0;
	int FrameNumber = 0;

	/* Time offset for IEEE 1344 indication. */
	float TimeOffset = 0.0;
	int	OffsetSignBit = 0;
	int OffsetOnes = 0;
	int OffsetHalf = 0;

	int	TimeQuality = 0;	/* Time quality for IEEE 1344 indication. */
	char ParityString[200];	/* Partial output string, to calculate parity on. */
	int	ParitySum = 0;
	int	ParityValue;
	char *StringPointer;

	/* Flags to indicate requested leap second addition or deletion by command line option. */
	/* Should be mutually exclusive - generally ensured by code which interprets command line option. */
	int	InsertLeapSecond = FALSE;
	int	DeleteLeapSecond = FALSE;

	/* Date and time of requested leap second addition or deletion. */
	int	LeapYear					= 0;
	int LeapMonth					= 0;
	int	LeapDayOfMonth				= 0;
	int LeapHour					= 0;
	int	LeapMinute					= 0;
	int	LeapDayOfYear				= 0;

	/* State flag for the insertion and deletion of leap seconds, esp. deletion, */
	/* where the logic gets a bit tricky. */
	int	LeapState = LEAPSTATE_NORMAL;

	/* Flags for indication of leap second pending and leap secod polarity in IEEE 1344 */
	int	LeapSecondPending = FALSE;
	int	LeapSecondPolarity = FALSE;

	/* Date and time of requested switch into or out of DST by command line option. */
	int	DstSwitchYear				= 0;
	int DstSwitchMonth				= 0;
	int	DstSwitchDayOfMonth			= 0;
	int DstSwitchHour				= 0;
	int	DstSwitchMinute				= 0;
	int	DstSwitchDayOfYear			= 0;

	/* Indicate when we have been asked to switch into or out of DST by command line option. */
	int	DstSwitchFlag = FALSE;

	/* To allow predict for DstPendingFlag in IEEE 1344 */
	int	DstSwitchPendingYear		= 0;	/* Default value isn't valid, but I don't care. */
	int	DstSwitchPendingDayOfYear	= 0;
	int	DstSwitchPendingHour		= 0;
	int	DstSwitchPendingMinute		= 0;

	/* /Flag for indication of a DST switch pending in IEEE 1344 */
	int	DstPendingFlag = FALSE;

	/* Attempt at unmodulated */
	int	Unmodulated = FALSE;
	int UnmodulatedInverted = FALSE;

	/* Offset to actual time value sent. */
	float	UseOffsetHoursFloat;
	int		UseOffsetSecondsInt = 0;
	float	UseOffsetSecondsFloat;

	/* String to allow us to put out reversed data - so can read the binary numbers. */
	char	OutputDataString[OUTPUT_DATA_STRING_LENGTH];
	
	/* Number of seconds to send before exiting.  Default = 0 = forever. */
	int		SecondsToSend = 0;
	int		CountOfSecondsSent = 0;	/* Counter of seconds */
	
	/* Flags to indicate whether to add or remove a cycle for time adjustment. */
	int		AddCycle = FALSE;	 	// We are ahead, add cycle to slow down and get back in sync.
	int		RemoveCycle = FALSE;	// We are behind, remove cycle to slow down and get back in sync.
	int		RateCorrection;			// Aggregate flag for passing to subroutines.
	int		EnableRateCorrection = TRUE;
	
	float	RatioError;


	CommandName = argv[0];

	if	(argc < 1)
		{
		Help ();
		exit (-1);
		}

	/*
	 * Parse options
	 */
	strlcpy(device, DEVICE, sizeof(device));
	Year = 0;
	SetSampleRate = SECOND;
	
#if	HAVE_SYS_SOUNDCARD_H
	while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:xy:z?")) != -1) {
#else
	while ((temp = getopt(argc, argv, "a:b:c:df:g:hHi:jk:l:o:q:r:stu:v:xy:z?")) != -1) {
#endif
		switch (temp) {

		case 'a':	/* specify audio device (/dev/audio) */
			strlcpy(device, optarg, sizeof(device));
			break;

		case 'b':	/* Remove (delete) a leap second at the end of the specified minute. */
			sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth,
			    &LeapHour, &LeapMinute);
			InsertLeapSecond = FALSE;
			DeleteLeapSecond = TRUE;
			break;
			
		case 'c':	/* specify number of seconds to send output for before exiting, 0 = forever */
			sscanf(optarg, "%d", &SecondsToSend);
			break;

		case 'd':	/* set DST for summer (WWV/H only) / start with DST active (IRIG) */
			DstFlag++;
			break;

		case 'f':	/* select format: i=IRIG-98 (default) 2=IRIG-2004 3-IRIG+IEEE-1344 w=WWV(H) */
			sscanf(optarg, "%c", &FormatCharacter);
			break;

		case 'g':	/* Date and time to switch back into / out of DST active. */
			sscanf(optarg, "%2d%2d%2d%2d%2d", &DstSwitchYear, &DstSwitchMonth, &DstSwitchDayOfMonth,
			    &DstSwitchHour, &DstSwitchMinute);
			DstSwitchFlag = TRUE;
			break;

		case 'h':
		case 'H':
		case '?':
			Help ();
			exit(-1);
			break;

		case 'i':	/* Insert (add) a leap second at the end of the specified minute. */
			sscanf(optarg, "%2d%2d%2d%2d%2d", &LeapYear, &LeapMonth, &LeapDayOfMonth,
			    &LeapHour, &LeapMinute);
			InsertLeapSecond = TRUE;
			DeleteLeapSecond = FALSE;
			break;
			
		case 'j':
			EnableRateCorrection = FALSE;
			break;

		case 'k':
			sscanf (optarg, "%d", &RateCorrection);
			EnableRateCorrection = FALSE;
			if  (RateCorrection < 0)
				{
				RemoveCycle = TRUE;
				AddCycle = FALSE;
				
				if  (Verbose)
					printf ("\n> Forcing rate correction removal of cycle...\n");
				}
			else
				{
				if  (RateCorrection > 0)
					{
					RemoveCycle = FALSE;
					AddCycle = TRUE;
				
					if  (Verbose)
						printf ("\n> Forcing rate correction addition of cycle...\n");
					}
				}
			break;

		case 'l':	/* use time offset from UTC */
			sscanf(optarg, "%f", &UseOffsetHoursFloat);
			UseOffsetSecondsFloat = UseOffsetHoursFloat * (float) SECONDS_PER_HOUR;
			UseOffsetSecondsInt = (int) (UseOffsetSecondsFloat + 0.5);
			break;

		case 'o':	/* Set IEEE 1344 time offset in hours - positive or negative, to the half hour */
			sscanf(optarg, "%f", &TimeOffset);
			if  (TimeOffset >= -0.2)
				{
				OffsetSignBit = 0;

				if  (TimeOffset > 0)
					{
					OffsetOnes    = TimeOffset;

					if  ( (TimeOffset - floor(TimeOffset)) >= 0.4)
						OffsetHalf = 1;
					else
						OffsetHalf = 0;
					}
				else
					{
					OffsetOnes    = 0;
					OffsetHalf    = 0;
					}
				}
			else
				{
				OffsetSignBit = 1;
				OffsetOnes    = -TimeOffset;

				if  ( (ceil(TimeOffset) - TimeOffset) >= 0.4)
					OffsetHalf = 1;
				else
					OffsetHalf = 0;
				}

			/*printf ("\nGot TimeOffset = %3.1f, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d...\n",
					TimeOffset, OffsetSignBit, OffsetOnes, OffsetHalf);
			*/
			break;

		case 'q':	/* Hex quality code 0 to 0x0F - 0 = maximum, 0x0F = no lock */
			sscanf(optarg, "%x", &TimeQuality);
			TimeQuality &= 0x0F;
			/*printf ("\nGot TimeQuality = 0x%1X...\n", TimeQuality);
			*/
			break;

		case 'r':	/* sample rate (nominally 8000, integer close to 8000 I hope) */
			sscanf(optarg, "%d", &SetSampleRate);
			break;

		case 's':	/* set leap warning bit (WWV/H only) */
			leap++;
			break;

		case 't':	/* select WWVH sync frequency */
			tone = 1200;
			break;

		case 'u':	/* set DUT1 offset (-7 to +7) */
			sscanf(optarg, "%d", &dut1);
			if (dut1 < 0)
				dut1 = abs(dut1);
			else
				dut1 |= 0x8;
			break;

#ifndef  HAVE_SYS_SOUNDCARD_H
		case 'v':	/* set output level (0-255) */
			sscanf(optarg, "%d", &level);
			break;
#endif

		case 'x':	/* Turn off verbose output. */
			Verbose = FALSE;
			break;

		case 'y':	/* Set initial date and time */
			sscanf(optarg, "%2d%2d%2d%2d%2d%2d", &Year, &Month, &DayOfMonth,
			    &Hour, &Minute, &Second);
			utc++;
			break;

		case 'z':	/* Turn on Debug output (also turns on Verbose below) */
			Debug = TRUE;
			break;

		default:
			printf("Invalid option \"%c\", aborting...\n", temp);
			exit (-1);
			break;
		}
	}

	if  (Debug)
	    Verbose = TRUE;

	if  (InsertLeapSecond || DeleteLeapSecond)
		{
		LeapDayOfYear = ConvertMonthDayToDayOfYear (LeapYear, LeapMonth, LeapDayOfMonth);

		if	(Debug)
			{
			printf ("\nHave request for leap second %s at year %4d day %3d at %2.2dh%2.2d....\n",\
					DeleteLeapSecond ? "DELETION" : (InsertLeapSecond ? "ADDITION" : "( error ! )" ),
					LeapYear, LeapDayOfYear, LeapHour, LeapMinute);
			}
		}

	if	(DstSwitchFlag)
		{
		DstSwitchDayOfYear = ConvertMonthDayToDayOfYear (DstSwitchYear, DstSwitchMonth, DstSwitchDayOfMonth);

		/* Figure out time of minute previous to DST switch, so can put up warning flag in IEEE 1344 */
		DstSwitchPendingYear		= DstSwitchYear;
		DstSwitchPendingDayOfYear	= DstSwitchDayOfYear;
		DstSwitchPendingHour		= DstSwitchHour;
		DstSwitchPendingMinute		= DstSwitchMinute - 1;
		if 	(DstSwitchPendingMinute < 0)
			{
			DstSwitchPendingMinute = 59;
			DstSwitchPendingHour--;
			if	(DstSwitchPendingHour < 0)
				{
				DstSwitchPendingHour = 23;
				DstSwitchPendingDayOfYear--;
				if	(DstSwitchPendingDayOfYear < 1)
					{
					DstSwitchPendingYear--;
					}
				}
			}

		if	(Debug)
			{
			printf ("\nHave DST switch request for year %4d day %3d at %2.2dh%2.2d,",
					DstSwitchYear, DstSwitchDayOfYear, DstSwitchHour, DstSwitchMinute);
			printf ("\n    so will have warning at year %4d day %3d at %2.2dh%2.2d.\n",
					DstSwitchPendingYear, DstSwitchPendingDayOfYear, DstSwitchPendingHour, DstSwitchPendingMinute);
			}
		}

	switch (tolower(FormatCharacter)) {
	case 'i':
		printf ("\nFormat is IRIG-1998 (no year coded)...\n\n");
		encode = IRIG;
		IrigIncludeYear = FALSE;
		IrigIncludeIeee = FALSE;
		break;

	case '2':
		printf ("\nFormat is IRIG-2004 (BCD year coded)...\n\n");
		encode = IRIG;
		IrigIncludeYear = TRUE;
		IrigIncludeIeee = FALSE;
		break;

	case '3':
		printf ("\nFormat is IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
		encode = IRIG;
		IrigIncludeYear = TRUE;
		IrigIncludeIeee = TRUE;
		break;

	case '4':
		printf ("\nFormat is unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
		encode = IRIG;
		IrigIncludeYear = TRUE;
		IrigIncludeIeee = TRUE;

		Unmodulated = TRUE;
		UnmodulatedInverted = FALSE;
		break;

	case '5':
		printf ("\nFormat is inverted unmodulated IRIG with IEEE-1344 (BCD year coded, and more control functions)...\n\n");
		encode = IRIG;
		IrigIncludeYear = TRUE;
		IrigIncludeIeee = TRUE;

		Unmodulated = TRUE;
		UnmodulatedInverted = TRUE;
		break;

	case 'w':
		printf ("\nFormat is WWV(H)...\n\n");
		encode = WWV;
		break;

	default:
		printf ("\n\nUnexpected format value of \'%c\', cannot parse, aborting...\n\n", FormatCharacter);
		exit (-1);
		break;
	}

	/*
	 * Open audio device and set options
	 */
	fd = open(device, O_WRONLY);
	if (fd <= 0) {
		printf("Unable to open audio device \"%s\", aborting: %s\n", device, strerror(errno));
		exit(1);
	}

#ifdef  HAVE_SYS_SOUNDCARD_H
	/* First set coding type */
	AudioFormat = AFMT_MU_LAW;
	if (ioctl(fd, SNDCTL_DSP_SETFMT, &AudioFormat)==-1)
	{ /* Fatal error */
	printf ("\nUnable to set output format, aborting...\n\n");
	exit(-1);
	}

	if  (AudioFormat != AFMT_MU_LAW)
	{
	printf ("\nUnable to set output format for mu law, aborting...\n\n");
	exit(-1);
	}

	/* Next set number of channels */
	MonoStereo = MONO;	/* Mono */
	if (ioctl(fd, SNDCTL_DSP_STEREO, &MonoStereo)==-1)
	{ /* Fatal error */
	printf ("\nUnable to set mono/stereo, aborting...\n\n");
	exit(-1);
	}

	if (MonoStereo != MONO)
	{
	printf ("\nUnable to set mono/stereo for mono, aborting...\n\n");
	exit(-1);
	}

	/* Now set sample rate */
	SampleRate = SetSampleRate;
	if (ioctl(fd, SNDCTL_DSP_SPEED, &SampleRate)==-1)
	{ /* Fatal error */
	printf ("\nUnable to set sample rate to %d, returned %d, aborting...\n\n", SetSampleRate, SampleRate);
	exit(-1);
	}

	SampleRateDifference = SampleRate - SetSampleRate;

	if  (SampleRateDifference < 0)
		SampleRateDifference = - SampleRateDifference;

	/* Fixed allowable sample rate error 0.1% */
	if (SampleRateDifference > (SetSampleRate/1000))
	{
	printf ("\nUnable to set sample rate to %d, result was %d, more than 0.1 percent, aborting...\n\n", SetSampleRate, SampleRate);
	exit(-1);
	}
	else
	{
	/* printf ("\nAttempt to set sample rate to %d, actual %d...\n\n", SetSampleRate, SampleRate); */
	}
#else
	rval = ioctl(fd, AUDIO_GETINFO, &info);
	if (rval < 0) {
		printf("\naudio control %s", strerror(errno));
		exit(0);
	}
	info.play.port = port;
	info.play.gain = level;
	info.play.sample_rate = SetSampleRate;
	info.play.channels = 1;
	info.play.precision = 8;
	info.play.encoding = AUDIO_ENCODING_ULAW;
	printf("\nport %d gain %d rate %d chan %d prec %d encode %d\n",
	    info.play.port, info.play.gain, info.play.sample_rate,
	    info.play.channels, info.play.precision,
	    info.play.encoding);
	ioctl(fd, AUDIO_SETINFO, &info);
#endif

 	/*
	 * Unless specified otherwise, read the system clock and
	 * initialize the time.
	 */
	gettimeofday(&TimeValue, NULL);		// Now always read the system time to keep "real time" of operation.
	NowRealTime = BaseRealTime = SecondsPartOfTime = TimeValue.tv_sec;
	SecondsRunningSimulationTime = 0;	// Just starting simulation, running zero seconds as of now.
	StabilityCount = 0;					// No stability yet.

	if	(utc)
		{
		DayOfYear = ConvertMonthDayToDayOfYear (Year, Month, DayOfMonth);
		}
	else
		{
		/* Apply offset to time. */
		if	(UseOffsetSecondsInt >= 0)
			SecondsPartOfTime += (time_t)   UseOffsetSecondsInt;
		else
			SecondsPartOfTime -= (time_t) (-UseOffsetSecondsInt);

		TimeStructure = gmtime(&SecondsPartOfTime);
		Minute = TimeStructure->tm_min;
		Hour = TimeStructure->tm_hour;
		DayOfYear = TimeStructure->tm_yday + 1;
		Year = TimeStructure->tm_year % 100;
		Second = TimeStructure->tm_sec;

		/*
		 * Delay the first second so the generator is accurately
		 * aligned with the system clock within one sample (125
		 * microseconds ).
		 */
		delay(SECOND - TimeValue.tv_usec * 8 / 1000);
		}

	StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR);

	memset(code, 0, sizeof(code));
	switch (encode) {

	/*
	 * For WWV/H and default time, carefully set the signal
	 * generator seconds number to agree with the current time.
	 */
	case WWV:
		printf("WWV time signal, starting point:\n");
		printf(" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Minute tone = %d Hz, Hour tone = %d Hz.\n",
		    Year, DayOfYear, Hour, Minute, Second, tone, HourTone);
		snprintf(code, sizeof(code), "%01d%03d%02d%02d%01d",
		    Year / 10, DayOfYear, Hour, Minute, Year % 10);
		if  (Verbose)
			{
		    printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s", 
				Year, DayOfYear, Hour, Minute, Second, code);

				if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
				printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
			else
				printf ("\n");
			}

		ptr = 8;
		for (BitNumber = 0; BitNumber <= Second; BitNumber++) {
			if (progx[BitNumber].sw == DEC)
				ptr--;
		}
		break;

	/*
	 * For IRIG the signal generator runs every second, so requires
	 * no additional alignment.
	 */
	case IRIG:
		printf ("IRIG-B time signal, starting point:\n");
		printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n",
		    Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds);
		printf ("\n");
		if  (Verbose)
		    {
    		printf ("Codes: \".\" = marker/position indicator, \"-\" = zero dummy bit, \"0\" = zero bit, \"1\" = one bit.\n");
			if  ((EnableRateCorrection) || (AddCycle) || (RemoveCycle))
				{
				printf ("       \"o\" = short zero, \"*\" = long zero, \"x\" = short one, \"+\" = long one.\n");
				}
	    	printf ("Numerical values are time order reversed in output to make it easier to read.\n");
    		/*                 111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999 */
	    	/*       0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 */
		    printf ("\n");
    		printf ("Legend of output codes:\n");
	    	//printf ("\n");
		    //printf ("|  StraightBinSecs  | IEEE_1344_Control |   Year  |    Day_of_Year    |  Hours  | Minutes |Seconds |\n");
    		//printf ("|  ---------------  | ----------------- |   ----  |    -----------    |  -----  | ------- |------- |\n");
	    	//printf ("|                   |                   |         |                   |         |         |        |\n");
	    	}
		break;
	}

	/*
	 * Run the signal generator to generate new timecode strings
	 * once per minute for WWV/H and once per second for IRIG.
	 */
	for (CountOfSecondsSent=0; ((SecondsToSend==0) || (CountOfSecondsSent<SecondsToSend)); CountOfSecondsSent++)
		{
		if  ((encode == IRIG) && (((Second % 20) == 0) || (CountOfSecondsSent == 0)))
			{
	    	printf ("\n");

			printf (" Year = %02d, Day of year = %03d, Time = %02d:%02d:%02d, Straight binary seconds (SBS) = %05d / 0x%04X.\n",
			    Year, DayOfYear, Hour, Minute, Second, StraightBinarySeconds, StraightBinarySeconds);
			if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
				{
				printf (" CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
				if  ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0)))
					{
					RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent);
					printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n", 
									RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate);
					}
				}
			else
				printf ("\n");

		    /* printf ("|Seconds | Minutes |  Hours  |    Day_of_Year    |   Year  | IEEE_1344_Control |  StraightBinSecs  |\n");
    		printf ("|------- | ------- |  -----  |    -----------    |   ----  | ----------------- |-------------------|\n");
	    	printf ("|        |         |         |                   |         |                   |                   |\n");*/
		    printf ("|  StraightBinSecs  | IEEE_1344_Control |   Year  |    Day_of_Year    |  Hours  | Minutes |Seconds |\n");
    		printf ("|  ---------------  | ----------------- |   ----  |    -----------    |  -----  | ------- |------- |\n");
	    	printf ("|                   |                   |         |                   |         |         |        |\n");
			}

		if  (RemoveCycle)
			{
			RateCorrection = -1;
			TotalSecondsCorrected ++;
			}
		else
			{
			if  (AddCycle)
				{
				TotalSecondsCorrected ++;
				RateCorrection = +1;
				}
			else
				RateCorrection = 0;
			}

		/*
		 * Crank the state machine to propagate carries to the
		 * year of century. Note that we delayed up to one
		 * second for alignment after reading the time, so this
		 * is the next second.
		 */

		if  (LeapState == LEAPSTATE_NORMAL)
			{
			/* If on the second of a leap (second 59 in the specified minute), then add or delete a second */
			if  ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute))
				{
				/* To delete a second, which means we go from 58->60 instead of 58->59->00. */
				if  ((DeleteLeapSecond) && (Second == 58))
					{
					LeapState = LEAPSTATE_DELETING;

					if	(Debug)
						printf ("\n<--- Ready to delete a leap second...\n");
					}
				else
					{	/* Delete takes precedence over insert. */
					/* To add a second, which means we go from 59->60->00 instead of 59->00. */
					if  ((InsertLeapSecond) && (Second == 59))
						{
						LeapState = LEAPSTATE_INSERTING;

						if	(Debug)
							printf ("\n<--- Ready to insert a leap second...\n");
						}
					}
				}
			}

		switch (LeapState)
			{
			case LEAPSTATE_NORMAL:
				Second = (Second + 1) % 60;
				break;

			case LEAPSTATE_DELETING:
				Second = 0;
				LeapState = LEAPSTATE_NORMAL;

				if	(Debug)
					printf ("\n<--- Deleting a leap second...\n");
				break;

			case LEAPSTATE_INSERTING:
				Second = 60;
				LeapState = LEAPSTATE_ZERO_AFTER_INSERT;

				if	(Debug)
					printf ("\n<--- Inserting a leap second...\n");
				break;

			case LEAPSTATE_ZERO_AFTER_INSERT:
				Second = 0;
				LeapState = LEAPSTATE_NORMAL;

				if	(Debug)
					printf ("\n<--- Inserted a leap second, now back to zero...\n");
				break;

			default:
				printf ("\n\nLeap second state invalid value of %d, aborting...", LeapState);
				exit (-1);
				break;
			}

		/* Check for second rollover, increment minutes and ripple upward if required. */
		if (Second == 0) {
			Minute++;
			if (Minute >= 60) {
				Minute = 0;
				Hour++;
			}

			/* Check for activation of DST switch. */
			/* If DST is active, this would mean that at the appointed time, we de-activate DST, */
			/* which translates to going backward an hour (repeating the last hour). */
			/* If DST is not active, this would mean that at the appointed time, we activate DST, */
			/* which translates to going forward an hour (skipping the next hour). */
			if	(DstSwitchFlag)
				{
				/* The actual switch happens on the zero'th second of the actual minute specified. */
				if	((Year == DstSwitchYear) && (DayOfYear == DstSwitchDayOfYear) && (Hour == DstSwitchHour) && (Minute == DstSwitchMinute))
					{
					if  (DstFlag == 0)
						{	/* DST flag is zero, not in DST, going to DST, "spring ahead", so increment hour by two instead of one. */
						Hour++;
						DstFlag = 1;

						/* Must adjust offset to keep consistent with UTC. */
						/* Here we have to increase offset by one hour.  If it goes from negative to positive, then we fix that. */
						if	(OffsetSignBit == 0)
							{	/* Offset is positive */
							if	(OffsetOnes == 0x0F)
								{
								OffsetSignBit = 1;
								OffsetOnes    = (OffsetHalf == 0) ? 8 : 7;
								}
							else
								OffsetOnes++;
							}
						else
							{	/* Offset is negative */
							if  (OffsetOnes == 0)
								{
								OffsetSignBit = 0;
								OffsetOnes    = (OffsetHalf == 0) ? 1 : 0;
								}
							else
								OffsetOnes--;
							}

						if	(Debug)
							printf ("\n<--- DST activated, spring ahead an hour, new offset !...\n");
						}
					else
						{	/* DST flag is non zero, in DST, going out of DST, "fall back", so no increment of hour. */
						Hour--;
						DstFlag = 0;

						/* Must adjust offset to keep consistent with UTC. */
						/* Here we have to reduce offset by one hour.  If it goes negative, then we fix that. */
						if	(OffsetSignBit == 0)
							{	/* Offset is positive */
							if  (OffsetOnes == 0)
								{
								OffsetSignBit = 1;
								OffsetOnes    = (OffsetHalf == 0) ? 1 : 0;
								}
							else
								OffsetOnes--;
							}
						else
							{	/* Offset is negative */
							if	(OffsetOnes == 0x0F)
								{
								OffsetSignBit = 0;
								OffsetOnes    = (OffsetHalf == 0) ? 8 : 7;
								}
							else
								OffsetOnes++;
							}

						if	(Debug)
							printf ("\n<--- DST de-activated, fall back an hour!...\n");
						}

					DstSwitchFlag = FALSE;	/* One time deal, not intended to run this program past two switches... */
					}
				}

			if (Hour >= 24) {
				/* Modified, just in case dumb case where activating DST advances 23h59:59 -> 01h00:00 */
				Hour = Hour % 24;
				DayOfYear++;
			}

			/*
			 * At year rollover check for leap second.
			 */
			if (DayOfYear >= (Year & 0x3 ? 366 : 367)) {
				if (leap) {
					WWV_Second(DATA0, RateCorrection);
					if  (Verbose)
					    printf("\nLeap!");
					leap = 0;
				}
				DayOfYear = 1;
				Year++;
			}
			if (encode == WWV) {
				snprintf(code, sizeof(code),
				    "%01d%03d%02d%02d%01d", Year / 10,
				    DayOfYear, Hour, Minute, Year % 10);
				if  (Verbose)
				    printf("\n Year = %2.2d, Day of year = %3d, Time = %2.2d:%2.2d:%2.2d, Code = %s", 
						Year, DayOfYear, Hour, Minute, Second, code);

				if  ((EnableRateCorrection) || (RemoveCycle) || (AddCycle))
					{
					printf (", CountOfSecondsSent = %d, TotalCyclesAdded = %d, TotalCyclesRemoved = %d\n", CountOfSecondsSent, TotalCyclesAdded, TotalCyclesRemoved);
					if  ((CountOfSecondsSent != 0) && ((TotalCyclesAdded != 0) || (TotalCyclesRemoved != 0)))
						{
						RatioError = ((float) (TotalCyclesAdded - TotalCyclesRemoved)) / (1000.0 * (float) CountOfSecondsSent);
						printf (" Adjusted by %2.1f%%, apparent send frequency is %4.2f Hz not %d Hz.\n\n", 
										RatioError*100.0, (1.0+RatioError)*((float) SetSampleRate), SetSampleRate);
						}
					}
				else
					printf ("\n");

				ptr = 8;
			}
		}	/* End of "if  (Second == 0)" */

		/* After all that, if we are in the minute just prior to a leap second, warn of leap second pending */
		/* and of the polarity */
		if  ((Year == LeapYear) && (DayOfYear == LeapDayOfYear) && (Hour == LeapHour) && (Minute == LeapMinute))
			{
			LeapSecondPending = TRUE;
			LeapSecondPolarity = DeleteLeapSecond;
			}
		else
			{
			LeapSecondPending = FALSE;
			LeapSecondPolarity = FALSE;
			}

		/* Notification through IEEE 1344 happens during the whole minute previous to the minute specified. */
		/* The time of that minute has been previously calculated. */
		if	((Year == DstSwitchPendingYear) && (DayOfYear == DstSwitchPendingDayOfYear) &&
					(Hour == DstSwitchPendingHour) && (Minute == DstSwitchPendingMinute))
			{
			DstPendingFlag = TRUE;
			}
		else
			{
			DstPendingFlag = FALSE;
			}


		StraightBinarySeconds = Second + (Minute * SECONDS_PER_MINUTE) + (Hour * SECONDS_PER_HOUR);

		if (encode == IRIG) {
			if  (IrigIncludeIeee)
				{
				if  ((OffsetOnes == 0) && (OffsetHalf == 0))
					OffsetSignBit = 0;

				ControlFunctions = (LeapSecondPending == 0 ? 0x00000 : 0x00001) | (LeapSecondPolarity == 0 ? 0x00000 : 0x00002)
						| (DstPendingFlag == 0 ? 0x00000 : 0x00004) | (DstFlag == 0 ? 0x00000 : 0x00008)
						| (OffsetSignBit == 0 ? 0x00000 : 0x00010)  | ((OffsetOnes & 0x0F) << 5)           | (OffsetHalf == 0 ? 0x00000 : 0x00200)
						| ((TimeQuality & 0x0F) << 10);
				/* if  (Verbose)
				        printf ("\nDstFlag = %d, OffsetSignBit = %d, OffsetOnes = %d, OffsetHalf = %d, TimeQuality = 0x%1.1X ==> ControlFunctions = 0x%5.5X...",
						    DstFlag, OffsetSignBit, OffsetOnes, OffsetHalf, TimeQuality, ControlFunctions);
				*/
				}
			else
				ControlFunctions = 0;

			/*
						      YearDay HourMin Sec
			snprintf(code, sizeof(code), "%04x%04d%06d%02d%02d%02d",
				0, Year, DayOfYear, Hour, Minute, Second);
			*/
			if  (IrigIncludeYear) {
				snprintf(ParityString, sizeof(ParityString),
				    "%04X%02d%04d%02d%02d%02d",
				    ControlFunctions & 0x7FFF, Year,
				    DayOfYear, Hour, Minute, Second);
			} else {
				snprintf(ParityString, sizeof(ParityString),
				    "%04X%02d%04d%02d%02d%02d",
				    ControlFunctions & 0x7FFF,
				    0, DayOfYear, Hour, Minute, Second);
			}

			if  (IrigIncludeIeee)
				{
				ParitySum = 0;
				for (StringPointer=ParityString; *StringPointer!=NUL; StringPointer++)
					{
					switch (toupper(*StringPointer))
						{
						case '1':
						case '2':
						case '4':
						case '8':
							ParitySum += 1;
							break;

						case '3':
						case '5':
						case '6':
						case '9':
						case 'A':
						case 'C':
							ParitySum += 2;
							break;

						case '7':
						case 'B':
						case 'D':
						case 'E':
							ParitySum += 3;
							break;

						case 'F':
							ParitySum += 4;
							break;
						}
					}

				if  ((ParitySum & 0x01) == 0x01)
					ParityValue = 0x01;
				else
					ParityValue = 0;
				}
			else
				ParityValue = 0;

			ControlFunctions |= ((ParityValue & 0x01) << 14);

			if  (IrigIncludeYear) {
				snprintf(code, sizeof(code),
				    /* YearDay HourMin Sec */
				    "%05X%05X%02d%04d%02d%02d%02d",
				    StraightBinarySeconds,
				    ControlFunctions, Year, DayOfYear,
				    Hour, Minute, Second);
			} else {
				snprintf(code, sizeof(code),
				    /* YearDay HourMin Sec */
				    "%05X%05X%02d%04d%02d%02d%02d",
				    StraightBinarySeconds,
				    ControlFunctions, 0, DayOfYear,
				    Hour, Minute, Second);
			}

			if  (Debug)
				printf("\nCode string: %s, ParityString = %s, ParitySum = 0x%2.2X, ParityValue = %d, DstFlag = %d...\n", code, ParityString, ParitySum, ParityValue, DstFlag);

			ptr = strlen(code)-1;
			OldPtr = 0;
		}

		/*
		 * Generate data for the second
		 */
		switch (encode) {

		/*
		 * The IRIG second consists of 20 BCD digits of width-
		 * modulateod pulses at 2, 5 and 8 ms and modulated 50
		 * percent on the 1000-Hz carrier.
		 */
		case IRIG:
			/* Initialize the output string */
			OutputDataString[0] = '\0';

			for (BitNumber = 0; BitNumber < 100; BitNumber++) {
				FrameNumber = (BitNumber/10) + 1;
				switch (FrameNumber)
					{
					case 1:
						/* bits 0 to 9, first frame */
						sw  = progz[BitNumber % 10].sw;
						arg = progz[BitNumber % 10].arg;
						break;

					case 2:
					case 3:
					case 4:
					case 5:
					case 6:
						/* bits 10 to 59, second to sixth frame */
						sw  = progy[BitNumber % 10].sw;
						arg = progy[BitNumber % 10].arg;
						break;

					case 7:
						/* bits 60 to 69, seventh frame */
						sw  = progw[BitNumber % 10].sw;
						arg = progw[BitNumber % 10].arg;
						break;

					case 8:
						/* bits 70 to 79, eighth frame */
						sw  = progv[BitNumber % 10].sw;
						arg = progv[BitNumber % 10].arg;
						break;

					case 9:
						/* bits 80 to 89, ninth frame */
						sw  = progw[BitNumber % 10].sw;
						arg = progw[BitNumber % 10].arg;
						break;

					case 10:
						/* bits 90 to 99, tenth frame */
						sw  = progu[BitNumber % 10].sw;
						arg = progu[BitNumber % 10].arg;
						break;

					default:
						/* , Unexpected values of FrameNumber */
						printf ("\n\nUnexpected value of FrameNumber = %d, cannot parse, aborting...\n\n", FrameNumber);
						exit (-1);
						break;
					}

				switch(sw) {

				case DECC:	/* decrement pointer and send bit. */
					ptr--;
				case COEF:	/* send BCD bit */
					AsciiValue = toupper(code[ptr]);
					HexValue   = isdigit(AsciiValue) ? AsciiValue - '0' : (AsciiValue - 'A')+10;
					/* if  (Debug) {
						if  (ptr != OldPtr) {
						if  (Verbose)
						    printf("\n(%c->%X)", AsciiValue, HexValue);
						OldPtr = ptr;
						}
					}
					*/
					// OK, adjust all unused bits in hundreds of days.
					if  ((FrameNumber == 5) && ((BitNumber % 10) > 1))
						{
						if  (RateCorrection < 0)
							{	// Need to remove cycles to catch up.
							if  ((HexValue & arg) != 0) 
								{
								if  (Unmodulated)
									{
									poop(M5, 1000, HIGH, UnmodulatedInverted);
									poop(M5-1, 1000, LOW,  UnmodulatedInverted);

									TotalCyclesRemoved += 1;
									}
								else
									{
									peep(M5, 1000, HIGH);
									peep(M5-1, 1000, LOW);

									TotalCyclesRemoved += 1;
									}
								strlcat(OutputDataString, "x", OUTPUT_DATA_STRING_LENGTH);
								}
							else 
								{
								if	(Unmodulated)
									{
									poop(M2, 1000, HIGH, UnmodulatedInverted);
									poop(M8-1, 1000, LOW,  UnmodulatedInverted);

									TotalCyclesRemoved += 1;
									}
								else
									{
									peep(M2, 1000, HIGH);
									peep(M8-1, 1000, LOW);

									TotalCyclesRemoved += 1;
									}
								strlcat(OutputDataString, "o", OUTPUT_DATA_STRING_LENGTH);
								}
							}	// End of true clause for "if  (RateCorrection < 0)"
						else
							{	// Else clause for "if  (RateCorrection < 0)"
							if  (RateCorrection > 0)
								{	// Need to add cycles to slow back down.
								if  ((HexValue & arg) != 0) 
									{
									if  (Unmodulated)
										{
										poop(M5, 1000, HIGH, UnmodulatedInverted);
										poop(M5+1, 1000, LOW,  UnmodulatedInverted);

										TotalCyclesAdded += 1;
										}
									else
										{
										peep(M5, 1000, HIGH);
										peep(M5+1, 1000, LOW);

										TotalCyclesAdded += 1;
										}
									strlcat(OutputDataString, "+", OUTPUT_DATA_STRING_LENGTH);
									}
								else 
									{
									if	(Unmodulated)
										{
										poop(M2, 1000, HIGH, UnmodulatedInverted);
										poop(M8+1, 1000, LOW,  UnmodulatedInverted);

										TotalCyclesAdded += 1;
										}
									else
										{
										peep(M2, 1000, HIGH);
										peep(M8+1, 1000, LOW);

										TotalCyclesAdded += 1;
										}
									strlcat(OutputDataString, "*", OUTPUT_DATA_STRING_LENGTH);
									}
								}	// End of true clause for "if  (RateCorrection > 0)"
							else
								{	// Else clause for "if  (RateCorrection > 0)"
								// Rate is OK, just do what you feel!
								if  ((HexValue & arg) != 0) 
									{
									if  (Unmodulated)
										{
										poop(M5, 1000, HIGH, UnmodulatedInverted);
										poop(M5, 1000, LOW,  UnmodulatedInverted);
										}
									else
										{
										peep(M5, 1000, HIGH);
										peep(M5, 1000, LOW);
										}
									strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH);
									}
								else 
									{
									if	(Unmodulated)
										{
										poop(M2, 1000, HIGH, UnmodulatedInverted);
										poop(M8, 1000, LOW,  UnmodulatedInverted);
										}
									else
										{
										peep(M2, 1000, HIGH);
										peep(M8, 1000, LOW);
										}
									strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH);
									}
								}	// End of else clause for "if  (RateCorrection > 0)"
							}	// End of else claues for "if  (RateCorrection < 0)"
						}	// End of true clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
					else
						{	// Else clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
						if  ((HexValue & arg) != 0) 
							{
							if  (Unmodulated)
								{
								poop(M5, 1000, HIGH, UnmodulatedInverted);
								poop(M5, 1000, LOW,  UnmodulatedInverted);
								}
							else
								{
								peep(M5, 1000, HIGH);
								peep(M5, 1000, LOW);
								}
							strlcat(OutputDataString, "1", OUTPUT_DATA_STRING_LENGTH);
							}
						else 
							{
							if	(Unmodulated)
								{
								poop(M2, 1000, HIGH, UnmodulatedInverted);
								poop(M8, 1000, LOW,  UnmodulatedInverted);
								}
							else
								{
								peep(M2, 1000, HIGH);
								peep(M8, 1000, LOW);
								}
							strlcat(OutputDataString, "0", OUTPUT_DATA_STRING_LENGTH);
							}
						} // end of else clause for "if  ((FrameNumber == 5) && (BitNumber == 8))"
					break;

				case DECZ:	/* decrement pointer and send zero bit */
					ptr--;
					if	(Unmodulated)
						{
						poop(M2, 1000, HIGH, UnmodulatedInverted);
						poop(M8, 1000, LOW,  UnmodulatedInverted);
						}
					else
						{
						peep(M2, 1000, HIGH);
						peep(M8, 1000, LOW);
						}
					strlcat(OutputDataString, "-", OUTPUT_DATA_STRING_LENGTH);
					break;

				case DEC:	/* send marker/position indicator IM/PI bit */
					ptr--;
				case NODEC:	/* send marker/position indicator IM/PI bit but no decrement pointer */
				case MIN:	/* send "second start" marker/position indicator IM/PI bit */
					if  (Unmodulated)
						{
						poop(arg,      1000, HIGH, UnmodulatedInverted);
						poop(10 - arg, 1000, LOW,  UnmodulatedInverted);
						}
					else
						{
						peep(arg,      1000, HIGH);
						peep(10 - arg, 1000, LOW);
						}
					strlcat(OutputDataString, ".", OUTPUT_DATA_STRING_LENGTH);
					break;

				default:
					printf ("\n\nUnknown state machine value \"%d\", unable to continue, aborting...\n\n", sw);
					exit (-1);
					break;
				}
				if (ptr < 0)
					break;
			}
			ReverseString ( OutputDataString );
			if  (Verbose)
				{
    			printf("%s", OutputDataString);
				if  (RateCorrection > 0)
					printf(" fast\n");
				else
					{
					if  (RateCorrection < 0)
						printf (" slow\n");
					else
						printf ("\n");
					}
				}
			break;

		/*
		 * The WWV/H second consists of 9 BCD digits of width-
		 * modulateod pulses 200, 500 and 800 ms at 100-Hz.
		 */
		case WWV:
			sw = progx[Second].sw;
			arg = progx[Second].arg;
			switch(sw) {

			case DATA:		/* send data bit */
				WWV_Second(arg, RateCorrection);
				if  (Verbose)
					{
					if  (arg == DATA0)
						printf ("0");
					else
						{
						if  (arg == DATA1)
							printf ("1");
						else
							{
							if  (arg == PI)
								printf ("P");
							else
								printf ("?");
							}
						}
					}
				break;

			case DATAX:		/* send data bit */
				WWV_SecondNoTick(arg, RateCorrection);
				if  (Verbose)
					{
					if  (arg == DATA0)
						printf ("0");
					else
						{
						if  (arg == DATA1)
							printf ("1");
						else
							{
							if  (arg == PI)
								printf ("P");
							else
								printf ("?");
							}
						}
					}
				break;

			case COEF:		/* send BCD bit */
				if (code[ptr] & arg) {
					WWV_Second(DATA1, RateCorrection);
					if  (Verbose)
					    printf("1");
				} else {
					WWV_Second(DATA0, RateCorrection);
					if  (Verbose)
					    printf("0");
				}
				break;

			case LEAP:		/* send leap bit */
				if (leap) {
					WWV_Second(DATA1, RateCorrection);
					if  (Verbose)
					    printf("L");
				} else {
					WWV_Second(DATA0, RateCorrection);
					if  (Verbose)
					    printf("0");
				}
				break;

			case DEC:		/* send data bit */
				ptr--;
				WWV_Second(arg, RateCorrection);
				if  (Verbose)
					{
					if  (arg == DATA0)
						printf ("0");
					else
						{
						if  (arg == DATA1)
							printf ("1");
						else
							{
							if  (arg == PI)
								printf ("P");
							else
								printf ("?");
							}
						}
					}
				break;

			case DECX:		/* send data bit with no tick */
				ptr--;
				WWV_SecondNoTick(arg, RateCorrection);
				if  (Verbose)
					{
					if  (arg == DATA0)
						printf ("0");
					else
						{
						if  (arg == DATA1)
							printf ("1");
						else
							{
							if  (arg == PI)
								printf ("P");
							else
								printf ("?");
							}
						}
					}
				break;

			case MIN:		/* send minute sync */
				if  (Minute == 0)
					{
					peep(arg, HourTone, HIGH);

					if  (RateCorrection < 0)
						{
						peep( 990 - arg, HourTone, OFF);
						TotalCyclesRemoved += 10;

						if  (Debug)
							printf ("\n* Shorter Second: ");
						}
					else
						{
						if	(RateCorrection > 0)
							{
							peep(1010 - arg, HourTone, OFF);

							TotalCyclesAdded += 10;

							if  (Debug)
								printf ("\n* Longer Second: ");
							}
						else
							{
							peep(1000 - arg, HourTone, OFF);
							}
						}

					if  (Verbose)
					    printf("H");
					}
				else
					{
					peep(arg, tone, HIGH);

					if  (RateCorrection < 0)
						{
						peep( 990 - arg, tone, OFF);
						TotalCyclesRemoved += 10;

						if  (Debug)
							printf ("\n* Shorter Second: ");
						}
					else
						{
						if	(RateCorrection > 0)
							{
							peep(1010 - arg, tone, OFF);

							TotalCyclesAdded += 10;

							if  (Debug)
								printf ("\n* Longer Second: ");
							}
						else
							{
							peep(1000 - arg, tone, OFF);
							}
						}

					if  (Verbose)
					    printf("M");
					}
				break;

			case DUT1:		/* send DUT1 bits */
				if (dut1 & arg)
					{
					WWV_Second(DATA1, RateCorrection);
					if  (Verbose)
					    printf("1");
					}
				else
					{
					WWV_Second(DATA0, RateCorrection);
					if  (Verbose)
					    printf("0");
					}
				break;

			case DST1:		/* send DST1 bit */
				ptr--;
				if (DstFlag)
					{
					WWV_Second(DATA1, RateCorrection);
					if  (Verbose)
					    printf("1");
					}
				else
					{
					WWV_Second(DATA0, RateCorrection);
					if  (Verbose)
					    printf("0");
					}
				break;

			case DST2:		/* send DST2 bit */
				if (DstFlag)
					{
					WWV_Second(DATA1, RateCorrection);
					if  (Verbose)
					    printf("1");
					}
				else
					{
					WWV_Second(DATA0, RateCorrection);
					if  (Verbose)
					    printf("0");
					}
				break;
			}
		}

	if  (EnableRateCorrection)
		{
		SecondsRunningSimulationTime++;

		gettimeofday(&TimeValue, NULL);
		NowRealTime = TimeValue.tv_sec;

		if  (NowRealTime >= BaseRealTime)		// Just in case system time corrects backwards, do not blow up.
			{
			SecondsRunningRealTime = (unsigned) (NowRealTime - BaseRealTime);
			SecondsRunningDifference = SecondsRunningSimulationTime - SecondsRunningRealTime;

			if  (Debug)
				{
				printf ("> NowRealTime = 0x%8.8X, BaseRealtime = 0x%8.8X, SecondsRunningRealTime = 0x%8.8X, SecondsRunningSimulationTime = 0x%8.8X.\n",
							(unsigned) NowRealTime, (unsigned) BaseRealTime, SecondsRunningRealTime, SecondsRunningSimulationTime);
				printf ("> SecondsRunningDifference = 0x%8.8X, ExpectedRunningDifference = 0x%8.8X.\n",
							SecondsRunningDifference, ExpectedRunningDifference);
				}

			if  (SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK)
				{
				if  (StabilityCount < MINIMUM_STABILITY_COUNT)
					{
					if  (StabilityCount == 0)
						{
						ExpectedRunningDifference = SecondsRunningDifference;
						StabilityCount++;
						if  (Debug)
							printf ("> Starting stability check.\n");
						}
					else
						{	// Else for "if  (StabilityCount == 0)"
						if  ((ExpectedRunningDifference+INITIAL_STABILITY_BAND > SecondsRunningDifference)
								&& (ExpectedRunningDifference-INITIAL_STABILITY_BAND < SecondsRunningDifference))
							{	// So far, still within stability band, increment count.
							StabilityCount++;
							if  (Debug)
								printf ("> StabilityCount = %d.\n", StabilityCount);
							}
						else
							{	// Outside of stability band, start over.
							StabilityCount = 0;
							if  (Debug)
								printf ("> Out of stability band, start over.\n");
							}
						} // End of else for "if  (StabilityCount == 0)"
					}	// End of true clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))"
				else
					{	// Else clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))" - OK, so we are supposed to be stable.
					if  (AddCycle)
						{
						if  (ExpectedRunningDifference >= SecondsRunningDifference)
							{
							if  (Debug)
								printf ("> Was adding cycles, ExpectedRunningDifference >= SecondsRunningDifference, can stop it now.\n");

							AddCycle = FALSE;
							RemoveCycle = FALSE;
							}
						else
							{
							if  (Debug)
								printf ("> Was adding cycles, not done yet.\n");
							}
						}
					else
						{
						if  (RemoveCycle)
							{
							if  (ExpectedRunningDifference <= SecondsRunningDifference)
								{
								if  (Debug)
									printf ("> Was removing cycles, ExpectedRunningDifference <= SecondsRunningDifference, can stop it now.\n");

								AddCycle = FALSE;
								RemoveCycle = FALSE;
								}
							else
								{
								if  (Debug)
									printf ("> Was removing cycles, not done yet.\n");
								}
							}
						else
							{
							if  ((ExpectedRunningDifference+RUNNING_STABILITY_BAND > SecondsRunningDifference)
									&& (ExpectedRunningDifference-RUNNING_STABILITY_BAND < SecondsRunningDifference))
								{	// All is well, within tolerances.
								if  (Debug)
									printf ("> All is well, within tolerances.\n");
								}
							else
								{	// Oops, outside tolerances.  Else clause of "if  ((ExpectedRunningDifference...SecondsRunningDifference)"
								if  (ExpectedRunningDifference > SecondsRunningDifference)
									{
									if  (Debug)
										printf ("> ExpectedRunningDifference > SecondsRunningDifference, running behind real time.\n");

									// Behind real time, have to add a cycle to slow down and get back in sync.
									AddCycle = FALSE;
									RemoveCycle = TRUE;
									}
								else
									{	// Else clause of "if  (ExpectedRunningDifference < SecondsRunningDifference)"
									if  (ExpectedRunningDifference < SecondsRunningDifference)
										{
										if  (Debug)
											printf ("> ExpectedRunningDifference < SecondsRunningDifference, running ahead of real time.\n");

										// Ahead of real time, have to remove a cycle to speed up and get back in sync.
										AddCycle = TRUE;
										RemoveCycle = FALSE;
										}
									else
										{
										if  (Debug)
											printf ("> Oops, outside tolerances, but doesn't fit the profiles, how can this be?\n");
										}
									}	// End of else clause of "if  (ExpectedRunningDifference > SecondsRunningDifference)"
								}	// End of else clause of "if  ((ExpectedRunningDifference...SecondsRunningDifference)"
							}	// End of else clause of "if  (RemoveCycle)".
						}	// End of else clause of "if  (AddCycle)".
					}	// End of else clause for "if  (StabilityCount < MINIMUM_STABILITY_COUNT))"
				}	// End of true clause for "if  ((SecondsRunningSimulationTime > RUN_BEFORE_STABILITY_CHECK)"
			}	// End of true clause for "if  (NowRealTime >= BaseRealTime)"
		else
			{
			if  (Debug)
				printf ("> Hmm, time going backwards?\n");
			}
		}	// End of true clause for "if  (EnableRateCorrection)"
		
	fflush (stdout);
	}
	
	
printf ("\n\n>> Completed %d seconds, exiting...\n\n", SecondsToSend);
return (0);
}


/*
 * Generate WWV/H 0 or 1 data pulse.
 */
void WWV_Second(
	int	code,		/* DATA0, DATA1, PI */
	int Rate		/* <0 -> do a short second, 0 -> normal second, >0 -> long second */
	)
{
	/*
	 * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
	 * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
	 * 100 Hz corresponding to 0, 1 or position indicator (PI),
	 * respectively. Note the 100-Hz data pulses are transmitted 6
	 * dB below the 1000-Hz sync pulses. Originally the data pulses
	 * were transmited 10 dB below the sync pulses, but the station
	 * engineers increased that to 6 dB because the Heath GC-1000
	 * WWV/H radio clock worked much better.
	 */
	peep(5, tone, HIGH);		/* send seconds tick */
	peep(25, tone, OFF);
	peep(code - 30, 100, LOW);	/* send data */
	
	/* The quiet time is shortened or lengthened to get us back on time */
	if  (Rate < 0)
		{
		peep( 990 - code, 100, OFF);
		
		TotalCyclesRemoved += 10;

		if  (Debug)
			printf ("\n* Shorter Second: ");
		}
	else
		{
		if  (Rate > 0)
			{
			peep(1010 - code, 100, OFF);

			TotalCyclesAdded += 10;

			if  (Debug)
				printf ("\n* Longer Second: ");
			}
		else
			peep(1000 - code, 100, OFF);
		}
}

/*
 * Generate WWV/H 0 or 1 data pulse, with no tick, for 29th and 59th seconds
 */
void WWV_SecondNoTick(
	int	code,		/* DATA0, DATA1, PI */
	int Rate		/* <0 -> do a short second, 0 -> normal second, >0 -> long second */
	)
{
	/*
	 * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
	 * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
	 * 100 Hz corresponding to 0, 1 or position indicator (PI),
	 * respectively. Note the 100-Hz data pulses are transmitted 6
	 * dB below the 1000-Hz sync pulses. Originally the data pulses
	 * were transmited 10 dB below the sync pulses, but the station
	 * engineers increased that to 6 dB because the Heath GC-1000
	 * WWV/H radio clock worked much better.
	 */
	peep(30, tone, OFF);		/* send seconds non-tick */
	peep(code - 30, 100, LOW);	/* send data */

	/* The quiet time is shortened or lengthened to get us back on time */
	if  (Rate < 0)
		{
		peep( 990 - code, 100, OFF);

		TotalCyclesRemoved += 10;

		if  (Debug)
			printf ("\n* Shorter Second: ");
		}
	else
		{
		if  (Rate > 0)
			{
			peep(1010 - code, 100, OFF);

			TotalCyclesAdded += 10;

			if  (Debug)
				printf ("\n* Longer Second: ");
			}
		else
			peep(1000 - code, 100, OFF);
		}
}

/*
 * Generate cycles of 100 Hz or any multiple of 100 Hz.
 */
void peep(
	int	pulse,		/* pulse length (ms) */
	int	freq,		/* frequency (Hz) */
	int	amp		/* amplitude */
	)
{
	int	increm;		/* phase increment */
	int	i, j;

	if (amp == OFF || freq == 0)
		increm = 10;
	else
		increm = freq / 100;
	j = 0;
	for (i = 0 ; i < pulse * 8; i++) {
		switch (amp) {

		case HIGH:
			buffer[bufcnt++] = ~c6000[j];
			break;

		case LOW:
			buffer[bufcnt++] = ~c3000[j];
			break;

		default:
			buffer[bufcnt++] = ~0;
		}
		if (bufcnt >= BUFLNG) {
			write(fd, buffer, BUFLNG);
			bufcnt = 0;
		}
		j = (j + increm) % 80;
	}
}


/*
 * Generate unmodulated from similar tables.
 */
void poop(
	int	pulse,		/* pulse length (ms) */
	int	freq,		/* frequency (Hz) */
	int	amp,		/* amplitude */
	int inverted	/* is upside down */
	)
{
	int	increm;		/* phase increment */
	int	i, j;

	if (amp == OFF || freq == 0)
		increm = 10;
	else
		increm = freq / 100;
	j = 0;
	for (i = 0 ; i < pulse * 8; i++) {
		switch (amp) {

		case HIGH:
			if  (inverted)
				buffer[bufcnt++] = ~u3000[j];
			else
				buffer[bufcnt++] = ~u6000[j];
			break;

		case LOW:
			if  (inverted)
				buffer[bufcnt++] = ~u6000[j];
			else
				buffer[bufcnt++] = ~u3000[j];
			break;

		default:
			buffer[bufcnt++] = ~0;
		}
		if (bufcnt >= BUFLNG) {
			write(fd, buffer, BUFLNG);
			bufcnt = 0;
		}
		j = (j + increm) % 80;
	}
}

/*
 * Delay for initial phasing
 */
void delay (
	int	Delay		/* delay in samples */
	)
{
	int	samples;	/* samples remaining */

	samples = Delay;
	memset(buffer, 0, BUFLNG);
	while (samples >= BUFLNG) {
		write(fd, buffer, BUFLNG);
		samples -= BUFLNG;
	}
		write(fd, buffer, samples);
}


/* Calc day of year from year month & day */
/* Year - 0 means 2000, 100 means 2100. */
/* Month - 1 means January, 12 means December. */
/* DayOfMonth - 1 is first day of month */
int
ConvertMonthDayToDayOfYear (int YearValue, int MonthValue, int DayOfMonthValue)
	{
	int	ReturnValue;
	int	LeapYear;
	int	MonthCounter;

	/* Array of days in a month.  Note that here January is zero. */
	/* NB: have to add 1 to days in February in a leap year! */
	int DaysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};


	LeapYear = FALSE;
	if  ((YearValue % 4) == 0)
		{
		if  ((YearValue % 100) == 0)
			{
			if  ((YearValue % 400) == 0)
				{
				LeapYear = TRUE;
				}
			}
		else
			{
			LeapYear = TRUE;
			}
		}

	if  (Debug)
		printf ("\nConvertMonthDayToDayOfYear(): Year %d %s a leap year.\n", YearValue+2000, LeapYear ? "is" : "is not");

	/* Day of month given us starts in this algorithm. */
	ReturnValue = DayOfMonthValue;

	/* Add in days in month for each month past January. */
	for (MonthCounter=1; MonthCounter<MonthValue; MonthCounter++)
		{
		ReturnValue += DaysInMonth [ MonthCounter - 1 ];
		}

	/* Add a day for leap years where we are past February. */
	if  ((LeapYear) && (MonthValue > 2))
		{
		ReturnValue++;
		}

	if  (Debug)
		printf ("\nConvertMonthDayToDayOfYear(): %4.4d-%2.2d-%2.2d represents day %3d of year.\n",
				YearValue+2000, MonthValue, DayOfMonthValue, ReturnValue);

	return (ReturnValue);
	}


void
Help ( void )
	{
	printf ("\n\nTime Code Generation - IRIG-B or WWV, v%d.%d, %s dmw", VERSION, ISSUE, ISSUE_DATE);
	printf ("\n\nRCS Info:");
	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 $");
	printf ("\n\nUsage: %s [option]*", CommandName);
	printf ("\n\nOptions: -a device_name                 Output audio device name (default /dev/audio)");
	printf (  "\n         -b yymmddhhmm                  Remove leap second at end of minute specified");
	printf (  "\n         -c seconds_to_send             Number of seconds to send (default 0 = forever)");
	printf (  "\n         -d                             Start with IEEE 1344 DST active");
	printf (  "\n         -f format_type                 i = Modulated IRIG-B 1998 (no year coded)");
	printf (  "\n                                        2 = Modulated IRIG-B 2002 (year coded)");
	printf (  "\n                                        3 = Modulated IRIG-B w/IEEE 1344 (year & control funcs) (default)");
	printf (  "\n                                        4 = Unmodulated IRIG-B w/IEEE 1344 (year & control funcs)");
	printf (  "\n                                        5 = Inverted unmodulated IRIG-B w/IEEE 1344 (year & control funcs)");
	printf (  "\n                                        w = WWV(H)");
	printf (  "\n         -g yymmddhhmm                  Switch into/out of DST at beginning of minute specified");
	printf (  "\n         -i yymmddhhmm                  Insert leap second at end of minute specified");
	printf (  "\n         -j                             Disable time rate correction against system clock (default enabled)");
	printf (  "\n         -k nn                          Force rate correction for testing (+1 = add cycle, -1 = remove cycle)");
	printf (  "\n         -l time_offset                 Set offset of time sent to UTC as per computer, +/- float hours");
	printf (  "\n         -o time_offset                 Set IEEE 1344 time offset, +/-, to 0.5 hour (default 0)");
	printf (  "\n         -q quality_code_hex            Set IEEE 1344 quality code (default 0)");
	printf (  "\n         -r sample_rate                 Audio sample rate (default 8000)");
	printf (  "\n         -s                             Set leap warning bit (WWV[H] only)");
	printf (  "\n         -t sync_frequency              WWV(H) on-time pulse tone frequency (default 1200)");
	printf (  "\n         -u DUT1_offset                 Set WWV(H) DUT1 offset -7 to +7 (default 0)");
#ifndef  HAVE_SYS_SOUNDCARD_H
	printf (  "\n         -v initial_output_level        Set initial output level (default %d, must be 0 to 255)", AUDIO_MAX_GAIN/8);
#endif
	printf (  "\n         -x                             Turn off verbose output (default on)");
	printf (  "\n         -y yymmddhhmmss                Set initial date and time as specified (default system time)");
	printf ("\n\nThis software licenced under the GPL, modifications performed 2006 & 2007 by Dean Weiten");
	printf (  "\nContact: Dean Weiten, Norscan Instruments Ltd., Winnipeg, MB, Canada, ph (204)-233-9138, E-mail dmw@norscan.com");
	printf ("\n\n");
	}

/* Reverse string order for nicer print. */
void
ReverseString(char *str)
	{
	int		StringLength;
	int		IndexCounter;
	int		CentreOfString;
	char	TemporaryCharacter;


	StringLength	= strlen(str);
	CentreOfString	= (StringLength/2)+1;
	for (IndexCounter = StringLength; IndexCounter >= CentreOfString; IndexCounter--)
		{
		TemporaryCharacter				= str[IndexCounter-1];
		str[IndexCounter-1]				= str[StringLength-IndexCounter];
		str[StringLength-IndexCounter]	= TemporaryCharacter;
		}
	}