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