/contrib/ntp/parseutil/testdcf.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 540 lines · 359 code · 60 blank · 121 comment · 53 complexity · d97289c34e349aecdde6dd00bcc9e5c1 MD5 · raw file

  1. /*
  2. * /src/NTP/ntp4-dev/parseutil/testdcf.c,v 4.10 2005/08/06 14:18:43 kardel RELEASE_20050806_A
  3. *
  4. * testdcf.c,v 4.10 2005/08/06 14:18:43 kardel RELEASE_20050806_A
  5. *
  6. * simple DCF77 100/200ms pulse test program (via 50Baud serial line)
  7. *
  8. * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
  9. * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * 3. Neither the name of the author nor the names of its contributors
  20. * may be used to endorse or promote products derived from this software
  21. * without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  27. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33. * SUCH DAMAGE.
  34. *
  35. */
  36. #include "ntp_stdlib.h"
  37. #include <sys/ioctl.h>
  38. #include <unistd.h>
  39. #include <stdio.h>
  40. #include <fcntl.h>
  41. #include <termios.h>
  42. /*
  43. * state flags
  44. */
  45. #define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */
  46. #define DCFB_DST 0x0002 /* DST in effect */
  47. #define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurrence) */
  48. #define DCFB_ALTERNATE 0x0008 /* alternate antenna used */
  49. struct clocktime /* clock time broken up from time code */
  50. {
  51. long wday;
  52. long day;
  53. long month;
  54. long year;
  55. long hour;
  56. long minute;
  57. long second;
  58. long usecond;
  59. long utcoffset; /* in minutes */
  60. long flags; /* current clock status */
  61. };
  62. typedef struct clocktime clocktime_t;
  63. static char type(unsigned int);
  64. #define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1))
  65. /*
  66. * parser related return/error codes
  67. */
  68. #define CVT_MASK 0x0000000F /* conversion exit code */
  69. #define CVT_NONE 0x00000001 /* format not applicable */
  70. #define CVT_FAIL 0x00000002 /* conversion failed - error code returned */
  71. #define CVT_OK 0x00000004 /* conversion succeeded */
  72. #define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */
  73. /*
  74. * DCF77 raw time code
  75. *
  76. * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
  77. * und Berlin, Maerz 1989
  78. *
  79. * Timecode transmission:
  80. * AM:
  81. * time marks are send every second except for the second before the
  82. * next minute mark
  83. * time marks consist of a reduction of transmitter power to 25%
  84. * of the nominal level
  85. * the falling edge is the time indication (on time)
  86. * time marks of a 100ms duration constitute a logical 0
  87. * time marks of a 200ms duration constitute a logical 1
  88. * FM:
  89. * see the spec. (basically a (non-)inverted psuedo random phase shift)
  90. *
  91. * Encoding:
  92. * Second Contents
  93. * 0 - 10 AM: free, FM: 0
  94. * 11 - 14 free
  95. * 15 R - alternate antenna
  96. * 16 A1 - expect zone change (1 hour before)
  97. * 17 - 18 Z1,Z2 - time zone
  98. * 0 0 illegal
  99. * 0 1 MEZ (MET)
  100. * 1 0 MESZ (MED, MET DST)
  101. * 1 1 illegal
  102. * 19 A2 - expect leap insertion/deletion (1 hour before)
  103. * 20 S - start of time code (1)
  104. * 21 - 24 M1 - BCD (lsb first) Minutes
  105. * 25 - 27 M10 - BCD (lsb first) 10 Minutes
  106. * 28 P1 - Minute Parity (even)
  107. * 29 - 32 H1 - BCD (lsb first) Hours
  108. * 33 - 34 H10 - BCD (lsb first) 10 Hours
  109. * 35 P2 - Hour Parity (even)
  110. * 36 - 39 D1 - BCD (lsb first) Days
  111. * 40 - 41 D10 - BCD (lsb first) 10 Days
  112. * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday)
  113. * 45 - 49 MO - BCD (lsb first) Month
  114. * 50 MO0 - 10 Months
  115. * 51 - 53 Y1 - BCD (lsb first) Years
  116. * 54 - 57 Y10 - BCD (lsb first) 10 Years
  117. * 58 P3 - Date Parity (even)
  118. * 59 - usually missing (minute indication), except for leap insertion
  119. */
  120. static char revision[] = "4.10";
  121. static struct rawdcfcode
  122. {
  123. char offset; /* start bit */
  124. } rawdcfcode[] =
  125. {
  126. { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 },
  127. { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 }
  128. };
  129. #define DCF_M 0
  130. #define DCF_R 1
  131. #define DCF_A1 2
  132. #define DCF_Z 3
  133. #define DCF_A2 4
  134. #define DCF_S 5
  135. #define DCF_M1 6
  136. #define DCF_M10 7
  137. #define DCF_P1 8
  138. #define DCF_H1 9
  139. #define DCF_H10 10
  140. #define DCF_P2 11
  141. #define DCF_D1 12
  142. #define DCF_D10 13
  143. #define DCF_DW 14
  144. #define DCF_MO 15
  145. #define DCF_MO0 16
  146. #define DCF_Y1 17
  147. #define DCF_Y10 18
  148. #define DCF_P3 19
  149. static struct partab
  150. {
  151. char offset; /* start bit of parity field */
  152. } partab[] =
  153. {
  154. { 21 }, { 29 }, { 36 }, { 59 }
  155. };
  156. #define DCF_P_P1 0
  157. #define DCF_P_P2 1
  158. #define DCF_P_P3 2
  159. #define DCF_Z_MET 0x2
  160. #define DCF_Z_MED 0x1
  161. static unsigned long
  162. ext_bf(
  163. register unsigned char *buf,
  164. register int idx
  165. )
  166. {
  167. register unsigned long sum = 0;
  168. register int i, first;
  169. first = rawdcfcode[idx].offset;
  170. for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--)
  171. {
  172. sum <<= 1;
  173. sum |= (buf[i] != '-');
  174. }
  175. return sum;
  176. }
  177. static unsigned
  178. pcheck(
  179. register unsigned char *buf,
  180. register int idx
  181. )
  182. {
  183. register int i,last;
  184. register unsigned psum = 1;
  185. last = partab[idx+1].offset;
  186. for (i = partab[idx].offset; i < last; i++)
  187. psum ^= (buf[i] != '-');
  188. return psum;
  189. }
  190. static unsigned long
  191. convert_rawdcf(
  192. register unsigned char *buffer,
  193. register int size,
  194. register clocktime_t *clock_time
  195. )
  196. {
  197. if (size < 57)
  198. {
  199. printf("%-30s", "*** INCOMPLETE");
  200. return CVT_NONE;
  201. }
  202. /*
  203. * check Start and Parity bits
  204. */
  205. if ((ext_bf(buffer, DCF_S) == 1) &&
  206. pcheck(buffer, DCF_P_P1) &&
  207. pcheck(buffer, DCF_P_P2) &&
  208. pcheck(buffer, DCF_P_P3))
  209. {
  210. /*
  211. * buffer OK
  212. */
  213. clock_time->flags = 0;
  214. clock_time->usecond= 0;
  215. clock_time->second = 0;
  216. clock_time->minute = ext_bf(buffer, DCF_M10);
  217. clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1);
  218. clock_time->hour = ext_bf(buffer, DCF_H10);
  219. clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1);
  220. clock_time->day = ext_bf(buffer, DCF_D10);
  221. clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1);
  222. clock_time->month = ext_bf(buffer, DCF_MO0);
  223. clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO);
  224. clock_time->year = ext_bf(buffer, DCF_Y10);
  225. clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1);
  226. clock_time->wday = ext_bf(buffer, DCF_DW);
  227. switch (ext_bf(buffer, DCF_Z))
  228. {
  229. case DCF_Z_MET:
  230. clock_time->utcoffset = -60;
  231. break;
  232. case DCF_Z_MED:
  233. clock_time->flags |= DCFB_DST;
  234. clock_time->utcoffset = -120;
  235. break;
  236. default:
  237. printf("%-30s", "*** BAD TIME ZONE");
  238. return CVT_FAIL|CVT_BADFMT;
  239. }
  240. if (ext_bf(buffer, DCF_A1))
  241. clock_time->flags |= DCFB_ANNOUNCE;
  242. if (ext_bf(buffer, DCF_A2))
  243. clock_time->flags |= DCFB_LEAP;
  244. if (ext_bf(buffer, DCF_R))
  245. clock_time->flags |= DCFB_ALTERNATE;
  246. return CVT_OK;
  247. }
  248. else
  249. {
  250. /*
  251. * bad format - not for us
  252. */
  253. printf("%-30s", "*** BAD FORMAT (invalid/parity)");
  254. return CVT_FAIL|CVT_BADFMT;
  255. }
  256. }
  257. static char
  258. type(
  259. unsigned int c
  260. )
  261. {
  262. c ^= 0xFF;
  263. return (c >= 0xF);
  264. }
  265. static const char *wday[8] =
  266. {
  267. "??",
  268. "Mo",
  269. "Tu",
  270. "We",
  271. "Th",
  272. "Fr",
  273. "Sa",
  274. "Su"
  275. };
  276. static char pat[] = "-\\|/";
  277. #define LINES (24-2) /* error lines after which the two headlines are repeated */
  278. int
  279. main(
  280. int argc,
  281. char *argv[]
  282. )
  283. {
  284. if ((argc != 2) && (argc != 3))
  285. {
  286. fprintf(stderr, "usage: %s [-f|-t|-ft|-tf] <device>\n", argv[0]);
  287. exit(1);
  288. }
  289. else
  290. {
  291. unsigned char c;
  292. char *file;
  293. int fd;
  294. int offset = 15;
  295. int trace = 0;
  296. int errs = LINES+1;
  297. /*
  298. * SIMPLE(!) argument "parser"
  299. */
  300. if (argc == 3)
  301. {
  302. if (strcmp(argv[1], "-f") == 0)
  303. offset = 0;
  304. if (strcmp(argv[1], "-t") == 0)
  305. trace = 1;
  306. if ((strcmp(argv[1], "-ft") == 0) ||
  307. (strcmp(argv[1], "-tf") == 0))
  308. {
  309. offset = 0;
  310. trace = 1;
  311. }
  312. file = argv[2];
  313. }
  314. else
  315. {
  316. file = argv[1];
  317. }
  318. fd = open(file, O_RDONLY);
  319. if (fd == -1)
  320. {
  321. perror(file);
  322. exit(1);
  323. }
  324. else
  325. {
  326. int i;
  327. #ifdef TIOCM_RTS
  328. int on = TIOCM_RTS;
  329. #endif
  330. struct timeval t, tt, tlast;
  331. char buf[61];
  332. clocktime_t clock_time;
  333. struct termios term;
  334. int rtc = CVT_NONE;
  335. if (tcgetattr(fd, &term) == -1)
  336. {
  337. perror("tcgetattr");
  338. exit(1);
  339. }
  340. memset(term.c_cc, 0, sizeof(term.c_cc));
  341. term.c_cc[VMIN] = 1;
  342. #ifdef NO_PARENB_IGNPAR /* Was: defined(SYS_IRIX4) || defined (SYS_IRIX5) */
  343. /* somehow doesn't grok PARENB & IGNPAR (mj) */
  344. term.c_cflag = CS8|CREAD|CLOCAL;
  345. #else
  346. term.c_cflag = CS8|CREAD|CLOCAL|PARENB;
  347. #endif
  348. term.c_iflag = IGNPAR;
  349. term.c_oflag = 0;
  350. term.c_lflag = 0;
  351. cfsetispeed(&term, B50);
  352. cfsetospeed(&term, B50);
  353. if (tcsetattr(fd, TCSANOW, &term) == -1)
  354. {
  355. perror("tcsetattr");
  356. exit(1);
  357. }
  358. #ifdef I_POP
  359. while (ioctl(fd, I_POP, 0) == 0)
  360. ;
  361. #endif
  362. #if defined(TIOCMBIC) && defined(TIOCM_RTS)
  363. if (ioctl(fd, TIOCMBIC, (caddr_t)&on) == -1)
  364. {
  365. perror("TIOCM_RTS");
  366. }
  367. #endif
  368. printf(" DCF77 monitor %s - Copyright (C) 1993-2005, Frank Kardel\n\n", revision);
  369. clock_time.hour = 0;
  370. clock_time.minute = 0;
  371. clock_time.day = 0;
  372. clock_time.wday = 0;
  373. clock_time.month = 0;
  374. clock_time.year = 0;
  375. clock_time.flags = 0;
  376. buf[60] = '\0';
  377. for ( i = 0; i < 60; i++)
  378. buf[i] = '.';
  379. gettimeofday(&tlast, 0L);
  380. i = 0;
  381. while (read(fd, &c, 1) == 1)
  382. {
  383. gettimeofday(&t, 0L);
  384. tt = t;
  385. t.tv_sec -= tlast.tv_sec;
  386. t.tv_usec -= tlast.tv_usec;
  387. if (t.tv_usec < 0)
  388. {
  389. t.tv_usec += 1000000;
  390. t.tv_sec -= 1;
  391. }
  392. if (errs > LINES)
  393. {
  394. printf(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]);
  395. printf(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]);
  396. errs = 0;
  397. }
  398. if (t.tv_sec > 1 ||
  399. (t.tv_sec == 1 &&
  400. t.tv_usec > 500000))
  401. {
  402. printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]);
  403. if ((rtc = convert_rawdcf((unsigned char *)buf, i, &clock_time)) != CVT_OK)
  404. {
  405. printf("\n");
  406. clock_time.hour = 0;
  407. clock_time.minute = 0;
  408. clock_time.day = 0;
  409. clock_time.wday = 0;
  410. clock_time.month = 0;
  411. clock_time.year = 0;
  412. clock_time.flags = 0;
  413. errs++;
  414. }
  415. if (((c^0xFF)+1) & (c^0xFF))
  416. buf[0] = '?';
  417. else
  418. buf[0] = type(c) ? '#' : '-';
  419. for ( i = 1; i < 60; i++)
  420. buf[i] = '.';
  421. i = 0;
  422. }
  423. else
  424. {
  425. if (((c^0xFF)+1) & (c^0xFF))
  426. buf[i] = '?';
  427. else
  428. buf[i] = type(c) ? '#' : '-';
  429. printf("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &buf[offset]);
  430. }
  431. if (rtc == CVT_OK)
  432. {
  433. printf("%s, %2d:%02d:%02d, %d.%02d.%02d, <%s%s%s%s>",
  434. wday[clock_time.wday],
  435. (int)clock_time.hour, (int)clock_time.minute, (int)i, (int)clock_time.day, (int)clock_time.month,
  436. (int)clock_time.year,
  437. (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_",
  438. (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_",
  439. (clock_time.flags & DCFB_DST) ? "D" : "_",
  440. (clock_time.flags & DCFB_LEAP) ? "L" : "_"
  441. );
  442. if (trace && (i == 0))
  443. {
  444. printf("\n");
  445. errs++;
  446. }
  447. }
  448. printf("\r");
  449. if (i < 60)
  450. {
  451. i++;
  452. }
  453. tlast = tt;
  454. fflush(stdout);
  455. }
  456. close(fd);
  457. }
  458. }
  459. return 0;
  460. }
  461. /*
  462. * History:
  463. *
  464. * testdcf.c,v
  465. * Revision 4.10 2005/08/06 14:18:43 kardel
  466. * cleanup warnings
  467. *
  468. * Revision 4.9 2005/08/06 14:14:38 kardel
  469. * document revision on startup
  470. *
  471. * Revision 4.8 2005/08/06 14:10:08 kardel
  472. * fix setting of baud rate
  473. *
  474. * Revision 4.7 2005/04/16 17:32:10 kardel
  475. * update copyright
  476. *
  477. * Revision 4.6 2004/11/14 15:29:42 kardel
  478. * support PPSAPI, upgrade Copyright to Berkeley style
  479. *
  480. */