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