/contrib/ntp/ntpd/refclock_gpsvme.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 254 lines · 195 code · 32 blank · 27 comment · 13 complexity · f0247733c9134a9da128fc7773828a11 MD5 · raw file

  1. /* refclock_psc.c: clock driver for Brandywine PCI-SyncClock32/HP-UX 11.X */
  2. #ifdef HAVE_CONFIG_H
  3. #include <config.h>
  4. #endif /* HAVE_CONFIG_H */
  5. #if defined(REFCLOCK) && defined(CLOCK_GPSVME)
  6. #include "ntpd.h"
  7. #include "ntp_io.h"
  8. #include "ntp_refclock.h"
  9. #include "ntp_unixtime.h"
  10. #include "ntp_stdlib.h"
  11. #ifdef __hpux
  12. #include <sys/rtprio.h> /* may already be included above */
  13. #include <sys/lock.h> /* NEEDED for PROCLOCK */
  14. #endif /* __hpux */
  15. #ifdef __linux__
  16. #include <sys/ioctl.h> /* for _IOR, ioctl */
  17. #endif /* __linux__ */
  18. enum { /* constants */
  19. BUFSIZE = 32,
  20. PSC_SYNC_OK = 0x40, /* Sync status bit */
  21. DP_LEAPSEC_DAY10DAY1 = 0x82, /* DP RAM address */
  22. DP_LEAPSEC_DAY1000DAY100 = 0x83,
  23. DELAY = 1,
  24. NUNIT = 2 /* max UNITS */
  25. };
  26. /* clock card registers */
  27. struct psc_regs {
  28. uint32_t low_time; /* card base + 0x00 */
  29. uint32_t high_time; /* card base + 0x04 */
  30. uint32_t ext_low_time; /* card base + 0x08 */
  31. uint32_t ext_high_time; /* card base + 0x0C */
  32. uint8_t device_status; /* card base + 0x10 */
  33. uint8_t device_control; /* card base + 0x11 */
  34. uint8_t reserved0; /* card base + 0x12 */
  35. uint8_t ext_100ns; /* card base + 0x13 */
  36. uint8_t match_usec; /* card base + 0x14 */
  37. uint8_t match_msec; /* card base + 0x15 */
  38. uint8_t reserved1; /* card base + 0x16 */
  39. uint8_t reserved2; /* card base + 0x17 */
  40. uint8_t reserved3; /* card base + 0x18 */
  41. uint8_t reserved4; /* card base + 0x19 */
  42. uint8_t dp_ram_addr; /* card base + 0x1A */
  43. uint8_t reserved5; /* card base + 0x1B */
  44. uint8_t reserved6; /* card base + 0x1C */
  45. uint8_t reserved7; /* card base + 0x1D */
  46. uint8_t dp_ram_data; /* card base + 0x1E */
  47. uint8_t reserved8; /* card base + 0x1F */
  48. } *volatile regp[NUNIT];
  49. #define PSC_REGS _IOR('K', 0, long) /* ioctl argument */
  50. /* Macros to swap byte order and convert BCD to binary */
  51. #define SWAP(val) ( ((val) >> 24) | (((val) & 0x00ff0000) >> 8) | \
  52. (((val) & 0x0000ff00) << 8) | (((val) & 0x000000ff) << 24) )
  53. #define BCD2INT2(val) ( ((val) >> 4 & 0x0f)*10 + ((val) & 0x0f) )
  54. #define BCD2INT3(val) ( ((val) >> 8 & 0x0f)*100 + ((val) >> 4 & 0x0f)*10 + \
  55. ((val) & 0x0f) )
  56. /* PSC interface definitions */
  57. #define PRECISION (-20) /* precision assumed (1 us) */
  58. #define REFID "USNO" /* reference ID */
  59. #define DESCRIPTION "Brandywine PCI-SyncClock32"
  60. #define DEVICE "/dev/refclock%1d" /* device file */
  61. /* clock unit control structure */
  62. struct psc_unit {
  63. short unit; /* NTP refclock unit number */
  64. short last_hour; /* last hour (monitor leap sec) */
  65. int msg_flag[2]; /* count error messages */
  66. };
  67. int fd[NUNIT]; /* file descriptor */
  68. /* Local function prototypes */
  69. static int psc_start(int, struct peer *);
  70. static void psc_shutdown(int, struct peer *);
  71. static void psc_poll(int, struct peer *);
  72. static void check_leap_sec(struct refclockproc *, int);
  73. /* Transfer vector */
  74. struct refclock refclock_gpsvme = {
  75. psc_start, psc_shutdown, psc_poll, noentry, noentry, noentry, NOFLAGS
  76. };
  77. /* psc_start: open device and initialize data for processing */
  78. static int
  79. psc_start(
  80. int unit,
  81. struct peer *peer
  82. )
  83. {
  84. char buf[BUFSIZE];
  85. struct refclockproc *pp;
  86. struct psc_unit *up = emalloc(sizeof *up);
  87. if (unit < 0 || unit > 1) { /* support units 0 and 1 */
  88. msyslog(LOG_ERR, "psc_start: bad unit: %d", unit);
  89. return 0;
  90. }
  91. if (!up) {
  92. msyslog(LOG_ERR, "psc_start: unit: %d, emalloc: %m", unit);
  93. return 0;
  94. }
  95. memset(up, '\0', sizeof *up);
  96. sprintf(buf, DEVICE, unit); /* dev file name */
  97. fd[unit] = open(buf, O_RDONLY); /* open device file */
  98. if (fd[unit] < 0) {
  99. msyslog(LOG_ERR, "psc_start: unit: %d, open failed. %m", unit);
  100. return 0;
  101. }
  102. /* get the address of the mapped regs */
  103. if (ioctl(fd[unit], PSC_REGS, &regp[unit]) < 0) {
  104. msyslog(LOG_ERR, "psc_start: unit: %d, ioctl failed. %m", unit);
  105. return 0;
  106. }
  107. /* initialize peer variables */
  108. pp = peer->procptr;
  109. pp->io.clock_recv = noentry;
  110. pp->io.srcclock = (caddr_t) peer;
  111. pp->io.datalen = 0;
  112. pp->io.fd = -1;
  113. pp->unitptr = (caddr_t) up;
  114. get_systime(&pp->lastrec);
  115. memcpy((char *)&pp->refid, REFID, 4);
  116. peer->precision = PRECISION;
  117. pp->clockdesc = DESCRIPTION;
  118. up->unit = unit;
  119. #ifdef __hpux
  120. rtprio(0,120); /* set real time priority */
  121. plock(PROCLOCK); /* lock process in memory */
  122. #endif /* __hpux */
  123. return 1;
  124. }
  125. /* psc_shutdown: shut down the clock */
  126. static void
  127. psc_shutdown(
  128. int unit,
  129. struct peer *peer
  130. )
  131. {
  132. free(peer->procptr->unitptr);
  133. close(fd[unit]);
  134. }
  135. /* psc_poll: read, decode, and record device time */
  136. static void
  137. psc_poll(
  138. int unit,
  139. struct peer *peer
  140. )
  141. {
  142. struct refclockproc *pp = peer->procptr;
  143. struct psc_unit *up;
  144. unsigned tlo, thi;
  145. unsigned char status;
  146. up = (struct psc_unit *) pp->unitptr;
  147. tlo = regp[unit]->low_time; /* latch and read first 4 bytes */
  148. thi = regp[unit]->high_time; /* read 4 higher order bytes */
  149. status = regp[unit]->device_status; /* read device status byte */
  150. if (!(status & PSC_SYNC_OK)) {
  151. refclock_report(peer, CEVNT_BADTIME);
  152. if (!up->msg_flag[unit]) { /* write once to system log */
  153. msyslog(LOG_WARNING,
  154. "SYNCHRONIZATION LOST on unit %1d, status %02x\n",
  155. status, unit);
  156. up->msg_flag[unit] = 1;
  157. }
  158. return;
  159. }
  160. get_systime(&pp->lastrec);
  161. pp->polls++;
  162. tlo = SWAP(tlo); /* little to big endian swap on */
  163. thi = SWAP(thi); /* copy of data */
  164. /* convert the BCD time to broken down time used by refclockproc */
  165. pp->day = BCD2INT3((thi & 0x0FFF0000) >> 16);
  166. pp->hour = BCD2INT2((thi & 0x0000FF00) >> 8);
  167. pp->minute = BCD2INT2(thi & 0x000000FF);
  168. pp->second = BCD2INT2(tlo >> 24);
  169. /* ntp_process() in ntp_refclock.c appears to use usec as fraction of
  170. second in microseconds if usec is nonzero. */
  171. pp->nsec = 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) +
  172. BCD2INT3(tlo & 0x00000FFF);
  173. sprintf(pp->a_lastcode, "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x",
  174. pp->day, pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
  175. tlo);
  176. pp->lencode = strlen(pp->a_lastcode);
  177. /* compute the timecode timestamp */
  178. if (!refclock_process(pp)) {
  179. refclock_report(peer, CEVNT_BADTIME);
  180. return;
  181. }
  182. /* simulate the NTP receive and packet procedures */
  183. refclock_receive(peer);
  184. /* write clock statistics to file */
  185. record_clock_stats(&peer->srcadr, pp->a_lastcode);
  186. /* With the first timecode beginning the day, check for a GPS
  187. leap second notification. */
  188. if (pp->hour < up->last_hour) {
  189. check_leap_sec(pp, unit);
  190. up->msg_flag[0] = up->msg_flag[1] = 0; /* reset flags */
  191. }
  192. up->last_hour = pp->hour;
  193. }
  194. /* check_leap_sec: read the Dual Port RAM leap second day registers. The
  195. onboard GPS receiver should write the hundreds digit of day of year in
  196. DP_LeapSec_Day1000Day100 and the tens and ones digits in
  197. DP_LeapSec_Day10Day1. If these values are nonzero and today, we have
  198. a leap second pending, so we set the pp->leap flag to LEAP_ADDSECOND.
  199. If the BCD data are zero or a date other than today, set pp->leap to
  200. LEAP_NOWARNING. */
  201. static void
  202. check_leap_sec(struct refclockproc *pp, int unit)
  203. {
  204. unsigned char dhi, dlo;
  205. int leap_day;
  206. regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY10DAY1;
  207. usleep(DELAY);
  208. dlo = regp[unit]->dp_ram_data;
  209. regp[unit]->dp_ram_addr = DP_LEAPSEC_DAY1000DAY100;
  210. usleep(DELAY);
  211. dhi = regp[unit]->dp_ram_data;
  212. leap_day = BCD2INT2(dlo) + 100*(dhi & 0x0F);
  213. pp->leap = LEAP_NOWARNING; /* default */
  214. if (leap_day && leap_day == pp->day) {
  215. pp->leap = LEAP_ADDSECOND; /* leap second today */
  216. msyslog(LOG_ERR, "LEAP_ADDSECOND flag set, day %d (%x %x).",
  217. leap_day, dhi, dlo);
  218. }
  219. }
  220. #else
  221. int refclock_gpsvme_bs;
  222. #endif /* REFCLOCK */