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