tg.c revision 1.1.1.1.12.1 1 1.1 kardel /* $NetBSD: tg.c,v 1.1.1.1.12.1 2014/08/19 23:51:49 tls Exp $ */
2 1.1 kardel
3 1.1 kardel /*
4 1.1 kardel * tg.c generate WWV or IRIG signals for test
5 1.1 kardel */
6 1.1 kardel /*
7 1.1 kardel * This program can generate audio signals that simulate the WWV/H
8 1.1 kardel * broadcast timecode. Alternatively, it can generate the IRIG-B
9 1.1 kardel * timecode commonly used to synchronize laboratory equipment. It is
10 1.1 kardel * intended to test the WWV/H driver (refclock_wwv.c) and the IRIG
11 1.1 kardel * driver (refclock_irig.c) in the NTP driver collection.
12 1.1 kardel *
13 1.1 kardel * Besides testing the drivers themselves, this program can be used to
14 1.1 kardel * synchronize remote machines over audio transmission lines or program
15 1.1 kardel * feeds. The program reads the time on the local machine and sets the
16 1.1 kardel * initial epoch of the signal generator within one millisecond.
17 1.1 kardel * Alernatively, the initial epoch can be set to an arbitrary time. This
18 1.1 kardel * is useful when searching for bugs and testing for correct response to
19 1.1 kardel * a leap second in UTC. Note however, the ultimate accuracy is limited
20 1.1 kardel * by the intrinsic frequency error of the codec sample clock, which can
21 1.1 kardel # reach well over 100 PPM.
22 1.1 kardel *
23 1.1 kardel * The default is to route generated signals to the line output
24 1.1 kardel * jack; the s option on the command line routes these signals to the
25 1.1 kardel * internal speaker as well. The v option controls the speaker volume
26 1.1 kardel * over the range 0-255. The signal generator by default uses WWV
27 1.1 kardel * format; the h option switches to WWVH format and the i option
28 1.1 kardel * switches to IRIG-B format.
29 1.1 kardel *
30 1.1 kardel * Once started the program runs continuously. The default initial epoch
31 1.1 kardel * for the signal generator is read from the computer system clock when
32 1.1 kardel * the program starts. The y option specifies an alternate epoch using a
33 1.1 kardel * string yydddhhmmss, where yy is the year of century, ddd the day of
34 1.1 kardel * year, hh the hour of day and mm the minute of hour. For instance,
35 1.1 kardel * 1946Z on 1 January 2006 is 060011946. The l option lights the leap
36 1.1 kardel * warning bit in the WWV/H timecode, so is handy to check for correct
37 1.1 kardel * behavior at the next leap second epoch. The remaining options are
38 1.1 kardel * specified below under the Parse Options heading. Most of these are
39 1.1 kardel * for testing.
40 1.1 kardel *
41 1.1 kardel * During operation the program displays the WWV/H timecode (9 digits)
42 1.1 kardel * or IRIG timecode (20 digits) as each new string is constructed. The
43 1.1 kardel * display is followed by the BCD binary bits as transmitted. Note that
44 1.1 kardel * the transmissionorder is low-order first as the frame is processed
45 1.1 kardel * left to right. For WWV/H The leap warning L preceeds the first bit.
46 1.1 kardel * For IRIG the on-time marker M preceeds the first (units) bit, so its
47 1.1 kardel * code is delayed one bit and the next digit (tens) needs only three
48 1.1 kardel * bits.
49 1.1 kardel *
50 1.1 kardel * The program has been tested with the Sun Blade 1500 running Solaris
51 1.1 kardel * 10, but not yet with other machines. It uses no special features and
52 1.1 kardel * should be readily portable to other hardware and operating systems.
53 1.1 kardel */
54 1.1 kardel #include <stdio.h>
55 1.1 kardel #include <stdlib.h>
56 1.1 kardel #include <time.h>
57 1.1 kardel #include <sys/audio.h>
58 1.1 kardel #include <math.h>
59 1.1 kardel #include <errno.h>
60 1.1 kardel #include <sys/types.h>
61 1.1 kardel #include <sys/stat.h>
62 1.1 kardel #include <fcntl.h>
63 1.1 kardel #include <string.h>
64 1.1 kardel #include <unistd.h>
65 1.1 kardel
66 1.1 kardel #define SECOND 8000 /* one second of 125-us samples */
67 1.1 kardel #define BUFLNG 400 /* buffer size */
68 1.1 kardel #define DEVICE "/dev/audio" /* default audio device */
69 1.1 kardel #define WWV 0 /* WWV encoder */
70 1.1 kardel #define IRIG 1 /* IRIG-B encoder */
71 1.1 kardel #define OFF 0 /* zero amplitude */
72 1.1 kardel #define LOW 1 /* low amplitude */
73 1.1 kardel #define HIGH 2 /* high amplitude */
74 1.1 kardel #define DATA0 200 /* WWV/H 0 pulse */
75 1.1 kardel #define DATA1 500 /* WWV/H 1 pulse */
76 1.1 kardel #define PI 800 /* WWV/H PI pulse */
77 1.1 kardel #define M2 2 /* IRIG 0 pulse */
78 1.1 kardel #define M5 5 /* IRIG 1 pulse */
79 1.1 kardel #define M8 8 /* IRIG PI pulse */
80 1.1 kardel
81 1.1 kardel /*
82 1.1 kardel * Companded sine table amplitude 3000 units
83 1.1 kardel */
84 1.1 kardel int c3000[] = {1, 48, 63, 70, 78, 82, 85, 89, 92, 94, /* 0-9 */
85 1.1 kardel 96, 98, 99, 100, 101, 101, 102, 103, 103, 103, /* 10-19 */
86 1.1 kardel 103, 103, 103, 103, 102, 101, 101, 100, 99, 98, /* 20-29 */
87 1.1 kardel 96, 94, 92, 89, 85, 82, 78, 70, 63, 48, /* 30-39 */
88 1.1 kardel 129, 176, 191, 198, 206, 210, 213, 217, 220, 222, /* 40-49 */
89 1.1 kardel 224, 226, 227, 228, 229, 229, 230, 231, 231, 231, /* 50-59 */
90 1.1 kardel 231, 231, 231, 231, 230, 229, 229, 228, 227, 226, /* 60-69 */
91 1.1 kardel 224, 222, 220, 217, 213, 210, 206, 198, 191, 176}; /* 70-79 */
92 1.1 kardel /*
93 1.1 kardel * Companded sine table amplitude 6000 units
94 1.1 kardel */
95 1.1 kardel int c6000[] = {1, 63, 78, 86, 93, 98, 101, 104, 107, 110, /* 0-9 */
96 1.1 kardel 112, 113, 115, 116, 117, 117, 118, 118, 119, 119, /* 10-19 */
97 1.1 kardel 119, 119, 119, 118, 118, 117, 117, 116, 115, 113, /* 20-29 */
98 1.1 kardel 112, 110, 107, 104, 101, 98, 93, 86, 78, 63, /* 30-39 */
99 1.1 kardel 129, 191, 206, 214, 221, 226, 229, 232, 235, 238, /* 40-49 */
100 1.1 kardel 240, 241, 243, 244, 245, 245, 246, 246, 247, 247, /* 50-59 */
101 1.1 kardel 247, 247, 247, 246, 246, 245, 245, 244, 243, 241, /* 60-69 */
102 1.1 kardel 240, 238, 235, 232, 229, 226, 221, 214, 206, 191}; /* 70-79 */
103 1.1 kardel
104 1.1 kardel /*
105 1.1 kardel * Decoder operations at the end of each second are driven by a state
106 1.1 kardel * machine. The transition matrix consists of a dispatch table indexed
107 1.1 kardel * by second number. Each entry in the table contains a case switch
108 1.1 kardel * number and argument.
109 1.1 kardel */
110 1.1 kardel struct progx {
111 1.1 kardel int sw; /* case switch number */
112 1.1 kardel int arg; /* argument */
113 1.1 kardel };
114 1.1 kardel
115 1.1 kardel /*
116 1.1 kardel * Case switch numbers
117 1.1 kardel */
118 1.1 kardel #define DATA 0 /* send data (0, 1, PI) */
119 1.1 kardel #define COEF 1 /* send BCD bit */
120 1.1 kardel #define DEC 2 /* decrement to next digit */
121 1.1 kardel #define MIN 3 /* minute pulse */
122 1.1 kardel #define LEAP 4 /* leap warning */
123 1.1 kardel #define DUT1 5 /* DUT1 bits */
124 1.1 kardel #define DST1 6 /* DST1 bit */
125 1.1 kardel #define DST2 7 /* DST2 bit */
126 1.1 kardel
127 1.1 kardel /*
128 1.1 kardel * WWV/H format (100-Hz, 9 digits, 1 m frame)
129 1.1 kardel */
130 1.1 kardel struct progx progx[] = {
131 1.1 kardel {MIN, 800}, /* 0 minute sync pulse */
132 1.1 kardel {DATA, DATA0}, /* 1 */
133 1.1 kardel {DST2, 0}, /* 2 DST2 */
134 1.1 kardel {LEAP, 0}, /* 3 leap warning */
135 1.1 kardel {COEF, 1}, /* 4 1 year units */
136 1.1 kardel {COEF, 2}, /* 5 2 */
137 1.1 kardel {COEF, 4}, /* 6 4 */
138 1.1 kardel {COEF, 8}, /* 7 8 */
139 1.1 kardel {DEC, DATA0}, /* 8 */
140 1.1 kardel {DATA, PI}, /* 9 p1 */
141 1.1 kardel {COEF, 1}, /* 10 1 minute units */
142 1.1 kardel {COEF, 2}, /* 11 2 */
143 1.1 kardel {COEF, 4}, /* 12 4 */
144 1.1 kardel {COEF, 8}, /* 13 8 */
145 1.1 kardel {DEC, DATA0}, /* 14 */
146 1.1 kardel {COEF, 1}, /* 15 10 minute tens */
147 1.1 kardel {COEF, 2}, /* 16 20 */
148 1.1 kardel {COEF, 4}, /* 17 40 */
149 1.1 kardel {COEF, 8}, /* 18 80 (not used) */
150 1.1 kardel {DEC, PI}, /* 19 p2 */
151 1.1 kardel {COEF, 1}, /* 20 1 hour units */
152 1.1 kardel {COEF, 2}, /* 21 2 */
153 1.1 kardel {COEF, 4}, /* 22 4 */
154 1.1 kardel {COEF, 8}, /* 23 8 */
155 1.1 kardel {DEC, DATA0}, /* 24 */
156 1.1 kardel {COEF, 1}, /* 25 10 hour tens */
157 1.1 kardel {COEF, 2}, /* 26 20 */
158 1.1 kardel {COEF, 4}, /* 27 40 (not used) */
159 1.1 kardel {COEF, 8}, /* 28 80 (not used) */
160 1.1 kardel {DEC, PI}, /* 29 p3 */
161 1.1 kardel {COEF, 1}, /* 30 1 day units */
162 1.1 kardel {COEF, 2}, /* 31 2 */
163 1.1 kardel {COEF, 4}, /* 32 4 */
164 1.1 kardel {COEF, 8}, /* 33 8 */
165 1.1 kardel {DEC, DATA0}, /* 34 not used */
166 1.1 kardel {COEF, 1}, /* 35 10 day tens */
167 1.1 kardel {COEF, 2}, /* 36 20 */
168 1.1 kardel {COEF, 4}, /* 37 40 */
169 1.1 kardel {COEF, 8}, /* 38 80 */
170 1.1 kardel {DEC, PI}, /* 39 p4 */
171 1.1 kardel {COEF, 1}, /* 40 100 day hundreds */
172 1.1 kardel {COEF, 2}, /* 41 200 */
173 1.1 kardel {COEF, 4}, /* 42 400 (not used) */
174 1.1 kardel {COEF, 8}, /* 43 800 (not used) */
175 1.1 kardel {DEC, DATA0}, /* 44 */
176 1.1 kardel {DATA, DATA0}, /* 45 */
177 1.1 kardel {DATA, DATA0}, /* 46 */
178 1.1 kardel {DATA, DATA0}, /* 47 */
179 1.1 kardel {DATA, DATA0}, /* 48 */
180 1.1 kardel {DATA, PI}, /* 49 p5 */
181 1.1 kardel {DUT1, 8}, /* 50 DUT1 sign */
182 1.1 kardel {COEF, 1}, /* 51 10 year tens */
183 1.1 kardel {COEF, 2}, /* 52 20 */
184 1.1 kardel {COEF, 4}, /* 53 40 */
185 1.1 kardel {COEF, 8}, /* 54 80 */
186 1.1 kardel {DST1, 0}, /* 55 DST1 */
187 1.1 kardel {DUT1, 1}, /* 56 0.1 DUT1 fraction */
188 1.1 kardel {DUT1, 2}, /* 57 0.2 */
189 1.1 kardel {DUT1, 4}, /* 58 0.4 */
190 1.1 kardel {DATA, PI}, /* 59 p6 */
191 1.1 kardel {DATA, DATA0}, /* 60 leap */
192 1.1 kardel };
193 1.1 kardel
194 1.1 kardel /*
195 1.1 kardel * IRIG format except first frame (1000 Hz, 20 digits, 1 s frame)
196 1.1 kardel */
197 1.1 kardel struct progx progy[] = {
198 1.1 kardel {COEF, 1}, /* 0 1 units */
199 1.1 kardel {COEF, 2}, /* 1 2 */
200 1.1 kardel {COEF, 4}, /* 2 4 */
201 1.1 kardel {COEF, 8}, /* 3 8 */
202 1.1 kardel {DEC, M2}, /* 4 im */
203 1.1 kardel {COEF, 1}, /* 5 10 tens */
204 1.1 kardel {COEF, 2}, /* 6 20 */
205 1.1 kardel {COEF, 4}, /* 7 40 */
206 1.1 kardel {COEF, 8}, /* 8 80 */
207 1.1 kardel {DEC, M8}, /* 9 pi */
208 1.1 kardel };
209 1.1 kardel
210 1.1 kardel /*
211 1.1 kardel * IRIG format first frame (1000 Hz, 20 digits, 1 s frame)
212 1.1 kardel */
213 1.1 kardel struct progx progz[] = {
214 1.1 kardel {MIN, M8}, /* 0 pi (second) */
215 1.1 kardel {COEF, 1}, /* 1 1 units */
216 1.1 kardel {COEF, 2}, /* 2 2 */
217 1.1 kardel {COEF, 4}, /* 3 4 */
218 1.1 kardel {COEF, 8}, /* 4 8 */
219 1.1 kardel {DEC, M2}, /* 5 im */
220 1.1 kardel {COEF, 1}, /* 6 10 tens */
221 1.1 kardel {COEF, 2}, /* 7 20 */
222 1.1 kardel {COEF, 4}, /* 8 40 */
223 1.1 kardel {DEC, M8}, /* 9 pi */
224 1.1 kardel };
225 1.1 kardel
226 1.1 kardel /*
227 1.1 kardel * Forward declarations
228 1.1 kardel */
229 1.1 kardel void sec(int); /* send second */
230 1.1 kardel void digit(int); /* encode digit */
231 1.1 kardel void peep(int, int, int); /* send cycles */
232 1.1 kardel void delay(int); /* delay samples */
233 1.1 kardel
234 1.1 kardel /*
235 1.1 kardel * Global variables
236 1.1 kardel */
237 1.1 kardel char buffer[BUFLNG]; /* output buffer */
238 1.1 kardel int bufcnt = 0; /* buffer counter */
239 1.1 kardel int second = 0; /* seconds counter */
240 1.1 kardel int fd; /* audio codec file descriptor */
241 1.1 kardel int tone = 1000; /* WWV sync frequency */
242 1.1 kardel int level = AUDIO_MAX_GAIN / 8; /* output level */
243 1.1 kardel int port = AUDIO_LINE_OUT; /* output port */
244 1.1 kardel int encode = WWV; /* encoder select */
245 1.1 kardel int leap = 0; /* leap indicator */
246 1.1 kardel int dst = 0; /* winter/summer time */
247 1.1 kardel int dut1 = 0; /* DUT1 correction (sign, magnitude) */
248 1.1 kardel int utc = 0; /* option epoch */
249 1.1 kardel
250 1.1 kardel /*
251 1.1 kardel * Main program
252 1.1 kardel */
253 1.1 kardel int
254 1.1 kardel main(
255 1.1 kardel int argc, /* command line options */
256 1.1 kardel char **argv /* poiniter to list of tokens */
257 1.1 kardel )
258 1.1 kardel {
259 1.1 kardel struct timeval tv; /* system clock at startup */
260 1.1 kardel audio_info_t info; /* Sun audio structure */
261 1.1 kardel struct tm *tm = NULL; /* structure returned by gmtime */
262 1.1 kardel char device[50]; /* audio device */
263 1.1 kardel char code[100]; /* timecode */
264 1.1 kardel int rval, temp, arg, sw, ptr;
265 1.1 kardel int minute, hour, day, year;
266 1.1 kardel int i;
267 1.1 kardel
268 1.1 kardel /*
269 1.1 kardel * Parse options
270 1.1 kardel */
271 1.1.1.1.12.1 tls strlcpy(device, DEVICE, sizeof(device));
272 1.1 kardel year = 0;
273 1.1 kardel while ((temp = getopt(argc, argv, "a:dhilsu:v:y:")) != -1) {
274 1.1 kardel switch (temp) {
275 1.1 kardel
276 1.1 kardel case 'a': /* specify audio device (/dev/audio) */
277 1.1.1.1.12.1 tls strlcpy(device, optarg, sizeof(device));
278 1.1 kardel break;
279 1.1 kardel
280 1.1 kardel case 'd': /* set DST for summer (WWV/H only) */
281 1.1 kardel dst++;
282 1.1 kardel break;
283 1.1 kardel
284 1.1 kardel case 'h': /* select WWVH sync frequency */
285 1.1 kardel tone = 1200;
286 1.1 kardel break;
287 1.1 kardel
288 1.1 kardel case 'i': /* select irig format */
289 1.1 kardel encode = IRIG;
290 1.1 kardel break;
291 1.1 kardel
292 1.1 kardel case 'l': /* set leap warning bit (WWV/H only) */
293 1.1 kardel leap++;
294 1.1 kardel break;
295 1.1 kardel
296 1.1 kardel case 's': /* enable speaker */
297 1.1 kardel port |= AUDIO_SPEAKER;
298 1.1 kardel break;
299 1.1 kardel
300 1.1 kardel case 'u': /* set DUT1 offset (-7 to +7) */
301 1.1 kardel sscanf(optarg, "%d", &dut1);
302 1.1 kardel if (dut1 < 0)
303 1.1 kardel dut1 = abs(dut1);
304 1.1 kardel else
305 1.1 kardel dut1 |= 0x8;
306 1.1 kardel break;
307 1.1 kardel
308 1.1 kardel case 'v': /* set output level (0-255) */
309 1.1 kardel sscanf(optarg, "%d", &level);
310 1.1 kardel break;
311 1.1 kardel
312 1.1 kardel case 'y': /* set initial date and time */
313 1.1 kardel sscanf(optarg, "%2d%3d%2d%2d", &year, &day,
314 1.1 kardel &hour, &minute);
315 1.1 kardel utc++;
316 1.1 kardel break;
317 1.1 kardel
318 1.1 kardel defult:
319 1.1 kardel printf("invalid option %c\n", temp);
320 1.1 kardel break;
321 1.1 kardel }
322 1.1 kardel }
323 1.1 kardel
324 1.1 kardel /*
325 1.1 kardel * Open audio device and set options
326 1.1 kardel */
327 1.1 kardel fd = open("/dev/audio", O_WRONLY);
328 1.1 kardel if (fd <= 0) {
329 1.1 kardel printf("audio open %s\n", strerror(errno));
330 1.1 kardel exit(1);
331 1.1 kardel }
332 1.1 kardel rval = ioctl(fd, AUDIO_GETINFO, &info);
333 1.1 kardel if (rval < 0) {
334 1.1 kardel printf("audio control %s\n", strerror(errno));
335 1.1 kardel exit(0);
336 1.1 kardel }
337 1.1 kardel info.play.port = port;
338 1.1 kardel info.play.gain = level;
339 1.1 kardel info.play.sample_rate = SECOND;
340 1.1 kardel info.play.channels = 1;
341 1.1 kardel info.play.precision = 8;
342 1.1 kardel info.play.encoding = AUDIO_ENCODING_ULAW;
343 1.1 kardel printf("port %d gain %d rate %d chan %d prec %d encode %d\n",
344 1.1 kardel info.play.port, info.play.gain, info.play.sample_rate,
345 1.1 kardel info.play.channels, info.play.precision,
346 1.1 kardel info.play.encoding);
347 1.1 kardel ioctl(fd, AUDIO_SETINFO, &info);
348 1.1 kardel
349 1.1 kardel /*
350 1.1 kardel * Unless specified otherwise, read the system clock and
351 1.1 kardel * initialize the time.
352 1.1 kardel */
353 1.1 kardel if (!utc) {
354 1.1 kardel gettimeofday(&tv, NULL);
355 1.1 kardel tm = gmtime(&tv.tv_sec);
356 1.1 kardel minute = tm->tm_min;
357 1.1 kardel hour = tm->tm_hour;
358 1.1 kardel day = tm->tm_yday + 1;
359 1.1 kardel year = tm->tm_year % 100;
360 1.1 kardel second = tm->tm_sec;
361 1.1 kardel
362 1.1 kardel /*
363 1.1 kardel * Delay the first second so the generator is accurately
364 1.1 kardel * aligned with the system clock within one sample (125
365 1.1 kardel * microseconds ).
366 1.1 kardel */
367 1.1 kardel delay(SECOND - tv.tv_usec * 8 / 1000);
368 1.1 kardel }
369 1.1 kardel memset(code, 0, sizeof(code));
370 1.1 kardel switch (encode) {
371 1.1 kardel
372 1.1 kardel /*
373 1.1 kardel * For WWV/H and default time, carefully set the signal
374 1.1 kardel * generator seconds number to agree with the current time.
375 1.1 kardel */
376 1.1 kardel case WWV:
377 1.1 kardel printf("year %d day %d time %02d:%02d:%02d tone %d\n",
378 1.1 kardel year, day, hour, minute, second, tone);
379 1.1.1.1.12.1 tls snprintf(code, sizeof(code), "%01d%03d%02d%02d%01d",
380 1.1.1.1.12.1 tls year / 10, day, hour, minute, year % 10);
381 1.1 kardel printf("%s\n", code);
382 1.1 kardel ptr = 8;
383 1.1 kardel for (i = 0; i <= second; i++) {
384 1.1 kardel if (progx[i].sw == DEC)
385 1.1 kardel ptr--;
386 1.1 kardel }
387 1.1 kardel break;
388 1.1 kardel
389 1.1 kardel /*
390 1.1 kardel * For IRIG the signal generator runs every second, so requires
391 1.1 kardel * no additional alignment.
392 1.1 kardel */
393 1.1 kardel case IRIG:
394 1.1 kardel printf("sbs %x year %d day %d time %02d:%02d:%02d\n",
395 1.1 kardel 0, year, day, hour, minute, second);
396 1.1 kardel break;
397 1.1 kardel }
398 1.1 kardel
399 1.1 kardel /*
400 1.1 kardel * Run the signal generator to generate new timecode strings
401 1.1 kardel * once per minute for WWV/H and once per second for IRIG.
402 1.1 kardel */
403 1.1 kardel while(1) {
404 1.1 kardel
405 1.1 kardel /*
406 1.1 kardel * Crank the state machine to propagate carries to the
407 1.1 kardel * year of century. Note that we delayed up to one
408 1.1 kardel * second for alignment after reading the time, so this
409 1.1 kardel * is the next second.
410 1.1 kardel */
411 1.1 kardel second = (second + 1) % 60;
412 1.1 kardel if (second == 0) {
413 1.1 kardel minute++;
414 1.1 kardel if (minute >= 60) {
415 1.1 kardel minute = 0;
416 1.1 kardel hour++;
417 1.1 kardel }
418 1.1 kardel if (hour >= 24) {
419 1.1 kardel hour = 0;
420 1.1 kardel day++;
421 1.1 kardel }
422 1.1 kardel
423 1.1 kardel /*
424 1.1 kardel * At year rollover check for leap second.
425 1.1 kardel */
426 1.1 kardel if (day >= (year & 0x3 ? 366 : 367)) {
427 1.1 kardel if (leap) {
428 1.1 kardel sec(DATA0);
429 1.1 kardel printf("\nleap!");
430 1.1 kardel leap = 0;
431 1.1 kardel }
432 1.1 kardel day = 1;
433 1.1 kardel year++;
434 1.1 kardel }
435 1.1 kardel if (encode == WWV) {
436 1.1.1.1.12.1 tls snprintf(code, sizeof(code),
437 1.1.1.1.12.1 tls "%01d%03d%02d%02d%01d", year / 10,
438 1.1.1.1.12.1 tls day, hour, minute, year % 10);
439 1.1 kardel printf("\n%s\n", code);
440 1.1 kardel ptr = 8;
441 1.1 kardel }
442 1.1 kardel }
443 1.1 kardel if (encode == IRIG) {
444 1.1.1.1.12.1 tls snprintf(code, sizeof(code),
445 1.1.1.1.12.1 tls "%04x%04d%06d%02d%02d%02d", 0, year, day,
446 1.1.1.1.12.1 tls hour, minute, second);
447 1.1 kardel printf("%s\n", code);
448 1.1 kardel ptr = 19;
449 1.1 kardel }
450 1.1 kardel
451 1.1 kardel /*
452 1.1 kardel * Generate data for the second
453 1.1 kardel */
454 1.1 kardel switch(encode) {
455 1.1 kardel
456 1.1 kardel /*
457 1.1 kardel * The IRIG second consists of 20 BCD digits of width-
458 1.1 kardel * modulateod pulses at 2, 5 and 8 ms and modulated 50
459 1.1 kardel * percent on the 1000-Hz carrier.
460 1.1 kardel */
461 1.1 kardel case IRIG:
462 1.1 kardel for (i = 0; i < 100; i++) {
463 1.1 kardel if (i < 10) {
464 1.1 kardel sw = progz[i].sw;
465 1.1 kardel arg = progz[i].arg;
466 1.1 kardel } else {
467 1.1 kardel sw = progy[i % 10].sw;
468 1.1 kardel arg = progy[i % 10].arg;
469 1.1 kardel }
470 1.1 kardel switch(sw) {
471 1.1 kardel
472 1.1 kardel case COEF: /* send BCD bit */
473 1.1 kardel if (code[ptr] & arg) {
474 1.1 kardel peep(M5, 1000, HIGH);
475 1.1 kardel peep(M5, 1000, LOW);
476 1.1 kardel printf("1");
477 1.1 kardel } else {
478 1.1 kardel peep(M2, 1000, HIGH);
479 1.1 kardel peep(M8, 1000, LOW);
480 1.1 kardel printf("0");
481 1.1 kardel }
482 1.1 kardel break;
483 1.1 kardel
484 1.1 kardel case DEC: /* send IM/PI bit */
485 1.1 kardel ptr--;
486 1.1 kardel printf(" ");
487 1.1 kardel peep(arg, 1000, HIGH);
488 1.1 kardel peep(10 - arg, 1000, LOW);
489 1.1 kardel break;
490 1.1 kardel
491 1.1 kardel case MIN: /* send data bit */
492 1.1 kardel peep(arg, 1000, HIGH);
493 1.1 kardel peep(10 - arg, 1000, LOW);
494 1.1 kardel printf("M ");
495 1.1 kardel break;
496 1.1 kardel }
497 1.1 kardel if (ptr < 0)
498 1.1 kardel break;
499 1.1 kardel }
500 1.1 kardel printf("\n");
501 1.1 kardel break;
502 1.1 kardel
503 1.1 kardel /*
504 1.1 kardel * The WWV/H second consists of 9 BCD digits of width-
505 1.1 kardel * modulateod pulses 200, 500 and 800 ms at 100-Hz.
506 1.1 kardel */
507 1.1 kardel case WWV:
508 1.1 kardel sw = progx[second].sw;
509 1.1 kardel arg = progx[second].arg;
510 1.1 kardel switch(sw) {
511 1.1 kardel
512 1.1 kardel case DATA: /* send data bit */
513 1.1 kardel sec(arg);
514 1.1 kardel break;
515 1.1 kardel
516 1.1 kardel case COEF: /* send BCD bit */
517 1.1 kardel if (code[ptr] & arg) {
518 1.1 kardel sec(DATA1);
519 1.1 kardel printf("1");
520 1.1 kardel } else {
521 1.1 kardel sec(DATA0);
522 1.1 kardel printf("0");
523 1.1 kardel }
524 1.1 kardel break;
525 1.1 kardel
526 1.1 kardel case LEAP: /* send leap bit */
527 1.1 kardel if (leap) {
528 1.1 kardel sec(DATA1);
529 1.1 kardel printf("L ");
530 1.1 kardel } else {
531 1.1 kardel sec(DATA0);
532 1.1 kardel printf(" ");
533 1.1 kardel }
534 1.1 kardel break;
535 1.1 kardel
536 1.1 kardel case DEC: /* send data bit */
537 1.1 kardel ptr--;
538 1.1 kardel sec(arg);
539 1.1 kardel printf(" ");
540 1.1 kardel break;
541 1.1 kardel
542 1.1 kardel case MIN: /* send minute sync */
543 1.1 kardel peep(arg, tone, HIGH);
544 1.1 kardel peep(1000 - arg, tone, OFF);
545 1.1 kardel break;
546 1.1 kardel
547 1.1 kardel case DUT1: /* send DUT1 bits */
548 1.1 kardel if (dut1 & arg)
549 1.1 kardel sec(DATA1);
550 1.1 kardel else
551 1.1 kardel sec(DATA0);
552 1.1 kardel break;
553 1.1 kardel
554 1.1 kardel case DST1: /* send DST1 bit */
555 1.1 kardel ptr--;
556 1.1 kardel if (dst)
557 1.1 kardel sec(DATA1);
558 1.1 kardel else
559 1.1 kardel sec(DATA0);
560 1.1 kardel printf(" ");
561 1.1 kardel break;
562 1.1 kardel
563 1.1 kardel case DST2: /* send DST2 bit */
564 1.1 kardel if (dst)
565 1.1 kardel sec(DATA1);
566 1.1 kardel else
567 1.1 kardel sec(DATA0);
568 1.1 kardel break;
569 1.1 kardel }
570 1.1 kardel }
571 1.1 kardel }
572 1.1 kardel }
573 1.1 kardel
574 1.1 kardel
575 1.1 kardel /*
576 1.1 kardel * Generate WWV/H 0 or 1 data pulse.
577 1.1 kardel */
578 1.1 kardel void sec(
579 1.1 kardel int code /* DATA0, DATA1, PI */
580 1.1 kardel )
581 1.1 kardel {
582 1.1 kardel /*
583 1.1 kardel * The WWV data pulse begins with 5 ms of 1000 Hz follwed by a
584 1.1 kardel * guard time of 25 ms. The data pulse is 170, 570 or 770 ms at
585 1.1 kardel * 100 Hz corresponding to 0, 1 or position indicator (PI),
586 1.1 kardel * respectively. Note the 100-Hz data pulses are transmitted 6
587 1.1 kardel * dB below the 1000-Hz sync pulses. Originally the data pulses
588 1.1 kardel * were transmited 10 dB below the sync pulses, but the station
589 1.1 kardel * engineers increased that to 6 dB because the Heath GC-1000
590 1.1 kardel * WWV/H radio clock worked much better.
591 1.1 kardel */
592 1.1 kardel peep(5, tone, HIGH); /* send seconds tick */
593 1.1 kardel peep(25, tone, OFF);
594 1.1 kardel peep(code - 30, 100, LOW); /* send data */
595 1.1 kardel peep(1000 - code, 100, OFF);
596 1.1 kardel }
597 1.1 kardel
598 1.1 kardel
599 1.1 kardel /*
600 1.1 kardel * Generate cycles of 100 Hz or any multiple of 100 Hz.
601 1.1 kardel */
602 1.1 kardel void peep(
603 1.1 kardel int pulse, /* pulse length (ms) */
604 1.1 kardel int freq, /* frequency (Hz) */
605 1.1 kardel int amp /* amplitude */
606 1.1 kardel )
607 1.1 kardel {
608 1.1 kardel int increm; /* phase increment */
609 1.1 kardel int i, j;
610 1.1 kardel
611 1.1 kardel if (amp == OFF || freq == 0)
612 1.1 kardel increm = 10;
613 1.1 kardel else
614 1.1 kardel increm = freq / 100;
615 1.1 kardel j = 0;
616 1.1 kardel for (i = 0 ; i < pulse * 8; i++) {
617 1.1 kardel switch (amp) {
618 1.1 kardel
619 1.1 kardel case HIGH:
620 1.1 kardel buffer[bufcnt++] = ~c6000[j];
621 1.1 kardel break;
622 1.1 kardel
623 1.1 kardel case LOW:
624 1.1 kardel buffer[bufcnt++] = ~c3000[j];
625 1.1 kardel break;
626 1.1 kardel
627 1.1 kardel default:
628 1.1 kardel buffer[bufcnt++] = ~0;
629 1.1 kardel }
630 1.1 kardel if (bufcnt >= BUFLNG) {
631 1.1 kardel write(fd, buffer, BUFLNG);
632 1.1 kardel bufcnt = 0;
633 1.1 kardel }
634 1.1 kardel j = (j + increm) % 80;
635 1.1 kardel }
636 1.1 kardel }
637 1.1 kardel
638 1.1 kardel
639 1.1 kardel /*
640 1.1 kardel * Delay for initial phasing
641 1.1 kardel */
642 1.1 kardel void delay (
643 1.1 kardel int delay /* delay in samples */
644 1.1 kardel )
645 1.1 kardel {
646 1.1 kardel int samples; /* samples remaining */
647 1.1 kardel
648 1.1 kardel samples = delay;
649 1.1 kardel memset(buffer, 0, BUFLNG);
650 1.1 kardel while (samples >= BUFLNG) {
651 1.1 kardel write(fd, buffer, BUFLNG);
652 1.1 kardel samples -= BUFLNG;
653 1.1 kardel }
654 1.1 kardel write(fd, buffer, samples);
655 1.1 kardel }
656