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