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