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