Skip to content

Commit 7dce509

Browse files
author
Jarkko Paso
committed
FHSS WS: Clock drift compensation implemented
1 parent 612c4b5 commit 7dce509

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

source/Service_Libs/fhss/fhss_ws.c

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ void (*fhss_bc_switch)(void) = NULL;
5454
#define MS_TO_US(x) (((uint32_t)x)*1000)
5555
// Microseconds to milliseconds
5656
#define US_TO_MS(x) divide_integer(x, 1000)
57+
// Milliseconds to nanoseconds
58+
#define MS_TO_NS(x) (((uint32_t)x)*1000000)
59+
// Nanoseconds to milliseconds
60+
#define NS_TO_MS(x) divide_integer(x, 1000000)
61+
// Microseconds to nanoseconds
62+
#define US_TO_NS(x) (((uint32_t)x)*1000)
63+
// Nanoseconds to microseconds
64+
#define NS_TO_US(x) divide_integer(x, 1000)
5765
#define DEF_2E24 0x1000000
5866
#define IE_HEADER_LENGTH_MASK 0x007f
5967
#define IE_HEADER_ID_MASK 0x7f80
@@ -92,6 +100,15 @@ static uint32_t get_remaining_slots_us(fhss_structure_t *fhss_structure, void (*
92100
return remaining_time_us;
93101
}
94102

103+
void fhss_ws_start_timer(fhss_structure_t *fhss_structure, uint32_t time, void (*callback)(const fhss_api_t *fhss_api, uint16_t))
104+
{
105+
// Number of millisecond slots in timeout(us)
106+
int32_t time_in_ms = divide_integer(time, 1000);
107+
// Reduce the compensation (per millisecond) from timeout.
108+
time -= NS_TO_US(time_in_ms*fhss_structure->ws->drift_per_millisecond_ns);
109+
fhss_start_timer(fhss_structure, time, callback);
110+
}
111+
95112
fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer)
96113
{
97114
if (!fhss_api || !fhss_configuration || !fhss_timer) {
@@ -196,7 +213,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
196213
return;
197214
}
198215
if (fhss_structure->ws->is_on_bc_channel == false) {
199-
fhss_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler);
216+
fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler);
200217
fhss_structure->ws->is_on_bc_channel = true;
201218
next_channel = fhss_structure->ws->bc_channel = fhss_ws_calc_bc_channel(fhss_structure);
202219

@@ -211,7 +228,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
211228
eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(bc_min_random, bc_max_random));
212229
} else {
213230
uint32_t timeout = MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval);
214-
fhss_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler);
231+
fhss_ws_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler);
215232
fhss_structure->ws->is_on_bc_channel = false;
216233
// Should return to own (unicast) listening channel after broadcast channel
217234
next_channel = fhss_structure->rx_channel;
@@ -353,7 +370,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
353370
// Start unicast schedule
354371
if ((fhss_structure->ws->fhss_configuration.ws_uc_channel_function != WS_FIXED_CHANNEL)) {
355372
fhss_ws_update_uc_channel_callback(fhss_structure);
356-
fhss_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval), fhss_unicast_handler);
373+
fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval), fhss_unicast_handler);
357374
fhss_structure->ws->unicast_timer_running = true;
358375
}
359376
}
@@ -689,7 +706,7 @@ static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay)
689706
fhss_structure->ws->unicast_timer_running = false;
690707
return;
691708
}
692-
fhss_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_unicast_handler);
709+
fhss_ws_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_unicast_handler);
693710
fhss_structure->ws->unicast_timer_running = true;
694711
fhss_ws_update_uc_channel_callback(fhss_structure);
695712
// Unless we have broadcast schedule, we have to poll unicast queue when changing channel. This is randomized by the unicast schedule.
@@ -733,6 +750,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
733750
platform_enter_critical();
734751
uint32_t prev_synchronization_time = fhss_structure->ws->synchronization_time;
735752
fhss_structure->ws->synchronization_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api);
753+
uint32_t time_since_last_synch_us = fhss_structure->ws->synchronization_time - prev_synchronization_time;
736754
uint32_t own_bc_interval_offset = fhss_ws_calculate_broadcast_interval_offset(fhss_structure, fhss_structure->ws->synchronization_time);
737755
fhss_stop_timer(fhss_structure, fhss_broadcast_handler);
738756
uint32_t time_from_reception_ms = US_TO_MS(fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api) - bc_timing_info->bt_rx_timestamp);
@@ -745,7 +763,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
745763
if (fhss_structure->ws->is_on_bc_channel) {
746764
timeout -= MS_TO_US(bc_timing_info->broadcast_interval - bc_timing_info->broadcast_dwell_interval);
747765
}
748-
fhss_start_timer(fhss_structure, timeout, fhss_broadcast_handler);
766+
fhss_ws_start_timer(fhss_structure, timeout, fhss_broadcast_handler);
749767
uint16_t slots_since_reception = (bc_timing_info->broadcast_interval_offset + time_from_reception_ms) / bc_timing_info->broadcast_interval;
750768
// TODO: Calculate drift error
751769
fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval = bc_timing_info->broadcast_dwell_interval;
@@ -759,7 +777,17 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
759777
//TODO: support multiple parents
760778
fhss_structure->ws->parent_bc_info = bc_timing_info;
761779
if (prev_synchronization_time) {
762-
tr_debug("synch to parent: %s, drift: %ims in %u seconds", trace_array(eui64, 8), true_bc_interval_offset - own_bc_interval_offset, US_TO_S(fhss_structure->ws->synchronization_time - prev_synchronization_time));
780+
if (SYNCH_COMPENSATION_MIN_INTERVAL <= US_TO_S(time_since_last_synch_us)) {
781+
// Compensate clock drift
782+
if (true_bc_interval_offset > own_bc_interval_offset) {
783+
// Our clock runs too slow compared to parent, mark as positive drift.
784+
fhss_structure->ws->drift_per_millisecond_ns += divide_integer(MS_TO_NS(true_bc_interval_offset - own_bc_interval_offset), US_TO_MS(time_since_last_synch_us));
785+
} else {
786+
// Our clock runs too fast compared to parent, mark as negative drift.
787+
fhss_structure->ws->drift_per_millisecond_ns -= divide_integer(MS_TO_NS(own_bc_interval_offset - true_bc_interval_offset), US_TO_MS(time_since_last_synch_us));
788+
}
789+
}
790+
tr_debug("synch to parent: %s, drift: %ims in %u seconds, compensation: %ins per ms", trace_array(eui64, 8), true_bc_interval_offset - own_bc_interval_offset, US_TO_S(time_since_last_synch_us), fhss_structure->ws->drift_per_millisecond_ns);
763791
}
764792
return 0;
765793
}
@@ -786,7 +814,7 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co
786814
fhss_structure->ws->unicast_timer_running = false;
787815
}
788816
if ((fhss_structure->ws->unicast_timer_running == false) && (fhss_configuration->ws_uc_channel_function != WS_FIXED_CHANNEL) && fhss_configuration->fhss_uc_dwell_interval) {
789-
fhss_start_timer(fhss_structure, MS_TO_US(fhss_configuration->fhss_uc_dwell_interval), fhss_unicast_handler);
817+
fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_configuration->fhss_uc_dwell_interval), fhss_unicast_handler);
790818
fhss_structure->ws->unicast_timer_running = true;
791819
}
792820
fhss_structure->ws->fhss_configuration = *fhss_configuration;

source/Service_Libs/fhss/fhss_ws.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#define WS_MAX_TXRX_SLOT_LEN_MS 100
2626
// Default minimum broadcast synchronization interval in seconds
2727
#define DEFAULT_MIN_SYNCH_INTERVAL 60
28+
// Drift compensation allowed if at least SYNCH_COMPENSATION_MIN_INTERVAL (seconds) since last synchronization
29+
#define SYNCH_COMPENSATION_MIN_INTERVAL 60
2830
typedef struct fhss_ws fhss_ws_t;
2931

3032
struct fhss_ws {
@@ -34,6 +36,7 @@ struct fhss_ws {
3436
uint16_t min_synch_interval;
3537
uint32_t txrx_slot_length_ms;
3638
uint32_t synchronization_time;
39+
int32_t drift_per_millisecond_ns;
3740
int16_t *tr51_channel_table;
3841
uint8_t *tr51_output_table;
3942
bool unicast_timer_running;

0 commit comments

Comments
 (0)