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