Skip to content

Commit e047723

Browse files
author
Jarkko Paso
authored
Merge pull request ARMmbed#1541 from ARMmbed/IOTTHD-2171
Iotthd 2171
2 parents f6c61fc + 5d98e3e commit e047723

File tree

22 files changed

+553
-200
lines changed

22 files changed

+553
-200
lines changed

nanostack/net_fhss.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ extern "C" {
3838
*/
3939
extern fhss_api_t *ns_fhss_create(const fhss_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer, fhss_statistics_t *fhss_statistics);
4040

41+
/**
42+
* @brief TODO: description.
43+
* @param fhss_configuration Basic FHSS configuration.
44+
* @param fhss_timer FHSS platform timer interface and configuration.
45+
* @param fhss_statistics FHSS statistics storage.
46+
* @return New FHSS instance if successful, NULL otherwise.
47+
*/
48+
extern fhss_api_t *ns_fhss_ws_create(const fhss_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer, fhss_statistics_t *fhss_statistics);
49+
4150
/**
4251
* @brief Set synchronization time configuration for FHSS network. Should be only called from Border router.
4352
* @param fhss_api FHSS instance.

source/Service_Libs/fhss/channel_functions.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,25 @@
4141

4242
static uint32_t global_seed = 1;
4343

44+
45+
uint16_t tr51_calc_nearest_prime_number(uint16_t start_value)
46+
{
47+
if (start_value < 2) {
48+
return 0;
49+
}
50+
uint16_t divider = start_value - 1;
51+
while (start_value) {
52+
if (start_value % divider--) {
53+
if (divider == 1) {
54+
return start_value;
55+
}
56+
} else {
57+
divider = ++start_value - 1;
58+
}
59+
}
60+
return 0;
61+
}
62+
4463
void tr51_seed_rand(uint32_t seed)
4564
{
4665
if (!seed) {
@@ -161,3 +180,16 @@ int32_t dh1cf_get_bc_channel_index(uint16_t slot_number, uint16_t bsi, int16_t n
161180
channel_number = dh1cf_hashword(key, 3, 0) % number_of_channels;
162181
return channel_number;
163182
}
183+
184+
int32_t tr51_get_uc_channel_index(uint16_t slot_number, uint8_t *mac, int16_t number_of_channels)
185+
{
186+
uint16_t nearest_prime = tr51_calc_nearest_prime_number(number_of_channels);
187+
int32_t channel_table[nearest_prime];
188+
int32_t output_table[number_of_channels];
189+
uint8_t first_element;
190+
uint8_t step_size;
191+
tr51_calculate_channel_table(number_of_channels, nearest_prime, channel_table);
192+
tr51_compute_cfd(mac, &first_element, &step_size, nearest_prime);
193+
tr51_calculate_hopping_sequence(channel_table, number_of_channels, first_element, step_size, output_table, NULL, 0);
194+
return output_table[slot_number];
195+
}

source/Service_Libs/fhss/channel_functions.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
void tr51_calculate_channel_table(uint16_t number_of_channels, uint16_t nearest_prime, int32_t *channel_table);
2525

2626
/**
27-
* @brief Calculate hopping sequence for a specific peer.
27+
* @brief Calculate hopping sequence for a specific peer using tr51 channel function.
2828
* @param channel_table Used channel table.
2929
* @param channel_table_length Length of the used channel table.
3030
* @param first_element Start generated by CFD function.
@@ -37,7 +37,16 @@ void tr51_calculate_channel_table(uint16_t number_of_channels, uint16_t nearest_
3737
uint16_t tr51_calculate_hopping_sequence(int32_t *channel_table, uint16_t channel_table_length, uint8_t first_element, uint8_t step_size, int32_t *output_table, uint16_t *excluded_channels, uint16_t number_of_excluded_channels);
3838

3939
/**
40-
* @brief Compute the unicast schedule channel index.
40+
* @brief Compute the unicast schedule channel index using tr51 channel function.
41+
* @param slot_number Current slot number.
42+
* @param mac MAC address of the node for which the index is calculated.
43+
* @param number_of_channels Number of channels.
44+
* @return Channel index.
45+
*/
46+
int32_t tr51_get_uc_channel_index(uint16_t slot_number, uint8_t *mac, int16_t number_of_channels);
47+
48+
/**
49+
* @brief Compute the unicast schedule channel index using direct hash channel function.
4150
* @param slot_number Current slot number.
4251
* @param mac MAC address of the node for which the index is calculated.
4352
* @param number_of_channels Number of channels.
@@ -46,7 +55,7 @@ uint16_t tr51_calculate_hopping_sequence(int32_t *channel_table, uint16_t channe
4655
int32_t dh1cf_get_uc_channel_index(uint16_t slot_number, uint8_t *mac, int16_t number_of_channels);
4756

4857
/**
49-
* @brief Compute the broadcast schedule channel index.
58+
* @brief Compute the broadcast schedule channel index using direct hash channel function.
5059
* @param slot_number Current slot number.
5160
* @param bsi Broadcast schedule identifier of the node for which the index is calculated.
5261
* @param number_of_channels Number of channels.

source/Service_Libs/fhss/fhss.c

Lines changed: 135 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "ns_trace.h"
2929
#include "eventOS_event.h"
3030
#include "eventOS_callback_timer.h"
31+
#include "platform/arm_hal_interrupt.h"
3132
#include "randLIB.h"
3233
#include <string.h>
3334

@@ -165,97 +166,7 @@ int fhss_reset_synch_monitor(fhss_synch_monitor_s *synch_monitor)
165166
return -1;
166167
}
167168

168-
uint32_t fhss_get_remaining_time_to_next_superframe(const fhss_structure_t *fhss_structure)
169-
{
170-
const uint32_t slots = fhss_structure->platform_functions.fhss_get_remaining_slots(fhss_superframe_handler, fhss_structure->fhss_api);
171-
const uint32_t time = slots * fhss_structure->platform_functions.fhss_resolution_divider;
172-
return time;
173-
}
174-
175-
void fhss_superframe_handler(const fhss_api_t *fhss_api, uint16_t delay)
176-
{
177-
int compensation = 0;
178-
fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api);
179-
if (!fhss_structure) {
180-
return;
181-
}
182-
/* Drift compensation doesn't work with Linux platform */
183-
#ifndef __linux__
184-
// Drift compensation on first superframe
185-
if (fhss_structure->current_superframe == 0) {
186-
/* Idea is to compensate number of drift_compensation (microseconds) on each channel.
187-
* However, fhss_resolution_divider defines the minimum timer resolution.
188-
* E.g. if fhss_resolution_divider = 64, compensate (drift_compensation * 64) on each 64th channel.
189-
*/
190-
if (++fhss_structure->synch_monitor.channel_counter == fhss_structure->platform_functions.fhss_resolution_divider) {
191-
compensation = fhss_structure->synch_monitor.drift_compensation;
192-
fhss_structure->synch_monitor.channel_counter = 0;
193-
}
194-
}
195-
#endif //__linux__
196-
// Restart timer asap to minimize the effect of dynamic execution time of
197-
// the rest of function.
198-
fhss_start_timer(fhss_structure, (fhss_structure->synch_configuration.fhss_superframe_length) - (delay * fhss_structure->platform_functions.fhss_resolution_divider) + (compensation * fhss_structure->platform_functions.fhss_resolution_divider), fhss_superframe_handler);
199-
200-
// check, if the current frame was the last one
201-
if (fhss_structure->current_superframe >= (fhss_structure->synch_configuration.fhss_number_of_superframes - 1)) {
202-
203-
// last superframe has passed, change channel
204-
fhss_structure->current_superframe = 0;
205-
fhss_structure->current_channel_index++;
206-
if (fhss_structure->current_channel_index >= fhss_structure->number_of_channels) {
207-
fhss_structure->synch_infos_sent_counter = 0;
208-
fhss_structure->current_channel_index = 0;
209-
fhss_structure->channel_list_counter++;
210-
// Repeated cycle is started from beginning, reset counter. Don't let the channel_list_counter overflow.
211-
if (fhss_structure->channel_list_counter >= ((uint16_t) fhss_structure->number_of_channels * MAX_SCRAMBLE_TABLE_INDEXES)) {
212-
fhss_structure->channel_list_counter = 0;
213-
}
214-
// Hop 0 don't have parent
215-
if (fhss_is_synch_root(fhss_structure) == false) {
216-
fhss_trig_event(fhss_structure, FHSS_COMPARE_SYNCH_PARENT);
217-
}
218-
fhss_trig_event(fhss_structure, FHSS_UPDATE_SYNCH_INFO_STORAGE);
219-
}
220-
fhss_update_channel(fhss_structure);
221-
} else {
222-
// bump up the superframe counter
223-
fhss_structure->current_superframe++;
224-
}
225-
if ((fhss_structure->send_synch_info_on_next_broadcast_channel == true) && (fhss_is_current_channel_broadcast(fhss_structure) == true)) {
226-
/* Randomize sending superframe of synchronization frame:
227-
* on first superframe probability is 1/number of superframes
228-
* on second superframe probability is 1/(number of superframes-1)
229-
* on third superframe probability is 1/(number of superframes-2)
230-
* on last superframe probability is 1/1
231-
*/
232-
if (randLIB_get_random_in_range(1, fhss_structure->synch_configuration.fhss_number_of_superframes - fhss_structure->current_superframe) == 1) {
233-
fhss_structure->send_synch_info_on_next_broadcast_channel = false;
234-
fhss_structure->synch_infos_sent_counter++;
235-
fhss_structure->callbacks.send_fhss_frame(fhss_structure->fhss_api, FHSS_SYNCH_FRAME);
236-
}
237-
}
238-
fhss_update_txrx_slots(fhss_structure);
239-
uint16_t queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, false) + fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true);
240-
if ((fhss_structure->tx_allowed == true || fhss_is_current_channel_broadcast(fhss_structure) == true) && queue_size) {
241-
/* Start timer with random timeout to trigger TX queue poll event.
242-
* Max random is half of the superframe length. Event timer resolution is 50us.
243-
* Divide Max random with TX queue size to transmit faster when TX queue is growing
244-
*/
245-
uint16_t max_random = ((fhss_structure->synch_configuration.fhss_superframe_length / 2) / 50) / queue_size;
246-
eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(1, max_random));
247-
}
248-
if (fhss_structure->fhss_timeout) {
249-
fhss_structure->fhss_timer += fhss_structure->synch_configuration.fhss_superframe_length;
250-
if (fhss_structure->fhss_timer >= fhss_structure->fhss_timeout) {
251-
fhss_trig_event(fhss_structure, FHSS_TIMER_EVENT);
252-
fhss_structure->fhss_timeout = 0;
253-
fhss_structure->fhss_timer = 0;
254-
}
255-
}
256-
}
257-
258-
int fhss_update_txrx_slots(fhss_structure_t *fhss_structure)
169+
static int fhss_update_txrx_slots(fhss_structure_t *fhss_structure)
259170
{
260171
uint8_t cur_superframe = fhss_structure->current_superframe;
261172
uint8_t number_of_tx_slots = fhss_structure->synch_configuration.fhss_number_of_tx_slots;
@@ -438,7 +349,7 @@ int fhss_sync_with_beacon(fhss_structure_t *fhss_structure,
438349

439350
if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
440351
fhss_structure->fhss_state = FHSS_SYNCHRONIZED;
441-
fhss_update_channel(fhss_structure);
352+
fhss_change_to_next_channel(fhss_structure);
442353
}
443354
if (fhss_is_synch_root(fhss_structure) == false) {
444355
// Initially synch drift might be massive. Request first few Beacons more frequently until compensation starts fixing the error.
@@ -563,7 +474,7 @@ static bool fhss_is_there_common_divisor(uint16_t i, uint8_t j)
563474
}
564475

565476

566-
int fhss_generate_scramble_table(fhss_structure_t *fhss_structure)
477+
static int fhss_generate_scramble_table(fhss_structure_t *fhss_structure)
567478
{
568479
uint8_t j = 2;
569480
fhss_structure->fhss_scramble_table = ns_dyn_mem_alloc(MAX_SCRAMBLE_TABLE_INDEXES);
@@ -746,3 +657,134 @@ void fhss_failed_list_free(fhss_structure_t *fhss_structure)
746657
fhss_failed_handle_remove(fhss_structure, i);
747658
}
748659
}
660+
661+
static int fhss_handle_state_set(fhss_structure_t *fhss_structure, fhss_states fhss_state, uint16_t pan_id)
662+
{
663+
// State is already set
664+
if (fhss_structure->fhss_state == fhss_state) {
665+
tr_debug("Synch same state %u", fhss_state);
666+
return -1;
667+
}
668+
669+
if (fhss_state == FHSS_UNSYNCHRONIZED) {
670+
tr_debug("FHSS down");
671+
fhss_down(fhss_structure);
672+
} else {
673+
// Do not synchronize to current pan
674+
if (fhss_structure->synch_panid == pan_id) {
675+
tr_debug("Synch same panid %u", pan_id);
676+
return -1;
677+
}
678+
if (fhss_structure->fhss_scramble_table == NULL) {
679+
if (fhss_generate_scramble_table(fhss_structure)) {
680+
tr_error("Failed to generate scramble table");
681+
return -1;
682+
}
683+
}
684+
uint32_t datarate = fhss_structure->callbacks.read_datarate(fhss_structure->fhss_api);
685+
fhss_set_datarate(fhss_structure, datarate);
686+
uint8_t mac_address[8];
687+
fhss_structure->callbacks.read_mac_address(fhss_structure->fhss_api, mac_address);
688+
fhss_structure->uc_channel_index = fhss_get_offset(fhss_structure, mac_address);
689+
// Get Beacon info from storage
690+
fhss_beacon_info_t *beacon_info = fhss_get_beacon_info(fhss_structure, pan_id);
691+
if (beacon_info) {
692+
memcpy(fhss_structure->synch_parent, beacon_info->source_address, 8);
693+
platform_enter_critical();
694+
// Calculate time since the Beacon was received
695+
uint32_t elapsed_time = fhss_structure->fhss_api->read_timestamp(fhss_structure->fhss_api) - beacon_info->timestamp;
696+
// Synchronize to given PAN
697+
fhss_beacon_received(fhss_structure, beacon_info->synch_info, elapsed_time);
698+
platform_exit_critical();
699+
// Delete stored Beacon infos
700+
fhss_flush_beacon_info_storage(fhss_structure);
701+
fhss_structure->synch_panid = pan_id;
702+
} else if (fhss_is_synch_root(fhss_structure) == true) {
703+
// Synch root will start new network
704+
fhss_start_timer(fhss_structure, fhss_structure->synch_configuration.fhss_superframe_length, fhss_superframe_handler);
705+
} else {
706+
tr_error("Synch info not found");
707+
return -1;
708+
}
709+
}
710+
return 0;
711+
}
712+
713+
static uint32_t fhss_get_compensation(fhss_structure_t *fhss_structure)
714+
{
715+
uint32_t compensation = 0;
716+
/* Drift compensation doesn't work with Linux platform */
717+
#ifndef __linux__
718+
// Drift compensation on first superframe
719+
if (fhss_structure->current_superframe == 0) {
720+
/* Idea is to compensate number of drift_compensation (microseconds) on each channel.
721+
* However, fhss_resolution_divider defines the minimum timer resolution.
722+
* E.g. if fhss_resolution_divider = 64, compensate (drift_compensation * 64) on each 64th channel.
723+
*/
724+
if (++fhss_structure->synch_monitor.channel_counter == fhss_structure->platform_functions.fhss_resolution_divider) {
725+
compensation = fhss_structure->synch_monitor.drift_compensation;
726+
fhss_structure->synch_monitor.channel_counter = 0;
727+
}
728+
}
729+
#else
730+
(void) fhss_structure;
731+
#endif //__linux__
732+
return compensation;
733+
}
734+
735+
static void fhss_superframe_callback(fhss_structure_t *fhss_structure)
736+
{
737+
if ((fhss_structure->send_synch_info_on_next_broadcast_channel == true) && (fhss_is_current_channel_broadcast(fhss_structure) == true)) {
738+
/* Randomize sending superframe of synchronization frame:
739+
* on first superframe probability is 1/number of superframes
740+
* on second superframe probability is 1/(number of superframes-1)
741+
* on third superframe probability is 1/(number of superframes-2)
742+
* on last superframe probability is 1/1
743+
*/
744+
if (randLIB_get_random_in_range(1, fhss_structure->synch_configuration.fhss_number_of_superframes - fhss_structure->current_superframe) == 1) {
745+
fhss_structure->send_synch_info_on_next_broadcast_channel = false;
746+
fhss_structure->synch_infos_sent_counter++;
747+
fhss_structure->callbacks.send_fhss_frame(fhss_structure->fhss_api, FHSS_SYNCH_FRAME);
748+
}
749+
}
750+
fhss_update_txrx_slots(fhss_structure);
751+
uint16_t queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, false) + fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true);
752+
if ((fhss_structure->tx_allowed == true || fhss_is_current_channel_broadcast(fhss_structure) == true) && queue_size) {
753+
/* Start timer with random timeout to trigger TX queue poll event.
754+
* Max random is half of the superframe length. Event timer resolution is 50us.
755+
* Divide Max random with TX queue size to transmit faster when TX queue is growing
756+
*/
757+
uint16_t max_random = ((fhss_structure->synch_configuration.fhss_superframe_length / 2) / 50) / queue_size;
758+
eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(1, max_random));
759+
}
760+
}
761+
762+
static void fhss_update_channel_callback(fhss_structure_t *fhss_structure)
763+
{
764+
if (fhss_structure->current_channel_index == 0) {
765+
fhss_structure->synch_infos_sent_counter = 0;
766+
if (++fhss_structure->channel_list_counter >= ((uint16_t) fhss_structure->number_of_channels * MAX_SCRAMBLE_TABLE_INDEXES)) {
767+
fhss_structure->channel_list_counter = 0;
768+
}
769+
if (fhss_is_synch_root(fhss_structure) == false) {
770+
fhss_trig_event(fhss_structure, FHSS_COMPARE_SYNCH_PARENT);
771+
}
772+
fhss_trig_event(fhss_structure, FHSS_UPDATE_SYNCH_INFO_STORAGE);
773+
}
774+
// If channel is broadcast channel (true), send event
775+
if (fhss_change_to_next_channel(fhss_structure) == true) {
776+
// Only if device is border router
777+
if (fhss_structure->own_hop == 0) {
778+
fhss_trig_event(fhss_structure, FHSS_BROADCAST_CHANNEL);
779+
}
780+
}
781+
}
782+
783+
int fhss_set_internal_callbacks(fhss_structure_t *fhss_structure)
784+
{
785+
fhss_structure->update_channel = fhss_update_channel_callback;
786+
fhss_structure->update_superframe = fhss_superframe_callback;
787+
fhss_structure->read_compensation = fhss_get_compensation;
788+
fhss_structure->handle_state_set = fhss_handle_state_set;
789+
return 0;
790+
}

source/Service_Libs/fhss/fhss.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,16 @@ int fhss_flush_beacon_info_storage(fhss_structure_t *fhss_structure);
3636
int fhss_add_beacon_info(fhss_structure_t *fhss_structure, uint16_t pan_id, uint8_t *source_address, uint32_t timestamp, uint8_t *synch_info);
3737
void fhss_update_beacon_info_lifetimes(fhss_structure_t *fhss_structure, uint32_t timestamp);
3838
uint32_t fhss_get_tx_time(fhss_structure_t *fhss_structure, uint16_t bytes_to_send, uint8_t phy_header_length, uint8_t phy_tail_length);
39-
void fhss_superframe_handler(const fhss_api_t *fhss_api, uint16_t delay);
4039
fhss_failed_tx_t *fhss_failed_handle_find(fhss_structure_t *fhss_structure, uint8_t handle);
4140
int fhss_failed_handle_add(fhss_structure_t *fhss_structure, uint8_t handle);
4241
int fhss_failed_handle_remove(fhss_structure_t *fhss_structure, uint8_t handle);
43-
int fhss_generate_scramble_table(fhss_structure_t *fhss_structure);
4442
void fhss_failed_list_free(fhss_structure_t *fhss_structure);
4543
int fhss_reset_synch_monitor(fhss_synch_monitor_s *synch_monitor);
44+
int fhss_set_internal_callbacks(fhss_structure_t *fhss_structure);
45+
4646
#define MAX_FHSS_TIMER_DIVIDER 100
4747
#define SYNCH_MONITOR_AVG_SAMPLES 5
4848

49-
/**
50-
* Update slots
51-
*
52-
* Every superframe handler interrupt calls this function to update the TX/RX slot status.
53-
*
54-
* @param fhss_structure Pointer to FHSS structure
55-
* @return 0 for success, -1 for fail
56-
*/
57-
int fhss_update_txrx_slots(fhss_structure_t *fhss_structure);
58-
5949
/**
6050
* Calculate time in microseconds to start of next superframe.
6151
*

source/Service_Libs/fhss/fhss_channel.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#define TRACE_GROUP "fhss"
3030

3131
// Enable this flag to use channel traces
32-
//#define FHSS_CHANNEL_DEBUG
32+
// #define FHSS_CHANNEL_DEBUG
3333

3434
static uint8_t fhss_get_bc_index(const fhss_structure_t *fhss_structure);
3535

0 commit comments

Comments
 (0)