parse_refclock(const char *line)
{
int i, n, poll, dpoll, filter_length, pps_rate;
- unsigned long ref_id;
+ unsigned long ref_id, lock_ref_id;
double offset, delay;
const char *tmp;
char name[5], cmd[10 + 1], *param;
offset = 0.0;
delay = 1e-9;
ref_id = 0;
+ lock_ref_id = 0;
if (sscanf(line, "%4s%n", name, &n) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock driver name at line %d", line_number);
if (sscanf(line, "%4s%n", (char *)ref, &n) != 1)
break;
ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
+ } else if (!strncasecmp(cmd, "lock", 4)) {
+ if (sscanf(line, "%4s%n", (char *)ref, &n) != 1)
+ break;
+ lock_ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
} else if (!strncasecmp(cmd, "poll", 4)) {
if (sscanf(line, "%d%n", &poll, &n) != 1) {
break;
refclock_sources[i].offset = offset;
refclock_sources[i].delay = delay;
refclock_sources[i].ref_id = ref_id;
+ refclock_sources[i].lock_ref_id = lock_ref_id;
n_refclock_sources++;
}
int length;
int index;
int used;
+ int last;
struct FilterSample *samples;
};
int pps_rate;
struct MedianFilter filter;
unsigned long ref_id;
+ unsigned long lock_ref;
double offset;
double delay;
SCH_TimeoutID timeout_id;
static void filter_fini(struct MedianFilter *filter);
static void filter_reset(struct MedianFilter *filter);
static void filter_add_sample(struct MedianFilter *filter, struct timeval *sample_time, double offset);
+static int filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset);
static int filter_get_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset, double *dispersion);
static void filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset);
inst->driver_polled = 0;
inst->leap_status = 0;
inst->pps_rate = params->pps_rate;
+ inst->lock_ref = params->lock_ref_id;
inst->offset = params->offset;
inst->delay = params->delay;
inst->timeout_id = -1;
void
RCL_StartRefclocks(void)
{
- int i;
+ int i, j;
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, NULL);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
+
+ if (inst->lock_ref) {
+ /* Replace lock refid with index to refclocks */
+ for (j = 0; j < n_sources && refclocks[j].ref_id != inst->lock_ref; j++)
+ ;
+ inst->lock_ref = (j < n_sources) ? j : -1;
+ } else
+ inst->lock_ref = -1;
}
if (n_sources > 0)
rate = instance->pps_rate;
assert(rate > 0);
- /* Ignore the pulse if we are not well synchronized */
-
- REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum,
- &ref_id, &ref_time, &root_delay, &root_dispersion);
- distance = fabs(root_delay) / 2 + root_dispersion;
-
- if (!is_synchronised || distance >= 0.5 / rate) {
-#if 0
- LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse dropped second=%.9f sync=%d dist=%.9f",
- second, is_synchronised, distance);
-#endif
- /* Drop also all stored samples */
- filter_reset(&instance->filter);
- return 0;
- }
-
offset = -second - correction + instance->offset;
/* Adjust the offset to [-0.5/rate, 0.5/rate) interval */
else if (offset >= 0.5 / rate)
offset -= 1.0 / rate;
+ if (instance->lock_ref != -1) {
+ struct timeval ref_sample_time;
+ double sample_diff, ref_offset, shift;
+
+ if (!filter_get_last_sample(&refclocks[instance->lock_ref].filter,
+ &ref_sample_time, &ref_offset))
+ return 0;
+
+ UTI_DiffTimevalsToDouble(&sample_diff, &cooked_time, &ref_sample_time);
+ if (fabs(sample_diff) >= 2.0 / rate)
+ return 0;
+
+ /* Align the offset to the reference sample */
+ if ((ref_offset - offset) >= 0.0)
+ shift = (long)((ref_offset - offset) * rate + 0.5) / (double)rate;
+ else
+ shift = (long)((ref_offset - offset) * rate - 0.5) / (double)rate;
+
+ offset += shift;
+
+ if (fabs(ref_offset - offset) >= 0.2 / rate)
+ return 0;
+
+#if 0
+ LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
+ second, offset, ref_offset - offset, sample_diff);
+#endif
+ } else {
+ /* Ignore the pulse if we are not well synchronized */
+
+ REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum,
+ &ref_id, &ref_time, &root_delay, &root_dispersion);
+ distance = fabs(root_delay) / 2 + root_dispersion;
+
+ if (!is_synchronised || distance >= 0.5 / rate) {
+#if 0
+ LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse dropped second=%.9f sync=%d dist=%.9f",
+ second, is_synchronised, distance);
+#endif
+ /* Drop also all stored samples */
+ filter_reset(&instance->filter);
+ return 0;
+ }
+ }
+
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f",
- second, offset + instance->offset);
+ second, offset);
#endif
filter_add_sample(&instance->filter, &cooked_time, offset);
filter->length = length;
filter->index = -1;
filter->used = 0;
+ filter->last = -1;
filter->samples = MallocArray(struct FilterSample, filter->length);
}
{
filter->index++;
filter->index %= filter->length;
+ filter->last = filter->index;
if (filter->used < filter->length)
filter->used++;
filter->samples[filter->index].offset = offset;
}
+static int
+filter_get_last_sample(struct MedianFilter *filter, struct timeval *sample_time, double *offset)
+{
+ if (filter->last < 0)
+ return 0;
+
+ *sample_time = filter->samples[filter->last].sample_time;
+ *offset = filter->samples[filter->last].offset;
+ return 1;
+}
+
static int
sample_compare(const void *a, const void *b)
{