/contrib/ntp/util/tg.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 652 lines · 447 code · 54 blank · 151 comment · 46 complexity · d44a9df95206d1171eac526a84d636d7 MD5 · raw file

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