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