/contrib/ntp/ntpd/refclock_msfees.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1462 lines · 1029 code · 155 blank · 278 comment · 209 complexity · 4320f73c2e04502e9632c8c24b626014 MD5 · raw file

  1. /* refclock_ees - clock driver for the EES M201 receiver */
  2. #ifdef HAVE_CONFIG_H
  3. #include <config.h>
  4. #endif
  5. #if defined(REFCLOCK) && defined(CLOCK_MSFEES) && defined(PPS)
  6. /* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes
  7. * were removed as the code was overly hairy, they weren't in use
  8. * (hence probably didn't work). Still in RCS file at cl.cam.ac.uk
  9. */
  10. #include "ntpd.h"
  11. #include "ntp_io.h"
  12. #include "ntp_refclock.h"
  13. #include "ntp_unixtime.h"
  14. #include "ntp_calendar.h"
  15. #include <ctype.h>
  16. #if defined(HAVE_BSD_TTYS)
  17. #include <sgtty.h>
  18. #endif /* HAVE_BSD_TTYS */
  19. #if defined(HAVE_SYSV_TTYS)
  20. #include <termio.h>
  21. #endif /* HAVE_SYSV_TTYS */
  22. #if defined(HAVE_TERMIOS)
  23. #include <termios.h>
  24. #endif
  25. #if defined(STREAM)
  26. #include <stropts.h>
  27. #endif
  28. #ifdef HAVE_SYS_TERMIOS_H
  29. # include <sys/termios.h>
  30. #endif
  31. #ifdef HAVE_SYS_PPSCLOCK_H
  32. # include <sys/ppsclock.h>
  33. #endif
  34. #include "ntp_stdlib.h"
  35. int dbg = 0;
  36. /*
  37. fudgefactor = fudgetime1;
  38. os_delay = fudgetime2;
  39. offset_fudge = os_delay + fudgefactor + inherent_delay;
  40. stratumtouse = fudgeval1 & 0xf
  41. dbg = fudgeval2;
  42. sloppyclockflag = flags & CLK_FLAG1;
  43. 1 log smoothing summary when processing sample
  44. 4 dump the buffer from the clock
  45. 8 EIOGETKD the last n uS time stamps
  46. if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0;
  47. ees->dump_vals = flags & CLK_FLAG3;
  48. ees->usealldata = flags & CLK_FLAG4;
  49. bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
  50. bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
  51. bug->values[2] = (u_long)ees->status;
  52. bug->values[3] = (u_long)ees->lastevent;
  53. bug->values[4] = (u_long)ees->reason;
  54. bug->values[5] = (u_long)ees->nsamples;
  55. bug->values[6] = (u_long)ees->codestate;
  56. bug->values[7] = (u_long)ees->day;
  57. bug->values[8] = (u_long)ees->hour;
  58. bug->values[9] = (u_long)ees->minute;
  59. bug->values[10] = (u_long)ees->second;
  60. bug->values[11] = (u_long)ees->tz;
  61. bug->values[12] = ees->yearstart;
  62. bug->values[13] = (ees->leaphold > current_time) ?
  63. ees->leaphold - current_time : 0;
  64. bug->values[14] = inherent_delay[unit].l_uf;
  65. bug->values[15] = offset_fudge[unit].l_uf;
  66. bug->times[0] = ees->reftime;
  67. bug->times[1] = ees->arrvtime;
  68. bug->times[2] = ees->lastsampletime;
  69. bug->times[3] = ees->offset;
  70. bug->times[4] = ees->lowoffset;
  71. bug->times[5] = ees->highoffset;
  72. bug->times[6] = inherent_delay[unit];
  73. bug->times[8] = os_delay[unit];
  74. bug->times[7] = fudgefactor[unit];
  75. bug->times[9] = offset_fudge[unit];
  76. bug->times[10]= ees->yearstart, 0;
  77. */
  78. /* This should support the use of an EES M201 receiver with RS232
  79. * output (modified to transmit time once per second).
  80. *
  81. * For the format of the message sent by the clock, see the EESM_
  82. * definitions below.
  83. *
  84. * It appears to run free for an integral number of minutes, until the error
  85. * reaches 4mS, at which point it steps at second = 01.
  86. * It appears that sometimes it steps 4mS (say at 7 min interval),
  87. * then the next minute it decides that it was an error, so steps back.
  88. * On the next minute it steps forward again :-(
  89. * This is typically 16.5uS/S then 3975uS at the 4min re-sync,
  90. * or 9.5uS/S then 3990.5uS at a 7min re-sync,
  91. * at which point it may lose the "00" second time stamp.
  92. * I assume that the most accurate time is just AFTER the re-sync.
  93. * Hence remember the last cycle interval,
  94. *
  95. * Can run in any one of:
  96. *
  97. * PPSCD PPS signal sets CD which interupts, and grabs the current TOD
  98. * (sun) *in the interupt code*, so as to avoid problems with
  99. * the STREAMS scheduling.
  100. *
  101. * It appears that it goes 16.5 uS slow each second, then every 4 mins it
  102. * generates no "00" second tick, and gains 3975 uS. Ho Hum ! (93/2/7)
  103. */
  104. /* Definitions */
  105. #ifndef MAXUNITS
  106. #define MAXUNITS 4 /* maximum number of EES units permitted */
  107. #endif
  108. #ifndef EES232
  109. #define EES232 "/dev/ees%d" /* Device to open to read the data */
  110. #endif
  111. /* Other constant stuff */
  112. #ifndef EESPRECISION
  113. #define EESPRECISION (-10) /* what the heck - 2**-10 = 1ms */
  114. #endif
  115. #ifndef EESREFID
  116. #define EESREFID "MSF\0" /* String to identify the clock */
  117. #endif
  118. #ifndef EESHSREFID
  119. #define EESHSREFID (0x7f7f0000 | ((REFCLK_MSF_EES) << 8)) /* Numeric refid */
  120. #endif
  121. /* Description of clock */
  122. #define EESDESCRIPTION "EES M201 MSF Receiver"
  123. /* Speed we run the clock port at. If this is changed the UARTDELAY
  124. * value should be recomputed to suit.
  125. */
  126. #ifndef SPEED232
  127. #define SPEED232 B9600 /* 9600 baud */
  128. #endif
  129. /* What is the inherent delay for this mode of working, i.e. when is the
  130. * data time stamped.
  131. */
  132. #define SAFETY_SHIFT 10 /* Split the shift to avoid overflow */
  133. #define BITS_TO_L_FP(bits, baud) \
  134. (((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT)
  135. #define INH_DELAY_CBREAK BITS_TO_L_FP(119, 9600)
  136. #define INH_DELAY_PPS BITS_TO_L_FP( 0, 9600)
  137. #ifndef STREAM_PP1
  138. #define STREAM_PP1 "ppsclocd\0<-- patch space for module name1 -->"
  139. #endif
  140. #ifndef STREAM_PP2
  141. #define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->"
  142. #endif
  143. /* Offsets of the bytes of the serial line code. The clock gives
  144. * local time with a GMT/BST indication. The EESM_ definitions
  145. * give offsets into ees->lastcode.
  146. */
  147. #define EESM_CSEC 0 /* centiseconds - always zero in our clock */
  148. #define EESM_SEC 1 /* seconds in BCD */
  149. #define EESM_MIN 2 /* minutes in BCD */
  150. #define EESM_HOUR 3 /* hours in BCD */
  151. #define EESM_DAYWK 4 /* day of week (Sun = 0 etc) */
  152. #define EESM_DAY 5 /* day of month in BCD */
  153. #define EESM_MON 6 /* month in BCD */
  154. #define EESM_YEAR 7 /* year MOD 100 in BCD */
  155. #define EESM_LEAP 8 /* 0x0f if leap year, otherwise zero */
  156. #define EESM_BST 9 /* 0x03 if BST, 0x00 if GMT */
  157. #define EESM_MSFOK 10 /* 0x3f if radio good, otherwise zero */
  158. /* followed by a frame alignment byte (0xff) /
  159. / which is not put into the lastcode buffer*/
  160. /* Length of the serial time code, in characters. The first length
  161. * is less the frame alignment byte.
  162. */
  163. #define LENEESPRT (EESM_MSFOK+1)
  164. #define LENEESCODE (LENEESPRT+1)
  165. /* Code state. */
  166. #define EESCS_WAIT 0 /* waiting for start of timecode */
  167. #define EESCS_GOTSOME 1 /* have an incomplete time code buffered */
  168. /* Default fudge factor and character to receive */
  169. #define DEFFUDGETIME 0 /* Default user supplied fudge factor */
  170. #ifndef DEFOSTIME
  171. #define DEFOSTIME 0 /* Default OS delay -- passed by Make ? */
  172. #endif
  173. #define DEFINHTIME INH_DELAY_PPS /* inherent delay due to sample point*/
  174. /* Limits on things. Reduce the number of samples to SAMPLEREDUCE by median
  175. * elimination. If we're running with an accurate clock, chose the BESTSAMPLE
  176. * as the estimated offset, otherwise average the remainder.
  177. */
  178. #define FULLSHIFT 6 /* NCODES root 2 */
  179. #define NCODES (1<< FULLSHIFT) /* 64 */
  180. #define REDUCESHIFT (FULLSHIFT -1) /* SAMPLEREDUCE root 2 */
  181. /* Towards the high ( Why ?) end of half */
  182. #define BESTSAMPLE ((samplereduce * 3) /4) /* 24 */
  183. /* Leap hold time. After a leap second the clock will no longer be
  184. * reliable until it resynchronizes. Hope 40 minutes is enough. */
  185. #define EESLEAPHOLD (40 * 60)
  186. #define EES_STEP_F (1 << 24) /* the receiver steps in units of about 4ms */
  187. #define EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/
  188. #define EES_STEP_NOTE (1 << 21)/* Log any unexpected jumps, say .5 ms .... */
  189. #define EES_STEP_NOTES 50 /* Only do a limited number */
  190. #define MAX_STEP 16 /* Max number of steps to remember */
  191. /* debug is a bit mask of debugging that is wanted */
  192. #define DB_SYSLOG_SMPLI 0x0001
  193. #define DB_SYSLOG_SMPLE 0x0002
  194. #define DB_SYSLOG_SMTHI 0x0004
  195. #define DB_SYSLOG_NSMTHE 0x0008
  196. #define DB_SYSLOG_NSMTHI 0x0010
  197. #define DB_SYSLOG_SMTHE 0x0020
  198. #define DB_PRINT_EV 0x0040
  199. #define DB_PRINT_CDT 0x0080
  200. #define DB_PRINT_CDTC 0x0100
  201. #define DB_SYSLOG_KEEPD 0x0800
  202. #define DB_SYSLOG_KEEPE 0x1000
  203. #define DB_LOG_DELTAS 0x2000
  204. #define DB_PRINT_DELTAS 0x4000
  205. #define DB_LOG_AWAITMORE 0x8000
  206. #define DB_LOG_SAMPLES 0x10000
  207. #define DB_NO_PPS 0x20000
  208. #define DB_INC_PPS 0x40000
  209. #define DB_DUMP_DELTAS 0x80000
  210. struct eesunit { /* EES unit control structure. */
  211. struct peer *peer; /* associated peer structure */
  212. struct refclockio io; /* given to the I/O handler */
  213. l_fp reftime; /* reference time */
  214. l_fp lastsampletime; /* time as in txt from last EES msg */
  215. l_fp arrvtime; /* Time at which pkt arrived */
  216. l_fp codeoffsets[NCODES]; /* the time of arrival of 232 codes */
  217. l_fp offset; /* chosen offset (for clkbug) */
  218. l_fp lowoffset; /* lowest sample offset (for clkbug) */
  219. l_fp highoffset; /* highest " " (for clkbug) */
  220. char lastcode[LENEESCODE+6]; /* last time code we received */
  221. u_long lasttime; /* last time clock heard from */
  222. u_long clocklastgood; /* last time good radio seen */
  223. u_char lencode; /* length of code in buffer */
  224. u_char nsamples; /* number of samples we've collected */
  225. u_char codestate; /* state of 232 code reception */
  226. u_char unit; /* unit number for this guy */
  227. u_char status; /* clock status */
  228. u_char lastevent; /* last clock event */
  229. u_char reason; /* reason for last abort */
  230. u_char hour; /* hour of day */
  231. u_char minute; /* minute of hour */
  232. u_char second; /* seconds of minute */
  233. char tz; /* timezone from clock */
  234. u_char ttytype; /* method used */
  235. u_char dump_vals; /* Should clock values be dumped */
  236. u_char usealldata; /* Use ALL samples */
  237. u_short day; /* day of year from last code */
  238. u_long yearstart; /* start of current year */
  239. u_long leaphold; /* time of leap hold expiry */
  240. u_long badformat; /* number of bad format codes */
  241. u_long baddata; /* number of invalid time codes */
  242. u_long timestarted; /* time we started this */
  243. long last_pps_no; /* The serial # of the last PPS */
  244. char fix_pending; /* Is a "sync to time" pending ? */
  245. /* Fine tuning - compensate for 4 mS ramping .... */
  246. l_fp last_l; /* last time stamp */
  247. u_char last_steps[MAX_STEP]; /* Most recent n steps */
  248. int best_av_step; /* Best guess at average step */
  249. char best_av_step_count; /* # of steps over used above */
  250. char this_step; /* Current pos in buffer */
  251. int last_step_late; /* How late the last step was (0-59) */
  252. long jump_fsecs; /* # of fractions of a sec last jump */
  253. u_long last_step; /* time of last step */
  254. int last_step_secs; /* Number of seconds in last step */
  255. int using_ramp; /* 1 -> noemal, -1 -> over stepped */
  256. };
  257. #define last_sec last_l.l_ui
  258. #define last_sfsec last_l.l_f
  259. #define this_uisec ((ees->arrvtime).l_ui)
  260. #define this_sfsec ((ees->arrvtime).l_f)
  261. #define msec(x) ((x) / (1<<22))
  262. #define LAST_STEPS (sizeof ees->last_steps / sizeof ees->last_steps[0])
  263. #define subms(x) ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5)))
  264. /* Bitmask for what methods to try to use -- currently only PPS enabled */
  265. #define T_CBREAK 1
  266. #define T_PPS 8
  267. /* macros to test above */
  268. #define is_cbreak(x) ((x)->ttytype & T_CBREAK)
  269. #define is_pps(x) ((x)->ttytype & T_PPS)
  270. #define is_any(x) ((x)->ttytype)
  271. #define CODEREASON 20 /* reason codes */
  272. /* Data space for the unit structures. Note that we allocate these on
  273. * the fly, but never give them back. */
  274. static struct eesunit *eesunits[MAXUNITS];
  275. static u_char unitinuse[MAXUNITS];
  276. /* Keep the fudge factors separately so they can be set even
  277. * when no clock is configured. */
  278. static l_fp inherent_delay[MAXUNITS]; /* when time stamp is taken */
  279. static l_fp fudgefactor[MAXUNITS]; /* fudgetime1 */
  280. static l_fp os_delay[MAXUNITS]; /* fudgetime2 */
  281. static l_fp offset_fudge[MAXUNITS]; /* Sum of above */
  282. static u_char stratumtouse[MAXUNITS];
  283. static u_char sloppyclockflag[MAXUNITS];
  284. static int deltas[60];
  285. static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */
  286. static l_fp onesec; /* = { 1, 0 }; */
  287. #ifndef DUMP_BUF_SIZE /* Size of buffer to be used by dump_buf */
  288. #define DUMP_BUF_SIZE 10112
  289. #endif
  290. /* ees_reset - reset the count back to zero */
  291. #define ees_reset(ees) (ees)->nsamples = 0; \
  292. (ees)->codestate = EESCS_WAIT
  293. /* ees_event - record and report an event */
  294. #define ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \
  295. ees_report_event((ees), (evcode))
  296. /* Find the precision of the system clock by reading it */
  297. #define USECS 1000000
  298. #define MINSTEP 5 /* some systems increment uS on each call */
  299. #define MAXLOOPS (USECS/9)
  300. /*
  301. * Function prototypes
  302. */
  303. static int msfees_start P((int unit, struct peer *peer));
  304. static void msfees_shutdown P((int unit, struct peer *peer));
  305. static void msfees_poll P((int unit, struct peer *peer));
  306. static void msfees_init P((void));
  307. static void dump_buf P((l_fp *coffs, int from, int to, char *text));
  308. static void ees_report_event P((struct eesunit *ees, int code));
  309. static void ees_receive P((struct recvbuf *rbufp));
  310. static void ees_process P((struct eesunit *ees));
  311. #ifdef QSORT_USES_VOID_P
  312. static int offcompare P((const void *va, const void *vb));
  313. #else
  314. static int offcompare P((const l_fp *a, const l_fp *b));
  315. #endif /* QSORT_USES_VOID_P */
  316. /*
  317. * Transfer vector
  318. */
  319. struct refclock refclock_msfees = {
  320. msfees_start, /* start up driver */
  321. msfees_shutdown, /* shut down driver */
  322. msfees_poll, /* transmit poll message */
  323. noentry, /* not used */
  324. msfees_init, /* initialize driver */
  325. noentry, /* not used */
  326. NOFLAGS /* not used */
  327. };
  328. static void
  329. dump_buf(
  330. l_fp *coffs,
  331. int from,
  332. int to,
  333. char *text
  334. )
  335. {
  336. char buff[DUMP_BUF_SIZE + 80];
  337. int i;
  338. register char *ptr = buff;
  339. sprintf(ptr, text);
  340. for (i=from; i<to; i++)
  341. { while (*ptr) ptr++;
  342. if ((ptr-buff) > DUMP_BUF_SIZE) msyslog(LOG_DEBUG, "D: %s", ptr=buff);
  343. sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295);
  344. }
  345. msyslog(LOG_DEBUG, "D: %s", buff);
  346. }
  347. /* msfees_init - initialize internal ees driver data */
  348. static void
  349. msfees_init(void)
  350. {
  351. register int i;
  352. /* Just zero the data arrays */
  353. memset((char *)eesunits, 0, sizeof eesunits);
  354. memset((char *)unitinuse, 0, sizeof unitinuse);
  355. acceptable_slop.l_ui = 0;
  356. acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
  357. onesec.l_ui = 1;
  358. onesec.l_uf = 0;
  359. /* Initialize fudge factors to default. */
  360. for (i = 0; i < MAXUNITS; i++) {
  361. fudgefactor[i].l_ui = 0;
  362. fudgefactor[i].l_uf = DEFFUDGETIME;
  363. os_delay[i].l_ui = 0;
  364. os_delay[i].l_uf = DEFOSTIME;
  365. inherent_delay[i].l_ui = 0;
  366. inherent_delay[i].l_uf = DEFINHTIME;
  367. offset_fudge[i] = os_delay[i];
  368. L_ADD(&offset_fudge[i], &fudgefactor[i]);
  369. L_ADD(&offset_fudge[i], &inherent_delay[i]);
  370. stratumtouse[i] = 0;
  371. sloppyclockflag[i] = 0;
  372. }
  373. }
  374. /* msfees_start - open the EES devices and initialize data for processing */
  375. static int
  376. msfees_start(
  377. int unit,
  378. struct peer *peer
  379. )
  380. {
  381. register struct eesunit *ees;
  382. register int i;
  383. int fd232 = -1;
  384. char eesdev[20];
  385. struct termios ttyb, *ttyp;
  386. struct refclockproc *pp;
  387. pp = peer->procptr;
  388. if (unit >= MAXUNITS) {
  389. msyslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
  390. unit, MAXUNITS-1);
  391. return 0;
  392. }
  393. if (unitinuse[unit]) {
  394. msyslog(LOG_ERR, "ees clock: unit number %d in use", unit);
  395. return 0;
  396. }
  397. /* Unit okay, attempt to open the devices. We do them both at
  398. * once to make sure we can */
  399. (void) sprintf(eesdev, EES232, unit);
  400. fd232 = open(eesdev, O_RDWR, 0777);
  401. if (fd232 == -1) {
  402. msyslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev);
  403. return 0;
  404. }
  405. #ifdef TIOCEXCL
  406. /* Set for exclusive use */
  407. if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) {
  408. msyslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev);
  409. goto screwed;
  410. }
  411. #endif
  412. /* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */
  413. /* Set port characteristics. If we don't have a STREAMS module or
  414. * a clock line discipline, cooked mode is just usable, even though it
  415. * strips the top bit. The only EES byte which uses the top
  416. * bit is the year, and we don't use that anyway. If we do
  417. * have the line discipline, we choose raw mode, and the
  418. * line discipline code will block up the messages.
  419. */
  420. /* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */
  421. ttyp = &ttyb;
  422. if (tcgetattr(fd232, ttyp) < 0) {
  423. msyslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
  424. goto screwed;
  425. }
  426. ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
  427. ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
  428. ttyp->c_oflag = 0;
  429. ttyp->c_lflag = ICANON;
  430. ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
  431. if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
  432. msyslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
  433. goto screwed;
  434. }
  435. if (tcflush(fd232, TCIOFLUSH) < 0) {
  436. msyslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
  437. goto screwed;
  438. }
  439. inherent_delay[unit].l_uf = INH_DELAY_PPS;
  440. /* offset fudge (how *late* the timestamp is) = fudge + os delays */
  441. offset_fudge[unit] = os_delay[unit];
  442. L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
  443. L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
  444. /* Looks like this might succeed. Find memory for the structure.
  445. * Look to see if there are any unused ones, if not we malloc() one.
  446. */
  447. if (eesunits[unit] != 0) /* The one we want is okay */
  448. ees = eesunits[unit];
  449. else {
  450. /* Look for an unused, but allocated struct */
  451. for (i = 0; i < MAXUNITS; i++) {
  452. if (!unitinuse[i] && eesunits[i] != 0)
  453. break;
  454. }
  455. if (i < MAXUNITS) { /* Reclaim this one */
  456. ees = eesunits[i];
  457. eesunits[i] = 0;
  458. } /* no spare -- make a new one */
  459. else ees = (struct eesunit *) emalloc(sizeof(struct eesunit));
  460. }
  461. memset((char *)ees, 0, sizeof(struct eesunit));
  462. eesunits[unit] = ees;
  463. /* Set up the structures */
  464. ees->peer = peer;
  465. ees->unit = (u_char)unit;
  466. ees->timestarted= current_time;
  467. ees->ttytype = 0;
  468. ees->io.clock_recv= ees_receive;
  469. ees->io.srcclock= (caddr_t)ees;
  470. ees->io.datalen = 0;
  471. ees->io.fd = fd232;
  472. /* Okay. Push one of the two (linked into the kernel, or dynamically
  473. * loaded) STREAMS module, and give it to the I/O code to start
  474. * receiving stuff.
  475. */
  476. #ifdef STREAM
  477. {
  478. int rc1;
  479. /* Pop any existing onews first ... */
  480. while (ioctl(fd232, I_POP, 0 ) >= 0) ;
  481. /* Now try pushing either of the possible modules */
  482. if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 &&
  483. ioctl(fd232, I_PUSH, STREAM_PP2) < 0) {
  484. msyslog(LOG_ERR,
  485. "ees clock: Push of `%s' and `%s' to %s failed %m",
  486. STREAM_PP1, STREAM_PP2, eesdev);
  487. goto screwed;
  488. }
  489. else {
  490. NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
  491. msyslog(LOG_INFO, "I: ees clock: PUSHed %s on %s",
  492. (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev);
  493. ees->ttytype |= T_PPS;
  494. }
  495. }
  496. #endif /* STREAM */
  497. /* Add the clock */
  498. if (!io_addclock(&ees->io)) {
  499. /* Oh shit. Just close and return. */
  500. msyslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev);
  501. goto screwed;
  502. }
  503. /* All done. Initialize a few random peer variables, then
  504. * return success. */
  505. peer->precision = sys_precision;
  506. peer->stratum = stratumtouse[unit];
  507. if (stratumtouse[unit] <= 1) {
  508. memcpy((char *)&pp->refid, EESREFID, 4);
  509. if (unit > 0 && unit < 10)
  510. ((char *)&pp->refid)[3] = '0' + unit;
  511. } else {
  512. peer->refid = htonl(EESHSREFID);
  513. }
  514. unitinuse[unit] = 1;
  515. pp->unitptr = (caddr_t) &eesunits[unit];
  516. pp->clockdesc = EESDESCRIPTION;
  517. msyslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
  518. return (1);
  519. screwed:
  520. if (fd232 != -1)
  521. (void) close(fd232);
  522. return (0);
  523. }
  524. /* msfees_shutdown - shut down a EES clock */
  525. static void
  526. msfees_shutdown(
  527. int unit,
  528. struct peer *peer
  529. )
  530. {
  531. register struct eesunit *ees;
  532. if (unit >= MAXUNITS) {
  533. msyslog(LOG_ERR,
  534. "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)",
  535. unit, MAXUNITS);
  536. return;
  537. }
  538. if (!unitinuse[unit]) {
  539. msyslog(LOG_ERR,
  540. "ees clock: INTERNAL ERROR, unit number %d not in use", unit);
  541. return;
  542. }
  543. /* Tell the I/O module to turn us off. We're history. */
  544. ees = eesunits[unit];
  545. io_closeclock(&ees->io);
  546. unitinuse[unit] = 0;
  547. }
  548. /* ees_report_event - note the occurance of an event */
  549. static void
  550. ees_report_event(
  551. struct eesunit *ees,
  552. int code
  553. )
  554. {
  555. if (ees->status != (u_char)code) {
  556. ees->status = (u_char)code;
  557. if (code != CEVNT_NOMINAL)
  558. ees->lastevent = (u_char)code;
  559. /* Should report event to trap handler in here.
  560. * Soon...
  561. */
  562. }
  563. }
  564. /* ees_receive - receive data from the serial interface on an EES clock */
  565. static void
  566. ees_receive(
  567. struct recvbuf *rbufp
  568. )
  569. {
  570. register int n_sample;
  571. register int day;
  572. register struct eesunit *ees;
  573. register u_char *dpt; /* Data PoinTeR: move along ... */
  574. register u_char *dpend; /* Points just *after* last data char */
  575. register char *cp;
  576. l_fp tmp;
  577. int call_pps_sample = 0;
  578. l_fp pps_arrvstamp;
  579. int sincelast;
  580. int pps_step = 0;
  581. int suspect_4ms_step = 0;
  582. struct ppsclockev ppsclockev;
  583. long *ptr = (long *) &ppsclockev;
  584. int rc;
  585. int request;
  586. #ifdef HAVE_CIOGETEV
  587. request = CIOGETEV;
  588. #endif
  589. #ifdef HAVE_TIOCGPPSEV
  590. request = TIOCGPPSEV;
  591. #endif
  592. /* Get the clock this applies to and a pointer to the data */
  593. ees = (struct eesunit *)rbufp->recv_srcclock;
  594. dpt = (u_char *)&rbufp->recv_space;
  595. dpend = dpt + rbufp->recv_length;
  596. if ((dbg & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
  597. printf("[%d] ", rbufp->recv_length);
  598. /* Check out our state and process appropriately */
  599. switch (ees->codestate) {
  600. case EESCS_WAIT:
  601. /* Set an initial guess at the timestamp as the recv time.
  602. * If just running in CBREAK mode, we can't improve this.
  603. * If we have the CLOCK Line Discipline, PPSCD, or sime such,
  604. * then we will do better later ....
  605. */
  606. ees->arrvtime = rbufp->recv_time;
  607. ees->codestate = EESCS_GOTSOME;
  608. ees->lencode = 0;
  609. /*FALLSTHROUGH*/
  610. case EESCS_GOTSOME:
  611. cp = &(ees->lastcode[ees->lencode]);
  612. /* Gobble the bytes until the final (possibly stripped) 0xff */
  613. while (dpt < dpend && (*dpt & 0x7f) != 0x7f) {
  614. *cp++ = (char)*dpt++;
  615. ees->lencode++;
  616. /* Oh dear -- too many bytes .. */
  617. if (ees->lencode > LENEESPRT) {
  618. NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
  619. msyslog(LOG_INFO,
  620. "I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]",
  621. ees->lencode, dpend - dpt, LENEESPRT,
  622. #define D(x) (ees->lastcode[x])
  623. D(0), D(1), D(2), D(3), D(4), D(5), D(6),
  624. D(7), D(8), D(9), D(10), D(11), D(12));
  625. #undef D
  626. ees->badformat++;
  627. ees->reason = CODEREASON + 1;
  628. ees_event(ees, CEVNT_BADREPLY);
  629. ees_reset(ees);
  630. return;
  631. }
  632. }
  633. /* Gave up because it was end of the buffer, rather than ff */
  634. if (dpt == dpend) {
  635. /* Incomplete. Wait for more. */
  636. if (dbg & DB_LOG_AWAITMORE)
  637. msyslog(LOG_INFO,
  638. "I: ees clock %d: %p == %p: await more",
  639. ees->unit, dpt, dpend);
  640. return;
  641. }
  642. /* This shouldn't happen ... ! */
  643. if ((*dpt & 0x7f) != 0x7f) {
  644. msyslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt);
  645. ees->badformat++;
  646. ees->reason = CODEREASON + 2;
  647. ees_event(ees, CEVNT_BADREPLY);
  648. ees_reset(ees);
  649. return;
  650. }
  651. /* Skip the 0xff */
  652. dpt++;
  653. /* Finally, got a complete buffer. Mainline code will
  654. * continue on. */
  655. cp = ees->lastcode;
  656. break;
  657. default:
  658. msyslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
  659. ees->unit, ees->codestate);
  660. ees->reason = CODEREASON + 5;
  661. ees_event(ees, CEVNT_FAULT);
  662. ees_reset(ees);
  663. return;
  664. }
  665. /* Boy! After all that crap, the lastcode buffer now contains
  666. * something we hope will be a valid time code. Do length
  667. * checks and sanity checks on constant data.
  668. */
  669. ees->codestate = EESCS_WAIT;
  670. ees->lasttime = current_time;
  671. if (ees->lencode != LENEESPRT) {
  672. ees->badformat++;
  673. ees->reason = CODEREASON + 6;
  674. ees_event(ees, CEVNT_BADREPLY);
  675. ees_reset(ees);
  676. return;
  677. }
  678. cp = ees->lastcode;
  679. /* Check that centisecond is zero */
  680. if (cp[EESM_CSEC] != 0) {
  681. ees->baddata++;
  682. ees->reason = CODEREASON + 7;
  683. ees_event(ees, CEVNT_BADREPLY);
  684. ees_reset(ees);
  685. return;
  686. }
  687. /* Check flag formats */
  688. if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) {
  689. ees->badformat++;
  690. ees->reason = CODEREASON + 8;
  691. ees_event(ees, CEVNT_BADREPLY);
  692. ees_reset(ees);
  693. return;
  694. }
  695. if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) {
  696. ees->badformat++;
  697. ees->reason = CODEREASON + 9;
  698. ees_event(ees, CEVNT_BADREPLY);
  699. ees_reset(ees);
  700. return;
  701. }
  702. if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) {
  703. ees->badformat++;
  704. ees->reason = CODEREASON + 10;
  705. ees_event(ees, CEVNT_BADREPLY);
  706. ees_reset(ees);
  707. return;
  708. }
  709. /* So far, so good. Compute day, hours, minutes, seconds,
  710. * time zone. Do range checks on these.
  711. */
  712. #define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) )
  713. #define istrue(x) ((x)?1:0)
  714. ees->second = bcdunpack(cp[EESM_SEC]); /* second */
  715. ees->minute = bcdunpack(cp[EESM_MIN]); /* minute */
  716. ees->hour = bcdunpack(cp[EESM_HOUR]); /* hour */
  717. day = bcdunpack(cp[EESM_DAY]); /* day of month */
  718. switch (bcdunpack(cp[EESM_MON])) { /* month */
  719. /* Add in lengths of all previous months. Add one more
  720. if it is a leap year and after February.
  721. */
  722. case 12: day += NOV; /*FALLSTHROUGH*/
  723. case 11: day += OCT; /*FALLSTHROUGH*/
  724. case 10: day += SEP; /*FALLSTHROUGH*/
  725. case 9: day += AUG; /*FALLSTHROUGH*/
  726. case 8: day += JUL; /*FALLSTHROUGH*/
  727. case 7: day += JUN; /*FALLSTHROUGH*/
  728. case 6: day += MAY; /*FALLSTHROUGH*/
  729. case 5: day += APR; /*FALLSTHROUGH*/
  730. case 4: day += MAR; /*FALLSTHROUGH*/
  731. case 3: day += FEB;
  732. if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/
  733. case 2: day += JAN; /*FALLSTHROUGH*/
  734. case 1: break;
  735. default: ees->baddata++;
  736. ees->reason = CODEREASON + 11;
  737. ees_event(ees, CEVNT_BADDATE);
  738. ees_reset(ees);
  739. return;
  740. }
  741. ees->day = day;
  742. /* Get timezone. The clocktime routine wants the number
  743. * of hours to add to the delivered time to get UT.
  744. * Currently -1 if BST flag set, 0 otherwise. This
  745. * is the place to tweak things if double summer time
  746. * ever happens.
  747. */
  748. ees->tz = istrue(cp[EESM_BST]) ? -1 : 0;
  749. if (ees->day > 366 || ees->day < 1 ||
  750. ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
  751. ees->baddata++;
  752. ees->reason = CODEREASON + 12;
  753. ees_event(ees, CEVNT_BADDATE);
  754. ees_reset(ees);
  755. return;
  756. }
  757. n_sample = ees->nsamples;
  758. /* Now, compute the reference time value: text -> tmp.l_ui */
  759. if (!clocktime(ees->day, ees->hour, ees->minute, ees->second,
  760. ees->tz, rbufp->recv_time.l_ui, &ees->yearstart,
  761. &tmp.l_ui)) {
  762. ees->baddata++;
  763. ees->reason = CODEREASON + 13;
  764. ees_event(ees, CEVNT_BADDATE);
  765. ees_reset(ees);
  766. return;
  767. }
  768. tmp.l_uf = 0;
  769. /* DON'T use ees->arrvtime -- it may be < reftime */
  770. ees->lastsampletime = tmp;
  771. /* If we are synchronised to the radio, update the reference time.
  772. * Also keep a note of when clock was last good.
  773. */
  774. if (istrue(cp[EESM_MSFOK])) {
  775. ees->reftime = tmp;
  776. ees->clocklastgood = current_time;
  777. }
  778. /* Compute the offset. For the fractional part of the
  779. * offset we use the expected delay for the message.
  780. */
  781. ees->codeoffsets[n_sample].l_ui = tmp.l_ui;
  782. ees->codeoffsets[n_sample].l_uf = 0;
  783. /* Number of seconds since the last step */
  784. sincelast = this_uisec - ees->last_step;
  785. memset((char *) &ppsclockev, 0, sizeof ppsclockev);
  786. rc = ioctl(ees->io.fd, request, (char *) &ppsclockev);
  787. if (dbg & DB_PRINT_EV) fprintf(stderr,
  788. "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08lx %08lx %ld\n",
  789. DB_PRINT_EV, ees->unit, ees->io.fd, request, is_pps(ees),
  790. rc, errno, ptr[0], ptr[1], ptr[2]);
  791. /* If we managed to get the time of arrival, process the info */
  792. if (rc >= 0) {
  793. int conv = -1;
  794. pps_step = ppsclockev.serial - ees->last_pps_no;
  795. /* Possible that PPS triggered, but text message didn't */
  796. if (pps_step == 2) msyslog(LOG_ERR, "pps step = 2 @ %02d", ees->second);
  797. if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1;
  798. if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4;
  799. /* allow for single loss of PPS only */
  800. if (pps_step != 1 && pps_step != 2)
  801. fprintf(stderr, "PPS step: %d too far off %ld (%d)\n",
  802. ppsclockev.serial, ees->last_pps_no, pps_step);
  803. else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
  804. fprintf(stderr, "buftvtots failed\n");
  805. else { /* if ((ABS(time difference) - 0.25) < 0)
  806. * then believe it ...
  807. */
  808. l_fp diff;
  809. diff = pps_arrvstamp;
  810. conv = 0;
  811. L_SUB(&diff, &ees->arrvtime);
  812. if (dbg & DB_PRINT_CDT)
  813. printf("[%x] Have %lx.%08lx and %lx.%08lx -> %lx.%08lx @ %s",
  814. DB_PRINT_CDT, (long)ees->arrvtime.l_ui, (long)ees->arrvtime.l_uf,
  815. (long)pps_arrvstamp.l_ui, (long)pps_arrvstamp.l_uf,
  816. (long)diff.l_ui, (long)diff.l_uf,
  817. ctime(&(ppsclockev.tv.tv_sec)));
  818. if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
  819. L_SUB(&diff, &acceptable_slop);
  820. if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
  821. ees->arrvtime = pps_arrvstamp;
  822. conv++;
  823. call_pps_sample++;
  824. }
  825. /* Some loss of some signals around sec = 1 */
  826. else if (ees->second == 1) {
  827. diff = pps_arrvstamp;
  828. L_ADD(&diff, &onesec);
  829. L_SUB(&diff, &ees->arrvtime);
  830. if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
  831. L_SUB(&diff, &acceptable_slop);
  832. msyslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
  833. pps_arrvstamp.l_ui - ees->arrvtime.l_ui,
  834. pps_arrvstamp.l_uf,
  835. ees->arrvtime.l_uf,
  836. diff.l_ui, diff.l_uf,
  837. (int)ppsclockev.tv.tv_usec,
  838. ctime(&(ppsclockev.tv.tv_sec)));
  839. if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
  840. suspect_4ms_step |= 2;
  841. ees->arrvtime = pps_arrvstamp;
  842. L_ADD(&ees->arrvtime, &onesec);
  843. conv++;
  844. call_pps_sample++;
  845. }
  846. }
  847. }
  848. ees->last_pps_no = ppsclockev.serial;
  849. if (dbg & DB_PRINT_CDTC)
  850. printf(
  851. "[%x] %08lx %08lx %d u%d (%d %d)\n",
  852. DB_PRINT_CDTC, (long)pps_arrvstamp.l_ui,
  853. (long)pps_arrvstamp.l_uf, conv, ees->unit,
  854. call_pps_sample, pps_step);
  855. }
  856. /* See if there has been a 4ms jump at a minute boundry */
  857. { l_fp delta;
  858. #define delta_isec delta.l_ui
  859. #define delta_ssec delta.l_i
  860. #define delta_sfsec delta.l_f
  861. long delta_f_abs;
  862. delta.l_i = ees->arrvtime.l_i;
  863. delta.l_f = ees->arrvtime.l_f;
  864. L_SUB(&delta, &ees->last_l);
  865. delta_f_abs = delta_sfsec;
  866. if (delta_f_abs < 0) delta_f_abs = -delta_f_abs;
  867. /* Dump the deltas each minute */
  868. if (dbg & DB_DUMP_DELTAS)
  869. { if (/*0 <= ees->second && */
  870. ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec;
  871. /* Dump on second 1, as second 0 sometimes missed */
  872. if (ees->second == 1) {
  873. char text[16 * ((sizeof deltas) / (sizeof deltas[0]))];
  874. char *cptr=text;
  875. int i;
  876. for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) {
  877. sprintf(cptr, " %d.%04d",
  878. msec(deltas[i]), subms(deltas[i]));
  879. while (*cptr) cptr++;
  880. }
  881. msyslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
  882. msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
  883. msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
  884. text+1);
  885. for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
  886. }
  887. }
  888. /* Lets see if we have a 4 mS step at a minute boundaary */
  889. if ( ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) &&
  890. (delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) &&
  891. (ees->second == 0 || ees->second == 1 || ees->second == 2) &&
  892. (sincelast < 0 || sincelast > 122)
  893. ) { /* 4ms jump at min boundry */
  894. int old_sincelast;
  895. int count=0;
  896. int sum = 0;
  897. /* Yes -- so compute the ramp time */
  898. if (ees->last_step == 0) sincelast = 0;
  899. old_sincelast = sincelast;
  900. /* First time in, just set "ees->last_step" */
  901. if(ees->last_step) {
  902. int other_step = 0;
  903. int third_step = 0;
  904. int this_step = (sincelast + (60 /2)) / 60;
  905. int p_step = ees->this_step;
  906. int p;
  907. ees->last_steps[p_step] = this_step;
  908. p= p_step;
  909. p_step++;
  910. if (p_step >= LAST_STEPS) p_step = 0;
  911. ees->this_step = p_step;
  912. /* Find the "average" interval */
  913. while (p != p_step) {
  914. int this = ees->last_steps[p];
  915. if (this == 0) break;
  916. if (this != this_step) {
  917. if (other_step == 0 && (
  918. this== (this_step +2) ||
  919. this== (this_step -2) ||
  920. this== (this_step +1) ||
  921. this== (this_step -1)))
  922. other_step = this;
  923. if (other_step != this) {
  924. int idelta = (this_step - other_step);
  925. if (idelta < 0) idelta = - idelta;
  926. if (third_step == 0 && (
  927. (idelta == 1) ? (
  928. this == (other_step +1) ||
  929. this == (other_step -1) ||
  930. this == (this_step +1) ||
  931. this == (this_step -1))
  932. :
  933. (
  934. this == (this_step + other_step)/2
  935. )
  936. )) third_step = this;
  937. if (third_step != this) break;
  938. }
  939. }
  940. sum += this;
  941. p--;
  942. if (p < 0) p += LAST_STEPS;
  943. count++;
  944. }
  945. msyslog(LOG_ERR, "MSF%d: %d: This=%d (%d), other=%d/%d, sum=%d, count=%d, pps_step=%d, suspect=%x", ees->unit, p, ees->last_steps[p], this_step, other_step, third_step, sum, count, pps_step, suspect_4ms_step);
  946. if (count != 0) sum = ((sum * 60) + (count /2)) / count;
  947. #define SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS])
  948. msyslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
  949. ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
  950. SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
  951. printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
  952. ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
  953. SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
  954. #undef SV
  955. ees->jump_fsecs = delta_sfsec;
  956. ees->using_ramp = 1;
  957. if (sincelast > 170)
  958. ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs);
  959. else ees->last_step_late = 30;
  960. if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30;
  961. if (ees->last_step_late < 0) ees->last_step_late = 0;
  962. if (ees->last_step_late >= 60) ees->last_step_late = 59;
  963. sincelast = 0;
  964. }
  965. else { /* First time in -- just save info */
  966. ees->last_step_late = 30;
  967. ees->jump_fsecs = delta_sfsec;
  968. ees->using_ramp = 1;
  969. sum = 4 * 60;
  970. }
  971. ees->last_step = this_uisec;
  972. printf("MSF%d: d=%3ld.%04ld@%d :%d:%d:$%d:%d:%d\n",
  973. ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
  974. ees->second, old_sincelast, ees->last_step_late, count, sum,
  975. ees->last_step_secs);
  976. msyslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
  977. ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second,
  978. old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
  979. if (sum) ees->last_step_secs = sum;
  980. }
  981. /* OK, so not a 4ms step at a minute boundry */
  982. else {
  983. if (suspect_4ms_step) msyslog(LOG_ERR,
  984. "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
  985. ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
  986. msec(EES_STEP_F - EES_STEP_F_GRACE),
  987. subms(EES_STEP_F - EES_STEP_F_GRACE),
  988. (int)msec(delta_f_abs),
  989. (int)subms(delta_f_abs),
  990. msec(EES_STEP_F + EES_STEP_F_GRACE),
  991. subms(EES_STEP_F + EES_STEP_F_GRACE),
  992. ees->second,
  993. sincelast);
  994. if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) {
  995. static int ees_step_notes = EES_STEP_NOTES;
  996. if (ees_step_notes > 0) {
  997. ees_step_notes--;
  998. printf("MSF%d: D=%3ld.%04ld@%02d :%d%s\n",
  999. ees->unit, (long)msec(delta_sfsec), (long)subms(delta_sfsec),
  1000. ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
  1001. msyslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
  1002. ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
  1003. }
  1004. }
  1005. }
  1006. }
  1007. ees->last_l = ees->arrvtime;
  1008. /* IF we have found that it's ramping
  1009. * && it's within twice the expected ramp period
  1010. * && there is a non zero step size (avoid /0 !)
  1011. * THEN we twiddle things
  1012. */
  1013. if (ees->using_ramp &&
  1014. sincelast < (ees->last_step_secs)*2 &&
  1015. ees->last_step_secs)
  1016. { long sec_of_ramp = sincelast + ees->last_step_late;
  1017. long fsecs;
  1018. l_fp inc;
  1019. /* Ramp time may vary, so may ramp for longer than last time */
  1020. if (sec_of_ramp > (ees->last_step_secs + 120))
  1021. sec_of_ramp = ees->last_step_secs;
  1022. /* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */
  1023. fsecs = sec_of_ramp * (ees->jump_fsecs / ees->last_step_secs);
  1024. if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
  1025. "[%x] MSF%d: %3ld/%03d -> d=%11ld (%d|%ld)",
  1026. DB_LOG_DELTAS,
  1027. ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
  1028. pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
  1029. if (dbg & DB_PRINT_DELTAS) printf(
  1030. "MSF%d: %3ld/%03d -> d=%11ld (%ld|%ld)\n",
  1031. ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
  1032. (long)pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
  1033. /* Must sign extend the result */
  1034. inc.l_i = (fsecs < 0) ? -1 : 0;
  1035. inc.l_f = fsecs;
  1036. if (dbg & DB_INC_PPS)
  1037. { L_SUB(&pps_arrvstamp, &inc);
  1038. L_SUB(&ees->arrvtime, &inc);
  1039. }
  1040. else
  1041. { L_ADD(&pps_arrvstamp, &inc);
  1042. L_ADD(&ees->arrvtime, &inc);
  1043. }
  1044. }
  1045. else {
  1046. if (dbg & DB_LOG_DELTAS) msyslog(LOG_ERR,
  1047. "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x",
  1048. DB_LOG_DELTAS,
  1049. ees->unit, ees->using_ramp,
  1050. sincelast,
  1051. (ees->last_step_secs)*2,
  1052. ees->last_step_secs);
  1053. if (dbg & DB_PRINT_DELTAS) printf(
  1054. "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n",
  1055. DB_LOG_DELTAS,
  1056. ees->unit, ees->using_ramp,
  1057. sincelast,
  1058. (ees->last_step_secs)*2,
  1059. ees->last_step_secs);
  1060. }
  1061. L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
  1062. L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
  1063. if (call_pps_sample && !(dbg & DB_NO_PPS)) {
  1064. /* Sigh -- it expects its args negated */
  1065. L_NEG(&pps_arrvstamp);
  1066. /*
  1067. * I had to disable this here, since it appears there is no pointer to the
  1068. * peer structure.
  1069. *
  1070. (void) pps_sample(peer, &pps_arrvstamp);
  1071. */
  1072. }
  1073. /* Subtract off the local clock time stamp */
  1074. L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime);
  1075. if (dbg & DB_LOG_SAMPLES) msyslog(LOG_ERR,
  1076. "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s",
  1077. ees->unit, DB_LOG_DELTAS, n_sample,
  1078. ees->codeoffsets[n_sample].l_f,
  1079. ees->codeoffsets[n_sample].l_f / 4295,
  1080. pps_arrvstamp.l_f,
  1081. pps_arrvstamp.l_f /4295,
  1082. (dbg & DB_NO_PPS) ? " [no PPS]" : "");
  1083. if (ees->nsamples++ == NCODES-1) ees_process(ees);
  1084. /* Done! */
  1085. }
  1086. /* offcompare - auxiliary comparison routine for offset sort */
  1087. #ifdef QSORT_USES_VOID_P
  1088. static int
  1089. offcompare(
  1090. const void *va,
  1091. const void *vb
  1092. )
  1093. {
  1094. const l_fp *a = (const l_fp *)va;
  1095. const l_fp *b = (const l_fp *)vb;
  1096. return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
  1097. }
  1098. #else
  1099. static int
  1100. offcompare(
  1101. const l_fp *a,
  1102. const l_fp *b
  1103. )
  1104. {
  1105. return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
  1106. }
  1107. #endif /* QSORT_USES_VOID_P */
  1108. /* ees_process - process a pile of samples from the clock */
  1109. static void
  1110. ees_process(
  1111. struct eesunit *ees
  1112. )
  1113. {
  1114. static int last_samples = -1;
  1115. register int i, j;
  1116. register int noff;
  1117. register l_fp *coffs = ees->codeoffsets;
  1118. l_fp offset, tmp;
  1119. double dispersion; /* ++++ */
  1120. int lostsync, isinsync;
  1121. int samples = ees->nsamples;
  1122. int samplelog = 0; /* keep "gcc -Wall" happy ! */
  1123. int samplereduce = (samples + 1) / 2;
  1124. double doffset;
  1125. /* Reset things to zero so we don't have to worry later */
  1126. ees_reset(ees);
  1127. if (sloppyclockflag[ees->unit]) {
  1128. samplelog = (samples < 2) ? 0 :
  1129. (samples < 5) ? 1 :
  1130. (samples < 9) ? 2 :
  1131. (samples < 17) ? 3 :
  1132. (samples < 33) ? 4 : 5;
  1133. samplereduce = (1 << samplelog);
  1134. }
  1135. if (samples != last_samples &&
  1136. ((samples != (last_samples-1)) || samples < 3)) {
  1137. msyslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....",
  1138. samples, last_samples, samplereduce);
  1139. last_samples = samples;
  1140. }
  1141. if (samples < 1) return;
  1142. /* If requested, dump the raw data we have in the buffer */
  1143. if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:");
  1144. /* Sort the offsets, trim off the extremes, then choose one. */
  1145. qsort(
  1146. #ifdef QSORT_USES_VOID_P
  1147. (void *)
  1148. #else
  1149. (char *)
  1150. #endif
  1151. coffs, (size_t)samples, sizeof(l_fp), offcompare);
  1152. noff = samples;
  1153. i = 0;
  1154. while ((noff - i) > samplereduce) {
  1155. /* Trim off the sample which is further away
  1156. * from the median. We work this out by doubling
  1157. * the median, subtracting off the end samples, and
  1158. * looking at the sign of the answer, using the
  1159. * identity (c-b)-(b-a) == 2*b-a-c
  1160. */
  1161. tmp = coffs[(noff + i)/2];
  1162. L_ADD(&tmp, &tmp);
  1163. L_SUB(&tmp, &coffs[i]);
  1164. L_SUB(&tmp, &coffs[noff-1]);
  1165. if (L_ISNEG(&tmp)) noff--; else i++;
  1166. }
  1167. /* If requested, dump the reduce data we have in the buffer */
  1168. if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced to:");
  1169. /* What we do next depends on the setting of the sloppy clock flag.
  1170. * If it is on, average the remainder to derive our estimate.
  1171. * Otherwise, just pick a representative value from the remaining stuff
  1172. */
  1173. if (sloppyclockflag[ees->unit]) {
  1174. offset.l_ui = offset.l_uf = 0;
  1175. for (j = i; j < noff; j++)
  1176. L_ADD(&offset, &coffs[j]);
  1177. for (j = samplelog; j > 0; j--)
  1178. L_RSHIFTU(&offset);
  1179. }
  1180. else offset = coffs[i+BESTSAMPLE];
  1181. /* Compute the dispersion as the difference between the
  1182. * lowest and highest offsets that remain in the
  1183. * consideration list.
  1184. *
  1185. * It looks like MOST clocks have MOD (max error), so halve it !
  1186. */
  1187. tmp = coffs[noff-1];
  1188. L_SUB(&tmp, &coffs[i]);
  1189. #define FRACT_SEC(n) ((1 << 30) / (n/2))
  1190. dispersion = LFPTOFP(&tmp) / 2; /* ++++ */
  1191. if (dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) msyslog(
  1192. (dbg & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO,
  1193. "I: [%x] Offset=%06d (%d), disp=%f%s [%d], %d %d=%d %d:%d %d=%d %d",
  1194. dbg & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE),
  1195. offset.l_f / 4295, offset.l_f,
  1196. (dispersion * 1526) / 100,
  1197. (sloppyclockflag[ees->unit]) ? " by averaging" : "",
  1198. FRACT_SEC(10) / 4295,
  1199. (coffs[0].l_f) / 4295,
  1200. i,
  1201. (coffs[i].l_f) / 4295,
  1202. (coffs[samples/2].l_f) / 4295,
  1203. (coffs[i+BESTSAMPLE].l_f) / 4295,
  1204. noff-1,
  1205. (coffs[noff-1].l_f) / 4295,
  1206. (coffs[samples-1].l_f) / 4295);
  1207. /* Are we playing silly wotsits ?
  1208. * If we are using all data, see if there is a "small" delta,
  1209. * and if so, blurr this with 3/4 of the delta from the last value
  1210. */
  1211. if (ees->usealldata && ees->offset.l_uf) {
  1212. long diff = (long) (ees->offset.l_uf - offset.l_uf);
  1213. /* is the delta small enough ? */
  1214. if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) {
  1215. int samd = (64 * 4) / samples;
  1216. long new;
  1217. if (samd < 2) samd = 2;
  1218. new = offset.l_uf + ((diff * (samd -1)) / samd);
  1219. /* Sign change -> need to fix up int part */
  1220. if ((new & 0x80000000) !=
  1221. (((long) offset.l_uf) & 0x80000000))
  1222. { NLOG(NLOG_CLOCKINFO) /* conditional if clause for conditional syslog */
  1223. msyslog(LOG_INFO, "I: %lx != %lx (%lx %lx), so add %d",
  1224. new & 0x80000000,
  1225. ((long) offset.l_uf) & 0x80000000,
  1226. new, (long) offset.l_uf,
  1227. (new < 0) ? -1 : 1);
  1228. offset.l_ui += (new < 0) ? -1 : 1;
  1229. }
  1230. dispersion /= 4;
  1231. if (dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) msyslog(
  1232. (dbg & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO,
  1233. "I: [%x] Smooth data: %ld -> %ld, dispersion now %f",
  1234. dbg & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE),
  1235. ((long) offset.l_uf) / 4295, new / 4295,
  1236. (dispersion * 1526) / 100);
  1237. offset.l_uf = (unsigned long) new;
  1238. }
  1239. else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
  1240. (dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
  1241. "[%x] No smooth as delta not %d < %ld < %d",
  1242. dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
  1243. - FRACT_SEC(100), diff, FRACT_SEC(100));
  1244. }
  1245. else if (dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) msyslog(
  1246. (dbg & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
  1247. "I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)",
  1248. dbg & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
  1249. ees->usealldata, ees->offset.l_f, ees->offset.l_uf,
  1250. offset.l_f, ees->offset.l_f - offset.l_f);
  1251. /* Collect offset info for debugging info */
  1252. ees->offset = offset;
  1253. ees->lowoffset = coffs[i];
  1254. ees->highoffset = coffs[noff-1];
  1255. /* Determine synchronization status. Can be unsync'd either
  1256. * by a report from the clock or by a leap hold.
  1257. *
  1258. * Loss of the radio signal for a short time does not cause
  1259. * us to go unsynchronised, since the receiver keeps quite
  1260. * good time on its own. The spec says 20ms in 4 hours; the
  1261. * observed drift in our clock (Cambridge) is about a second
  1262. * a day, but even that keeps us within the inherent tolerance
  1263. * of the clock for about 15 minutes. Observation shows that
  1264. * the typical "short" outage is 3 minutes, so to allow us
  1265. * to ride out those, we will give it 5 minutes.
  1266. */
  1267. lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0;
  1268. isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1;
  1269. /* Done. Use time of last good, synchronised code as the
  1270. * reference time, and lastsampletime as the receive time.
  1271. */
  1272. if (ees->fix_pending) {
  1273. msyslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
  1274. ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
  1275. ees->fix_pending = 0;
  1276. }
  1277. LFPTOD(&offset, doffset);
  1278. refclock_receive(ees->peer);
  1279. ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL);
  1280. }
  1281. /* msfees_poll - called by the transmit procedure */
  1282. static void
  1283. msfees_poll(
  1284. int unit,
  1285. struct peer *peer
  1286. )
  1287. {
  1288. if (unit >= MAXUNITS) {
  1289. msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid",
  1290. unit);
  1291. return;
  1292. }
  1293. if (!unitinuse[unit]) {
  1294. msyslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused",
  1295. unit);
  1296. return;
  1297. }
  1298. ees_process(eesunits[unit]);
  1299. if ((current_time - eesunits[unit]->lasttime) > 150)
  1300. ees_event(eesunits[unit], CEVNT_FAULT);
  1301. }
  1302. #else
  1303. int refclock_msfees_bs;
  1304. #endif /* REFCLOCK */