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