#include "nqptp-clock-sources.h"
#include "debug.h"
-#include "general-utilities.h"
#include "nqptp-ptp-definitions.h"
+#include "general-utilities.h"
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <string.h>
memset(&clocks_private_info[i], 0, sizeof(clock_source_private_data));
strncpy((char *)&clocks_private_info[i].ip, sender_string,
FIELD_SIZEOF(clock_source_private_data, ip) - 1);
+ clocks_private_info[i].vacant_samples = MAX_TIMING_SAMPLES;
clocks_private_info[i].in_use = 1;
debug(2, "create record for ip: %s.", &clocks_private_info[i].ip);
} else {
int best_so_far = -1;
int timing_peer_count = 0;
- uint32_t acceptance_mask =
- (1 << clock_is_qualified) | (1 << clock_is_a_timing_peer) | (1 << clock_is_valid);
+ uint32_t acceptance_mask = (1 << clock_is_qualified) | (1 << clock_is_a_timing_peer) | (1 << clock_is_valid);
for (i = 0; i < MAX_CLOCKS; i++) {
if ((clocks_private[i].flags & acceptance_mask) == acceptance_mask) {
// found a possible clock candidate
if (old_master != -1) {
// but there was a master clock, so remove it
debug(1, "shm interface -- remove master clock designation");
- update_master_clock_info(0, NULL, 0, 0);
+ update_master_clock_info(0, NULL, 0, 0, 0);
}
if (timing_peer_count == 0)
debug(2, "No timing peer list found");
else
debug(1, "No master clock not found!");
- } else {
- // we found a master clock
- clocks_private[best_so_far].flags |= (1 << clock_is_master);
- if (old_master != best_so_far) {
- // if it's a new master, drop all previous estimates and limits
- clocks_private[best_so_far].previous_offset_time = 0; // resync
+ } else {
+ // we found a master clock
+ clocks_private[best_so_far].flags |= (1 << clock_is_master);
+
+ if (old_master != best_so_far) {
+ // clang-format off
+ // Now we use the last few samples to calculate the best offset for the
+ // new master clock.
+
+ // The time of the oldest sample we use will become the time of the start of the
+ // mastership
+
+ // We will accept samples that would make the local-to-clock offset greatest,
+ // provided they are not too old and that they don't push the current clock time
+ // more than, say, 1000 ms plus one sample interval in the future.
+
+ // This sample is the only time estimate we have when the clock is definitely a master
+ // so we use it to eliminate any previous time estimates, made when the clock wasn't designated
+ // a master, that would put it more than, say, a second further into the future.
+
+ // Allow the samples to give a valid master clock time up to this much later than the single definitive sample we have:
+
+ uint64_t oldest_acceptable_master_clock_time = clocks_private[best_so_far].source_time + 1150000000;
+
+ // we will try to improve on this single definitive local_to_source_time_offset we have
+ int changes_made = 0;
+
+ uint64_t best_offset_so_far = clocks_private[best_so_far].local_to_source_time_offset;
+ uint64_t age_of_oldest_legitimate_sample = clocks_private[best_so_far].local_time;
+
+ int number_of_samples = MAX_TIMING_SAMPLES - clocks_private[best_so_far].vacant_samples;
+ int samples_checked = 0;
+// if (0) {
+ if (number_of_samples > 0) {
+ debug(3,"Number of samples: %d.", number_of_samples);
+ uint64_t time_now = get_time_now();
+ uint64_t oldest_acceptable_time = time_now - 10000000000; // only go back this far (ns)
+ int i;
+ for (i = 0; i < number_of_samples; i++) {
+ int64_t age_relative_to_oldest_acceptable_time = clocks_private[best_so_far].samples[i].local_time - oldest_acceptable_time;
+ if (age_relative_to_oldest_acceptable_time > 0) {
+ if (clocks_private[best_so_far].samples[i].local_time < age_of_oldest_legitimate_sample) {
+ age_of_oldest_legitimate_sample = clocks_private[best_so_far].samples[i].local_time;
+ }
+ uint64_t possible_offset = clocks_private[best_so_far].samples[i].clock_time - clocks_private[best_so_far].samples[i].local_time;
+ uint64_t possible_master_clock_time = clocks_private[best_so_far].local_time + possible_offset;
+ int64_t age_relative_to_oldest_acceptable_master_clock_time = possible_master_clock_time - oldest_acceptable_master_clock_time;
+ if (age_relative_to_oldest_acceptable_master_clock_time <= 0) {
+ samples_checked++;
+ // so, the sample was not obtained too far in the past
+ // and it would not push the estimated master clock_time too far into the future
+ // so, if it is greater than the best_offset_so_far, then make it the new one
+ if (possible_offset > best_offset_so_far) {
+ debug(3,"new best offset");
+ best_offset_so_far = possible_offset;
+ changes_made++;
+ }
+ } else {
+ debug(3,"sample too far into the future");
+ }
+ } else {
+ debug(3,"sample too old");
+ }
+ }
+
+ }
+
+// if (changes_made == 0) {
+// clocks_private[best_so_far].previous_offset_time = 0; // if you have no previous samples (how?), then resync
+// clocks_private[best_so_far].mastership_start_time = clocks_private[best_so_far].local_time;
+// } else {
+ clocks_private[best_so_far].mastership_start_time = age_of_oldest_legitimate_sample;
+ int64_t offset_difference = best_offset_so_far - clocks_private[best_so_far].local_to_source_time_offset;
+
+ debug(2,"Lookback difference: %f ms with %d samples checked of %d samples total.", 0.000001 * offset_difference, samples_checked, number_of_samples);
+ clocks_private[best_so_far].local_to_source_time_offset = best_offset_so_far;
+
+// clocks_private[best_so_far].previous_offset_time = clocks_private[best_so_far].local_time;
+// clocks_private[best_so_far].previous_offset = clocks_private[best_so_far].local_to_source_time_offset;
+// }
+
+ debug(2,"Master sampling started %f ms before becoming master.", 0.000001 * (clocks_private[best_so_far].local_time - age_of_oldest_legitimate_sample));
+ update_master_clock_info(clocks_private[best_so_far].clock_id,
+ (const char *)&clocks_private[best_so_far].ip,
+ clocks_private[best_so_far].local_time,
+ clocks_private[best_so_far].local_to_source_time_offset,
+ clocks_private[best_so_far].mastership_start_time);
+ // clang-format on
+
+ clocks_private[best_so_far].previous_offset_time = 0; // resync
}
}
clock_is_master
} clock_flags;
+// 8 samples per seconds
+#define MAX_TIMING_SAMPLES 47
+ typedef struct {
+ uint64_t local_time, clock_time;
+ } timing_samples;
+
// information about each clock source
typedef struct {
char ip[64]; // 64 is nicely aligned and bigger than INET6_ADDRSTRLEN (46)
uint32_t flags;
uint16_t in_use;
uint64_t previous_offset, previous_offset_time, last_sync_time;
+ uint64_t mastership_start_time; // set to the time of the first sample used as master
// for garbage collection
uint64_t time_of_last_use; // will be taken out of use if not used for a while and not in the
uint64_t announce_times[4]; // we'll check qualification and currency using these
int is_one_of_ours; // true if it is one of our own clocks
+ timing_samples samples[MAX_TIMING_SAMPLES];
+ int vacant_samples; // the number of elements in the timing_samples array that are not yet used
+ int next_sample_goes_here; // point to where in the timing samples array the next entries should
+ // go
+
+
// these are for finding the best clock to use
// See Figure 27 and 27 pp 89 -- 90 for the Data set comparison algorithm
void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len,
clock_source_private_data *clock_private_info, uint64_t reception_time) {
- clock_private_info->flags |= (1 << clock_is_valid); // valid because it has at least one follow_up
- struct ptp_follow_up_message *msg = (struct ptp_follow_up_message *)buf;
-
- uint16_t seconds_hi = nctohs(&msg->follow_up.preciseOriginTimestamp[0]);
- uint32_t seconds_low = nctohl(&msg->follow_up.preciseOriginTimestamp[2]);
- uint32_t nanoseconds = nctohl(&msg->follow_up.preciseOriginTimestamp[6]);
- uint64_t preciseOriginTimestamp = seconds_hi;
- preciseOriginTimestamp = preciseOriginTimestamp << 32;
- preciseOriginTimestamp = preciseOriginTimestamp + seconds_low;
- preciseOriginTimestamp = preciseOriginTimestamp * 1000000000L;
- preciseOriginTimestamp = preciseOriginTimestamp + nanoseconds;
-
- // if ((clock_private_info->flags & (1 << clock_is_master)) != 0) {
+ clock_private_info->flags |= (1 << clock_is_valid); // valid because it has at least one follow_up
+ struct ptp_follow_up_message *msg = (struct ptp_follow_up_message *)buf;
+
+ uint16_t seconds_hi = nctohs(&msg->follow_up.preciseOriginTimestamp[0]);
+ uint32_t seconds_low = nctohl(&msg->follow_up.preciseOriginTimestamp[2]);
+ uint32_t nanoseconds = nctohl(&msg->follow_up.preciseOriginTimestamp[6]);
+ uint64_t preciseOriginTimestamp = seconds_hi;
+ preciseOriginTimestamp = preciseOriginTimestamp << 32;
+ preciseOriginTimestamp = preciseOriginTimestamp + seconds_low;
+ preciseOriginTimestamp = preciseOriginTimestamp * 1000000000L;
+ preciseOriginTimestamp = preciseOriginTimestamp + nanoseconds;
+
+ // update our sample information
+
+ clock_private_info->samples[clock_private_info->next_sample_goes_here].local_time =
+ reception_time;
+ clock_private_info->samples[clock_private_info->next_sample_goes_here]
+ .clock_time = preciseOriginTimestamp;
+
+ if (clock_private_info->vacant_samples > 0)
+ clock_private_info->vacant_samples--;
+
+ clock_private_info->next_sample_goes_here++;
+ // if we have need to wrap.
+ if (clock_private_info->next_sample_goes_here == MAX_TIMING_SAMPLES)
+ clock_private_info->next_sample_goes_here = 0;
+
+
+// if ((clock_private_info->flags & (1 << clock_is_master)) != 0) {
if (1) {
debug(2, "FOLLOWUP from %" PRIx64 ", %s.", clock_private_info->clock_id,
&clock_private_info->ip);
uint32_t old_flags = clock_private_info->flags;
- // if ((clock_private_info->flags & (1 << clock_is_valid)) == 0) {
+ //if ((clock_private_info->flags & (1 << clock_is_valid)) == 0) {
// debug(1, "clock %" PRIx64 " is now valid at: %s", packet_clock_id, clock_private_info->ip);
//}
if (old_flags != clock_private_info->flags) {
update_master();
- }
-
- if ((clock_private_info->flags & (1 << clock_is_master)) != 0) {
+ } else if ((clock_private_info->flags & (1 << clock_is_master)) != 0) {
update_master_clock_info(clock_private_info->clock_id, (const char *)&clock_private_info->ip,
- reception_time, offset);
+ reception_time, offset, clock_private_info->mastership_start_time);
debug(3, "clock: %" PRIx64 ", time: %" PRIu64 ", offset: %" PRId64 ", jitter: %+f ms.",
clock_private_info->clock_id, reception_time, offset, 0.000001 * jitter);
}
int epoll_fd;
void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time,
- uint64_t local_to_master_offset) {
+ uint64_t local_to_master_offset, uint64_t mastership_start_time) {
if (shared_memory->master_clock_id != master_clock_id)
debug(1, "Master clock is: %" PRIx64 ".", master_clock_id);
int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
warn("Can't acquire mutex to update master clock!");
if (shared_memory->master_clock_id != master_clock_id) {
shared_memory->master_clock_id = master_clock_id;
- shared_memory->master_clock_start_time = local_time;
+ shared_memory->master_clock_start_time = mastership_start_time;
}
if (ip != NULL)
strncpy((char *)&shared_memory->master_clock_ip, ip,
#ifdef CONFIG_USE_GIT_VERSION_STRING
if (git_version_string[0] != '\0')
fprintf(stdout, "Version: %s. Shared Memory Interface Version: %u.\n", git_version_string,
- NQPTP_SHM_STRUCTURES_VERSION);
+ NQPTP_SHM_STRUCTURES_VERSION);
else
#endif
- fprintf(stdout, "Version: %s. Shared Memory Interface Version: %u.\n", VERSION,
- NQPTP_SHM_STRUCTURES_VERSION);
+ fprintf(stdout, "Version: %s. Shared Memory Interface Version: %u.\n", VERSION,
+ NQPTP_SHM_STRUCTURES_VERSION);
exit(EXIT_SUCCESS);
} else if (strcmp(argv[i] + 1, "vvv") == 0) {
debug_level = 3;
extern struct shm_structure *shared_memory;
void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time,
- uint64_t local_to_master_offset);
+ uint64_t local_to_master_offset, uint64_t mastership_start_time);
#endif
+