Skip to content

Commit 59bbe31

Browse files
author
Jarkko Paso
authored
Merge pull request #1917 from ARMmbed/IOTTHD-3029
FHSS WS: Clock drift compensation implemented
2 parents ac4a76e + bc2fb64 commit 59bbe31

File tree

2 files changed

+39
-11
lines changed

2 files changed

+39
-11
lines changed

source/Service_Libs/fhss/fhss_ws.c

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,25 @@ void (*fhss_uc_switch)(void) = NULL;
4343
void (*fhss_bc_switch)(void) = NULL;
4444
#endif /*FHSS_CHANNEL_DEBUG_CBS*/
4545
// Seconds to milliseconds
46-
#define S_TO_MS(x) (((uint32_t)x)*1000)
46+
#define S_TO_MS(x) (((int32_t)x)*1000)
4747
// Milliseconds to seconds
4848
#define MS_TO_S(x) divide_integer(x, 1000)
4949
// Seconds to microseconds
50-
#define S_TO_US(x) (((uint32_t)x)*1000000)
50+
#define S_TO_US(x) (((int32_t)x)*1000000)
5151
// Microseconds to seconds
5252
#define US_TO_S(x) divide_integer(x, 1000000)
5353
// Milliseconds to microseconds
54-
#define MS_TO_US(x) (((uint32_t)x)*1000)
54+
#define MS_TO_US(x) (((int32_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) (((int32_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) (((int32_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
@@ -77,8 +85,11 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure);
7785
static uint8_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure);
7886

7987
// This function supports rounding up
80-
static uint32_t divide_integer(uint32_t dividend, uint32_t divisor)
88+
static int32_t divide_integer(int32_t dividend, int32_t divisor)
8189
{
90+
if (dividend < 0) {
91+
return (dividend - divisor / 2) / divisor;
92+
}
8293
return (dividend + divisor / 2) / divisor;
8394
}
8495

@@ -92,6 +103,15 @@ static uint32_t get_remaining_slots_us(fhss_structure_t *fhss_structure, void (*
92103
return remaining_time_us;
93104
}
94105

106+
void fhss_ws_start_timer(fhss_structure_t *fhss_structure, uint32_t time, void (*callback)(const fhss_api_t *fhss_api, uint16_t))
107+
{
108+
// Number of millisecond slots in timeout(us)
109+
int32_t time_in_ms = divide_integer(time, 1000);
110+
// Reduce the compensation (per millisecond) from timeout.
111+
time -= NS_TO_US(time_in_ms*fhss_structure->ws->drift_per_millisecond_ns);
112+
fhss_start_timer(fhss_structure, time, callback);
113+
}
114+
95115
fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer)
96116
{
97117
if (!fhss_api || !fhss_configuration || !fhss_timer) {
@@ -196,7 +216,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
196216
return;
197217
}
198218
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);
219+
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);
200220
fhss_structure->ws->is_on_bc_channel = true;
201221
next_channel = fhss_structure->ws->bc_channel = fhss_ws_calc_bc_channel(fhss_structure);
202222

@@ -211,7 +231,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
211231
eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(bc_min_random, bc_max_random));
212232
} else {
213233
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);
234+
fhss_ws_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler);
215235
fhss_structure->ws->is_on_bc_channel = false;
216236
// Should return to own (unicast) listening channel after broadcast channel
217237
next_channel = fhss_structure->rx_channel;
@@ -353,7 +373,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
353373
// Start unicast schedule
354374
if ((fhss_structure->ws->fhss_configuration.ws_uc_channel_function != WS_FIXED_CHANNEL)) {
355375
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);
376+
fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval), fhss_unicast_handler);
357377
fhss_structure->ws->unicast_timer_running = true;
358378
}
359379
}
@@ -689,7 +709,7 @@ static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay)
689709
fhss_structure->ws->unicast_timer_running = false;
690710
return;
691711
}
692-
fhss_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_unicast_handler);
712+
fhss_ws_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_unicast_handler);
693713
fhss_structure->ws->unicast_timer_running = true;
694714
fhss_ws_update_uc_channel_callback(fhss_structure);
695715
// Unless we have broadcast schedule, we have to poll unicast queue when changing channel. This is randomized by the unicast schedule.
@@ -733,6 +753,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
733753
platform_enter_critical();
734754
uint32_t prev_synchronization_time = fhss_structure->ws->synchronization_time;
735755
fhss_structure->ws->synchronization_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api);
756+
uint32_t time_since_last_synch_us = fhss_structure->ws->synchronization_time - prev_synchronization_time;
736757
uint32_t own_bc_interval_offset = fhss_ws_calculate_broadcast_interval_offset(fhss_structure, fhss_structure->ws->synchronization_time);
737758
fhss_stop_timer(fhss_structure, fhss_broadcast_handler);
738759
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 +766,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
745766
if (fhss_structure->ws->is_on_bc_channel) {
746767
timeout -= MS_TO_US(bc_timing_info->broadcast_interval - bc_timing_info->broadcast_dwell_interval);
747768
}
748-
fhss_start_timer(fhss_structure, timeout, fhss_broadcast_handler);
769+
fhss_ws_start_timer(fhss_structure, timeout, fhss_broadcast_handler);
749770
uint16_t slots_since_reception = (bc_timing_info->broadcast_interval_offset + time_from_reception_ms) / bc_timing_info->broadcast_interval;
750771
// TODO: Calculate drift error
751772
fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval = bc_timing_info->broadcast_dwell_interval;
@@ -759,7 +780,11 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
759780
//TODO: support multiple parents
760781
fhss_structure->ws->parent_bc_info = bc_timing_info;
761782
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));
783+
if (SYNCH_COMPENSATION_MIN_INTERVAL <= US_TO_S(time_since_last_synch_us)) {
784+
// Update clock drift
785+
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));
786+
}
787+
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);
763788
}
764789
return 0;
765790
}
@@ -786,7 +811,7 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co
786811
fhss_structure->ws->unicast_timer_running = false;
787812
}
788813
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);
814+
fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_configuration->fhss_uc_dwell_interval), fhss_unicast_handler);
790815
fhss_structure->ws->unicast_timer_running = true;
791816
}
792817
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)