49 #if TSCH_ADAPTIVE_TIMESYNC 53 static int32_t drift_ppm;
55 static int32_t compensated_ticks;
57 static uint8_t timesync_entry_count;
59 static uint32_t asn_since_last_learning;
62 #define TSCH_DRIFT_UNIT (1000L * 1000 * 256) 68 return (
long int)drift_ppm / 256;
73 timesync_entry_add(int32_t val)
75 #define NUM_TIMESYNC_ENTRIES 8 76 static int32_t buffer[NUM_TIMESYNC_ENTRIES];
79 if(timesync_entry_count == 0) {
83 if(timesync_entry_count < NUM_TIMESYNC_ENTRIES) {
84 timesync_entry_count++;
90 pos = (pos + 1) % NUM_TIMESYNC_ENTRIES;
93 for(i = 0; i < timesync_entry_count; ++i) {
96 return val / timesync_entry_count;
101 timesync_learn_drift_ticks(uint32_t time_delta_asn, int32_t drift_ticks)
104 int32_t time_delta_ticks = time_delta_asn * tsch_timing[tsch_ts_timeslot_length];
105 int32_t real_drift_ticks = drift_ticks + compensated_ticks;
106 int32_t last_drift_ppm = (int32_t)(((int64_t)real_drift_ticks * TSCH_DRIFT_UNIT) / time_delta_ticks);
108 drift_ppm = timesync_entry_add(last_drift_ppm);
111 snprintf(log->message,
sizeof(log->message),
125 timesync_entry_count = 0;
126 compensated_ticks = 0;
127 asn_since_last_learning = 0;
129 asn_since_last_learning += time_delta_asn;
130 if(asn_since_last_learning >= 4 * TSCH_SLOTS_PER_SECOND) {
131 timesync_learn_drift_ticks(asn_since_last_learning, drift_correction);
132 compensated_ticks = 0;
133 asn_since_last_learning = 0;
136 compensated_ticks += drift_correction;
143 compensate_internal(uint32_t time_delta_usec, int32_t drift_ppm, int32_t *remainder, int16_t *tick_conversion_error)
145 int64_t d = (int64_t)time_delta_usec * drift_ppm + *remainder;
146 int32_t amount = d / TSCH_DRIFT_UNIT;
147 int32_t amount_ticks;
149 *remainder = (int32_t)(d - amount * TSCH_DRIFT_UNIT);
151 amount += *tick_conversion_error;
152 amount_ticks = US_TO_RTIMERTICKS(amount);
153 *tick_conversion_error = amount - RTIMERTICKS_TO_US(amount_ticks);
155 if(ABS(amount_ticks) > RTIMER_ARCH_SECOND / 128) {
157 snprintf(log->message,
sizeof(log->message),
158 "!too big compensation %ld delta %ld", (
long int)amount_ticks, (
long int)time_delta_usec));
159 amount_ticks = (amount_ticks > 0 ? RTIMER_ARCH_SECOND : -RTIMER_ARCH_SECOND) / 128;
170 uint32_t time_delta_usec = RTIMERTICKS_TO_US_64(time_delta_ticks);
174 static int32_t remainder;
175 static int16_t tick_conversion_error;
176 result = compensate_internal(time_delta_usec, drift_ppm,
177 &remainder, &tick_conversion_error);
178 compensated_ticks += result;
181 if(TSCH_BASE_DRIFT_PPM) {
182 static int32_t base_drift_remainder;
183 static int16_t base_drift_tick_conversion_error;
184 result += compensate_internal(time_delta_usec, 256L * TSCH_BASE_DRIFT_PPM,
185 &base_drift_remainder, &base_drift_tick_conversion_error);
#define TSCH_LOG_ADD(log_type, init_code)
Use this macro to add a log to the queue (will be printed out later, after leaving interrupt context)...
struct tsch_neighbor * last_timesource_neighbor
The neighbor last used as our time source.
TSCH neighbor information.
void tsch_set_ka_timeout(uint32_t timeout)
Set the desynchronization timeout after which a node sends a unicasst keep-alive (KA) to its time sou...
void tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int32_t drift_correction)
Updates timesync information for a given neighbor.
int32_t tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks)
Computes time compensation for a given point in the future.
Main API declarations for TSCH.
long int tsch_adaptive_timesync_get_drift_ppm(void)
Gives the estimated clock drift w.r.t.