/contrib/ntp/ntpd/refclock_pcf.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 224 lines · 153 code · 30 blank · 41 comment · 29 complexity · 3552a3c5b6541439f8b8bbf7ae2c056b MD5 · raw file

  1. /*
  2. * refclock_pcf - clock driver for the Conrad parallel port radio clock
  3. */
  4. #ifdef HAVE_CONFIG_H
  5. # include <config.h>
  6. #endif
  7. #if defined(REFCLOCK) && defined(CLOCK_PCF)
  8. #include "ntpd.h"
  9. #include "ntp_io.h"
  10. #include "ntp_refclock.h"
  11. #include "ntp_calendar.h"
  12. #include "ntp_stdlib.h"
  13. /*
  14. * This driver supports the parallel port radio clock sold by Conrad
  15. * Electronic under order numbers 967602 and 642002.
  16. *
  17. * It requires that the local timezone be CET/CEST and that the pcfclock
  18. * device driver be installed. A device driver for Linux is available at
  19. * http://home.pages.de/~voegele/pcf.html. Information about a FreeBSD
  20. * driver is available at http://schumann.cx/pcfclock/.
  21. */
  22. /*
  23. * Interface definitions
  24. */
  25. #define DEVICE "/dev/pcfclocks/%d"
  26. #define OLDDEVICE "/dev/pcfclock%d"
  27. #define PRECISION (-1) /* precision assumed (about 0.5 s) */
  28. #define REFID "PCF"
  29. #define DESCRIPTION "Conrad parallel port radio clock"
  30. #define LENPCF 18 /* timecode length */
  31. /*
  32. * Function prototypes
  33. */
  34. static int pcf_start P((int, struct peer *));
  35. static void pcf_shutdown P((int, struct peer *));
  36. static void pcf_poll P((int, struct peer *));
  37. /*
  38. * Transfer vector
  39. */
  40. struct refclock refclock_pcf = {
  41. pcf_start, /* start up driver */
  42. pcf_shutdown, /* shut down driver */
  43. pcf_poll, /* transmit poll message */
  44. noentry, /* not used */
  45. noentry, /* initialize driver (not used) */
  46. noentry, /* not used */
  47. NOFLAGS /* not used */
  48. };
  49. /*
  50. * pcf_start - open the device and initialize data for processing
  51. */
  52. static int
  53. pcf_start(
  54. int unit,
  55. struct peer *peer
  56. )
  57. {
  58. struct refclockproc *pp;
  59. int fd;
  60. char device[128];
  61. /*
  62. * Open device file for reading.
  63. */
  64. (void)sprintf(device, DEVICE, unit);
  65. fd = open(device, O_RDONLY);
  66. if (fd == -1) {
  67. (void)sprintf(device, OLDDEVICE, unit);
  68. fd = open(device, O_RDONLY);
  69. }
  70. #ifdef DEBUG
  71. if (debug)
  72. printf ("starting PCF with device %s\n",device);
  73. #endif
  74. if (fd == -1) {
  75. return (0);
  76. }
  77. pp = peer->procptr;
  78. pp->io.clock_recv = noentry;
  79. pp->io.srcclock = (caddr_t)peer;
  80. pp->io.datalen = 0;
  81. pp->io.fd = fd;
  82. /*
  83. * Initialize miscellaneous variables
  84. */
  85. peer->precision = PRECISION;
  86. pp->clockdesc = DESCRIPTION;
  87. /* one transmission takes 172.5 milliseconds since the radio clock
  88. transmits 69 bits with a period of 2.5 milliseconds per bit */
  89. pp->fudgetime1 = 0.1725;
  90. memcpy((char *)&pp->refid, REFID, 4);
  91. return (1);
  92. }
  93. /*
  94. * pcf_shutdown - shut down the clock
  95. */
  96. static void
  97. pcf_shutdown(
  98. int unit,
  99. struct peer *peer
  100. )
  101. {
  102. struct refclockproc *pp;
  103. pp = peer->procptr;
  104. (void)close(pp->io.fd);
  105. }
  106. /*
  107. * pcf_poll - called by the transmit procedure
  108. */
  109. static void
  110. pcf_poll(
  111. int unit,
  112. struct peer *peer
  113. )
  114. {
  115. struct refclockproc *pp;
  116. char buf[LENPCF];
  117. struct tm tm, *tp;
  118. time_t t;
  119. pp = peer->procptr;
  120. buf[0] = 0;
  121. if (read(pp->io.fd, buf, sizeof(buf)) < sizeof(buf) || buf[0] != 9) {
  122. refclock_report(peer, CEVNT_FAULT);
  123. return;
  124. }
  125. tm.tm_mday = buf[11] * 10 + buf[10];
  126. tm.tm_mon = buf[13] * 10 + buf[12] - 1;
  127. tm.tm_year = buf[15] * 10 + buf[14];
  128. tm.tm_hour = buf[7] * 10 + buf[6];
  129. tm.tm_min = buf[5] * 10 + buf[4];
  130. tm.tm_sec = buf[3] * 10 + buf[2];
  131. tm.tm_isdst = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1;
  132. /*
  133. * Y2K convert the 2-digit year
  134. */
  135. if (tm.tm_year < 99)
  136. tm.tm_year += 100;
  137. t = mktime(&tm);
  138. if (t == (time_t) -1) {
  139. refclock_report(peer, CEVNT_BADTIME);
  140. return;
  141. }
  142. #if defined(__GLIBC__) && defined(_BSD_SOURCE)
  143. if ((tm.tm_isdst > 0 && tm.tm_gmtoff != 7200)
  144. || (tm.tm_isdst == 0 && tm.tm_gmtoff != 3600)
  145. || tm.tm_isdst < 0) {
  146. #ifdef DEBUG
  147. if (debug)
  148. printf ("local time zone not set to CET/CEST\n");
  149. #endif
  150. refclock_report(peer, CEVNT_BADTIME);
  151. return;
  152. }
  153. #endif
  154. pp->lencode = strftime(pp->a_lastcode, BMAX, "%Y %m %d %H %M %S", &tm);
  155. #if defined(_REENTRANT) || defined(_THREAD_SAFE)
  156. tp = gmtime_r(&t, &tm);
  157. #else
  158. tp = gmtime(&t);
  159. #endif
  160. if (!tp) {
  161. refclock_report(peer, CEVNT_FAULT);
  162. return;
  163. }
  164. get_systime(&pp->lastrec);
  165. pp->polls++;
  166. pp->year = tp->tm_year + 1900;
  167. pp->day = tp->tm_yday + 1;
  168. pp->hour = tp->tm_hour;
  169. pp->minute = tp->tm_min;
  170. pp->second = tp->tm_sec;
  171. pp->nsec = buf[16] * 31250000;
  172. if (buf[17] & 1)
  173. pp->nsec += 500000000;
  174. #ifdef DEBUG
  175. if (debug)
  176. printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
  177. unit, pp->year, tp->tm_mon + 1, tp->tm_mday, pp->hour,
  178. pp->minute, pp->second);
  179. #endif
  180. if (!refclock_process(pp)) {
  181. refclock_report(peer, CEVNT_BADTIME);
  182. return;
  183. }
  184. record_clock_stats(&peer->srcadr, pp->a_lastcode);
  185. if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2))
  186. pp->leap = LEAP_NOTINSYNC;
  187. else
  188. pp->leap = LEAP_NOWARNING;
  189. pp->lastref = pp->lastrec;
  190. refclock_receive(peer);
  191. }
  192. #else
  193. int refclock_pcf_bs;
  194. #endif /* REFCLOCK */