Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fhss.c Source File

fhss.c

00001 /*
00002  * Copyright (c) 2015-2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "nsconfig.h"
00018 #include "ns_types.h"
00019 #include "fhss_api.h "
00020 #include "fhss_config.h "
00021 #include "fhss.h"
00022 #include "fhss_channel.h"
00023 #include "channel_list.h"
00024 #include "nsdynmemLIB.h"
00025 #include "fhss_beacon.h"
00026 #include "fhss_statistics.h"
00027 #include "ns_trace.h"
00028 #include "eventOS_event.h"
00029 #include "eventOS_callback_timer.h"
00030 #include "randLIB.h"
00031 #include <string.h>
00032 
00033 #define TRACE_GROUP "fhss"
00034 // Uncomment this to get timestamped output on superframe events.
00035 // Note: the result may be massive, as there will be dozens or hundreds of lines of trace per second.
00036 // #define FHSS_MASSIVE_TRACE
00037 
00038 // TODO: create linked list
00039 // FHSS object pointer
00040 fhss_structure_t *fhss_struct = 0;
00041 
00042 static bool fhss_check_remaining_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_length, uint8_t phy_header_length, uint8_t phy_tail_length);
00043 static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots);
00044 static fhss_structure_t *fhss_get_object_with_timer_id(const int8_t timer_id);
00045 static int fhss_generate_scramble_table(fhss_structure_t *fhss_structure);
00046 static bool fhss_is_there_common_divisor(uint16_t i, uint8_t j);
00047 static void fhss_update_channel(fhss_structure_t *fhss_structure);
00048 static int fhss_reset_synch_monitor(fhss_synch_monitor_s *synch_monitor, bool reset_compensation);
00049 static int fhss_reset(fhss_structure_t *fhss_structure);
00050 static void fhss_failed_list_free(fhss_structure_t *fhss_structure);
00051 
00052 
00053 int8_t fhss_enable(fhss_api_t *fhss_api, const fhss_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer, fhss_statistics_t *fhss_statistics)
00054 {
00055     if (!fhss_api || !fhss_configuration || !fhss_timer || fhss_struct) {
00056         tr_err("Invalid FHSS enable configuration");
00057         return -1;
00058     }
00059     int channel_count = channel_list_count_channels(fhss_configuration->channel_mask);
00060     if (channel_count <= 0) {
00061         // There must be at least one configured channel in channel list
00062         return -2;
00063     }
00064     fhss_struct = ns_dyn_mem_alloc(sizeof(fhss_structure_t));
00065     if (!fhss_struct) {
00066         return -3;
00067     }
00068     fhss_struct->fhss_api = fhss_api;
00069     fhss_struct->fhss_configuration = *fhss_configuration;
00070     fhss_struct->platform_functions = *fhss_timer;
00071     fhss_struct->fhss_stats_ptr = fhss_statistics;
00072     fhss_struct->number_of_channels = channel_count;
00073 
00074     // set a invalid id to tasklet_id, so we know that one is not started yet
00075     fhss_struct->beacon_tasklet_id = -1;
00076 
00077     if (!fhss_struct->platform_functions.fhss_resolution_divider) {
00078         fhss_struct->platform_functions.fhss_resolution_divider = 1;
00079     }
00080     // Default synch interval is 240 seconds
00081     if (!fhss_struct->fhss_configuration.fhss_max_synch_interval) {
00082         fhss_struct->fhss_configuration.fhss_max_synch_interval = 240;
00083     }
00084     ns_list_init(&fhss_struct->fhss_failed_tx_list);
00085     fhss_struct->own_hop = 0xff;
00086     fhss_reset(fhss_struct);
00087     fhss_reset_synch_monitor(&fhss_struct->synch_monitor, true);
00088     fhss_struct->active_fhss_events = 0;
00089     fhss_struct->fhss_beacon_info_store = NULL;
00090     fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb);
00091 
00092     fhss_generate_scramble_table(fhss_struct);
00093 
00094     if (fhss_beacon_create_tasklet(fhss_struct) < 0) {
00095         // XXX: should we free the fhss_structure here?
00096         return -5;
00097     }
00098 
00099     return 0;
00100 }
00101 
00102 int8_t fhss_set_datarate(fhss_structure_t *fhss_structure, uint32_t datarate)
00103 {
00104     if (!fhss_structure) {
00105         return -1;
00106     }
00107     // If datarate is not set, use default 250kbit/s. Datarate is used as divider later.
00108     if (!datarate) {
00109         datarate = 250000;
00110     }
00111     fhss_structure->datarate = datarate;
00112     return 0;
00113 }
00114 
00115 int8_t fhss_set_synch_configuration(fhss_structure_t *fhss_structure, const fhss_synch_configuration_t *fhss_synch_configuration)
00116 {
00117     if (!fhss_structure) {
00118         return -1;
00119     }
00120     if (!fhss_synch_configuration) {
00121         return -2;
00122     }
00123     // None of the configurations can be set zero
00124     if( fhss_synch_configuration->fhss_number_of_bc_channels == 0 || fhss_synch_configuration->fhss_number_of_tx_slots == 0
00125             || fhss_synch_configuration->fhss_number_of_superframes == 0 || fhss_synch_configuration->fhss_superframe_length == 0) {
00126         return -3;
00127     }
00128     // Number of channels must be divisible with the number of broadcast channels.
00129     // Number of superframes must be divisible with the number of TX slots
00130     if (((fhss_structure->number_of_channels % fhss_synch_configuration->fhss_number_of_bc_channels) != 0) ||
00131             ((fhss_synch_configuration->fhss_number_of_superframes % fhss_synch_configuration->fhss_number_of_tx_slots) != 0) ||
00132             (fhss_synch_configuration->fhss_number_of_superframes <= fhss_synch_configuration->fhss_number_of_tx_slots)) {
00133         return -4;
00134     }
00135     fhss_structure->synch_configuration = *fhss_synch_configuration;
00136     fhss_structure->own_hop = 0;
00137     return 0;
00138 }
00139 
00140 fhss_structure_t *fhss_get_object_with_api(const fhss_api_t *fhss_api)
00141 {
00142     if (!fhss_api || !fhss_struct) {
00143         return NULL;
00144     }
00145     if (fhss_struct->fhss_api == fhss_api) {
00146         return fhss_struct;
00147     }
00148     return NULL;
00149 }
00150 
00151 bool fhss_is_synch_root(fhss_structure_t *fhss_structure)
00152 {
00153     if (fhss_structure->own_hop > 0) {
00154         return false;
00155     }
00156     return true;
00157 }
00158 
00159 void fhss_set_active_event(fhss_structure_t *fhss_structure, uint8_t event_type)
00160 {
00161     fhss_structure->active_fhss_events |= (1 << event_type);
00162 }
00163 
00164 void fhss_clear_active_event(fhss_structure_t *fhss_structure, uint8_t event_type)
00165 {
00166     fhss_structure->active_fhss_events &= ~(1 << event_type);
00167 }
00168 
00169 bool fhss_read_active_event(fhss_structure_t *fhss_structure, uint8_t event_type)
00170 {
00171     if (fhss_structure->active_fhss_events & (1 << event_type)) {
00172         return true;
00173     }
00174     return false;
00175 }
00176 
00177 static fhss_structure_t *fhss_get_object_with_timer_id(const int8_t timer_id)
00178 {
00179     if (timer_id <0 || !fhss_struct) {
00180         return NULL;
00181     }
00182     if (fhss_struct->fhss_event_timer == timer_id) {
00183         return fhss_struct;
00184     }
00185     return NULL;
00186 }
00187 
00188 static bool fhss_is_bc_sending_superframe(fhss_structure_t *fhss_structure)
00189 {
00190     if (fhss_structure->current_superframe >= fhss_structure->broadcast_start_superframe) {
00191         return true;
00192     }
00193 
00194     return false;
00195 }
00196 
00197 bool fhss_check_bad_channel(fhss_structure_t *fhss_structure, uint8_t handle)
00198 {
00199     if (!fhss_structure) {
00200         return false;
00201     }
00202     fhss_failed_tx_t *failed_tx = fhss_failed_handle_find(fhss_structure, handle);
00203     if (!failed_tx) {
00204         return true;
00205     }
00206     if (failed_tx->bad_channel == fhss_structure->rx_channel) {
00207         return false;
00208     }
00209     return true;
00210 }
00211 
00212 bool fhss_check_channel_type(fhss_structure_t *fhss_structure, bool is_bc, int frame_type)
00213 {
00214     if (!fhss_structure) {
00215         return false;
00216     }
00217 
00218     // Channel type check is valid only when FHSS is synchronized
00219     if(fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00220         return true;
00221     }
00222 
00223     if (frame_type == FHSS_DATA_FRAME) {
00224         if (is_bc == true) {
00225             // Drop: if packet has broadcast destination but current channel is unicast channel or current superframe is not broadcast sending superframe
00226             if ((fhss_is_current_channel_broadcast(fhss_structure) == false) || (fhss_is_bc_sending_superframe(fhss_structure) == false)) {
00227                 return false;
00228             }
00229         } else if (fhss_is_current_channel_broadcast(fhss_structure) == true) {
00230             // Drop: If waiting synchronization Beacon and packet has unicast destination
00231             if (fhss_structure->beacons_received_timer) {
00232                 return false;
00233             }
00234         }
00235     }
00236     if (frame_type == FHSS_SYNCH_FRAME) {
00237 
00238     }
00239     if (frame_type == FHSS_SYNCH_REQUEST_FRAME) {
00240         // Drop: If we have unicast channels in our configuration and current channel is broadcast channel
00241         if ((fhss_structure->number_of_channels > fhss_structure->synch_configuration.fhss_number_of_bc_channels) && (fhss_is_current_channel_broadcast(fhss_structure) == true)) {
00242             return false;
00243         }
00244 
00245         uint8_t current_superframe = fhss_structure->current_superframe;
00246         uint8_t synch_attempt = fhss_structure->beacons_received_timer;
00247         if (fhss_structure->synch_configuration.fhss_number_of_tx_slots > 1) {
00248             // Send synch request either before or after the middle of the channel depending on attempt number.
00249             uint8_t middle_of_superframes = fhss_structure->synch_configuration.fhss_number_of_superframes / 2;
00250 
00251             if (synch_attempt & 1) {
00252                 if (fhss_structure->current_superframe < middle_of_superframes) {
00253                     return false;
00254                 }
00255             } else {
00256                 if (fhss_structure->current_superframe >= middle_of_superframes) {
00257                     return false;
00258                 }
00259             }
00260         } else if ((current_superframe == 0) || (current_superframe == (fhss_structure->synch_configuration.fhss_number_of_superframes - 1))){
00261             return false;
00262         }
00263     }
00264     return true;
00265 
00266 }
00267 
00268 bool fhss_check_tx_allowed(fhss_structure_t *fhss_structure, bool is_bc, uint16_t frame_length, int frame_type, uint8_t phy_header_length, uint8_t phy_tail_length)
00269 {
00270     if (!fhss_structure) {
00271         return false;
00272     }
00273     // Check is valid only when FHSS is synchronized
00274     if(fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00275         return true;
00276     }
00277     // Allow: If sending synchronization frame
00278     if (frame_type == FHSS_SYNCH_FRAME) {
00279         return true;
00280     }
00281     // Allow: If sending broadcast (on broadcast channel)
00282     if (is_bc == true) {
00283         return true;
00284     }
00285     // Deny: If FHSS is not on TX slot
00286     if (fhss_structure->tx_allowed == false) {
00287         return false;
00288     }
00289     // Deny: If not enough time before TX slot end
00290     if (fhss_check_remaining_tx_time(fhss_structure, frame_length, phy_header_length, phy_tail_length) == false) {
00291         return false;
00292     }
00293     return true;
00294 }
00295 
00296 static int fhss_reset_synch_monitor(fhss_synch_monitor_s *synch_monitor, bool reset_compensation)
00297 {
00298     if (synch_monitor) {
00299         synch_monitor->avg_synch_fix = 0;
00300         // Initialize to -1 instead of 0 to drop the first beacon after network scan (from synch monitoring)
00301         synch_monitor->avg_synch_fix_counter = -1;
00302         if (reset_compensation == true) {
00303             synch_monitor->drift_compensation = 0;
00304         }
00305         synch_monitor->channel_counter = 0;
00306         return 0;
00307     }
00308     return -1;
00309 }
00310 
00311 static int fhss_reset(fhss_structure_t *fhss_structure)
00312 {
00313     if (fhss_structure) {
00314         fhss_structure->platform_functions.fhss_timer_stop(fhss_structure->fhss_api);
00315         fhss_struct->synch_panid = 0xffff;
00316         fhss_beacon_periodic_stop(fhss_structure);
00317         fhss_struct->current_superframe = 0;
00318         fhss_struct->current_channel_index = 0;
00319         fhss_struct->channel_list_counter = 0;
00320         if (fhss_is_synch_root(fhss_structure) == false) {
00321             fhss_struct->own_hop = 0xff;
00322         }
00323         fhss_struct->tx_allowed = false;
00324         fhss_struct->synch_interval = (uint32_t) (fhss_struct->fhss_configuration.fhss_max_synch_interval/BEACON_INTERVAL_INIT_DIVIDER) * 1000;
00325         fhss_struct->rx_channel = 0;
00326         fhss_struct->beacons_received_timer = 0;
00327         memset(fhss_struct->synch_parent, 0xff, 8);
00328         fhss_struct->send_synch_info_on_next_broadcast_channel = false;
00329         memset(&fhss_struct->synch_configuration, 0, sizeof(fhss_synch_configuration_t));
00330         fhss_struct->synch_infos_sent_counter = 0;
00331         fhss_struct->broadcast_start_superframe = 0;
00332         fhss_failed_list_free(fhss_structure);
00333         fhss_struct->fhss_state = FHSS_UNSYNCHRONIZED;
00334         return 0;
00335     }
00336     return -1;
00337 }
00338 
00339 int fhss_down(fhss_structure_t *fhss_structure)
00340 {
00341     if (fhss_structure) {
00342         fhss_reset(fhss_structure);
00343         fhss_reset_synch_monitor(&fhss_struct->synch_monitor, false);
00344         fhss_stats_update(fhss_structure, STATS_FHSS_DRIFT_COMP, fhss_structure->synch_monitor.drift_compensation);
00345         fhss_stats_update(fhss_structure, STATS_FHSS_AVG_SYNCH_FIX, fhss_structure->synch_monitor.avg_synch_fix);
00346         fhss_stats_update(fhss_structure, STATS_FHSS_SYNCH_INTERVAL, fhss_structure->synch_interval / 1000);
00347         return 0;
00348     }
00349     return -1;
00350 }
00351 
00352 
00353 int8_t fhss_disable(fhss_structure_t *fhss_structure)
00354 {
00355     if (!fhss_structure) {
00356         return -1;
00357     }
00358     ns_dyn_mem_free(fhss_structure);
00359     fhss_structure = 0;
00360     fhss_struct = 0;
00361     return 0;
00362 }
00363 
00364 void fhss_start_timer(fhss_structure_t *fhss_structure, uint32_t time, void (*callback)(const fhss_api_t *fhss_api, uint16_t))
00365 {
00366     if (callback){
00367         // Don't allow starting with zero slots
00368         if (time < fhss_structure->platform_functions.fhss_resolution_divider) {
00369             time = fhss_structure->platform_functions.fhss_resolution_divider;
00370         }
00371         fhss_structure->platform_functions.fhss_timer_start(time / fhss_structure->platform_functions.fhss_resolution_divider, callback, fhss_structure->fhss_api);
00372     }
00373 }
00374 
00375 uint32_t fhss_get_remaining_time_to_next_superframe(const fhss_structure_t *fhss_structure)
00376 {
00377     const uint32_t slots = fhss_structure->platform_functions.fhss_get_remaining_slots(fhss_structure->fhss_api);
00378     const uint32_t time = slots * fhss_structure->platform_functions.fhss_resolution_divider;
00379     return time;
00380 }
00381 
00382 void fhss_superframe_handler(const fhss_api_t *fhss_api, uint16_t delay)
00383 {
00384     int compensation = 0;
00385     fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api);
00386     if (!fhss_structure) {
00387         return;
00388     }
00389 /* Drift compensation doesn't work with Linux platform */
00390 #ifndef __linux__
00391     // Drift compensation on first superframe
00392     if (fhss_structure->current_superframe == 0) {
00393         /* Idea is to compensate number of drift_compensation (microseconds) on each channel.
00394          * However, fhss_resolution_divider defines the minimum timer resolution.
00395          * E.g. if fhss_resolution_divider = 64, compensate (drift_compensation * 64) on each 64th channel.
00396          */
00397         if (++fhss_structure->synch_monitor.channel_counter == fhss_structure->platform_functions.fhss_resolution_divider) {
00398             compensation = fhss_structure->synch_monitor.drift_compensation;
00399             fhss_structure->synch_monitor.channel_counter = 0;
00400         }
00401     }
00402 #endif //__linux__
00403     // Restart timer asap to minimize the effect of dynamic execution time of
00404     // the rest of function.
00405     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);
00406 
00407     // check, if the current frame was the last one
00408     if (fhss_structure->current_superframe >= (fhss_structure->synch_configuration.fhss_number_of_superframes - 1)) {
00409 
00410         // last superframe has passed, change channel
00411         fhss_structure->current_superframe = 0;
00412         fhss_structure->current_channel_index++;
00413         if (fhss_structure->current_channel_index >= fhss_structure->number_of_channels) {
00414             fhss_structure->synch_infos_sent_counter = 0;
00415             fhss_structure->current_channel_index = 0;
00416             fhss_structure->channel_list_counter++;
00417             // Repeated cycle is started from beginning, reset counter. Don't let the channel_list_counter overflow.
00418             if (fhss_structure->channel_list_counter >= ((uint16_t) fhss_structure->number_of_channels * MAX_SCRAMBLE_TABLE_INDEXES)) {
00419                 fhss_structure->channel_list_counter = 0;
00420             }
00421             // Hop 0 don't have parent
00422             if (fhss_is_synch_root(fhss_structure) == false) {
00423                 fhss_trig_event(fhss_structure, FHSS_COMPARE_SYNCH_PARENT);
00424             }
00425             fhss_trig_event(fhss_structure, FHSS_UPDATE_SYNCH_INFO_STORAGE);
00426         }
00427         fhss_update_channel(fhss_structure);
00428     } else  {
00429         // bump up the superframe counter
00430         fhss_structure->current_superframe++;
00431 
00432 #ifdef FHSS_MASSIVE_TRACE
00433         tr_debug("%"PRIu32": handler, super: %"PRIu8,
00434                 fhss_structure->fhss_api->read_timestamp(fhss_structure->fhss_api), fhss_structure->current_superframe);
00435 #endif
00436     }
00437     if ((fhss_structure->send_synch_info_on_next_broadcast_channel == true) && (fhss_is_current_channel_broadcast(fhss_structure) == true)) {
00438         /* Randomize sending superframe of synchronization frame:
00439          * on first superframe probability is 1/number of superframes
00440          * on second superframe probability is 1/(number of superframes-1)
00441          * on third superframe probability is 1/(number of superframes-2)
00442          * on last superframe probability is 1/1
00443          */
00444         if (randLIB_get_random_in_range(1, fhss_structure->synch_configuration.fhss_number_of_superframes - fhss_structure->current_superframe) == 1) {
00445             fhss_structure->send_synch_info_on_next_broadcast_channel = false;
00446             fhss_structure->synch_infos_sent_counter++;
00447             fhss_structure->callbacks.send_fhss_frame(fhss_structure->fhss_api, FHSS_SYNCH_FRAME);
00448         }
00449     }
00450     fhss_update_txrx_slots(fhss_structure);
00451     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);
00452     if ((fhss_structure->tx_allowed == true || fhss_is_current_channel_broadcast(fhss_structure) == true) && queue_size) {
00453         /* Start timer with random timeout to trigger TX queue poll event.
00454          * Max random is half of the superframe length. Event timer resolution is 50us.
00455          * Divide Max random with TX queue size to transmit faster when TX queue is growing
00456          */
00457         uint16_t max_random = ((fhss_structure->synch_configuration.fhss_superframe_length / 2) / 50) / queue_size;
00458         eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(1, max_random));
00459     }
00460     if (fhss_structure->fhss_timeout) {
00461         fhss_structure->fhss_timer += fhss_structure->synch_configuration.fhss_superframe_length;
00462         if (fhss_structure->fhss_timer >= fhss_structure->fhss_timeout) {
00463             fhss_trig_event(fhss_structure, FHSS_TIMER_EVENT);
00464             fhss_structure->fhss_timeout = 0;
00465             fhss_structure->fhss_timer = 0;
00466         }
00467     }
00468 }
00469 
00470 int fhss_timeout_start(fhss_structure_t *fhss_structure, uint32_t time)
00471 {
00472     if (!fhss_structure) {
00473         return -1;
00474     }
00475     fhss_structure->fhss_timeout = time;
00476     fhss_structure->fhss_timer = 0;
00477     return 0;
00478 }
00479 
00480 int fhss_timeout_stop(fhss_structure_t *fhss_structure)
00481 {
00482     if (!fhss_structure) {
00483         return -1;
00484     }
00485     fhss_structure->fhss_timeout = 0;
00486     fhss_structure->fhss_timer = 0;
00487     return 0;
00488 }
00489 
00490 int fhss_update_txrx_slots(fhss_structure_t *fhss_structure)
00491 {
00492     uint8_t cur_superframe = fhss_structure->current_superframe;
00493     uint8_t number_of_tx_slots = fhss_structure->synch_configuration.fhss_number_of_tx_slots;
00494     uint8_t number_of_superframes = fhss_structure->synch_configuration.fhss_number_of_superframes;
00495     uint8_t tx_slot_length = ((number_of_superframes / 2) / number_of_tx_slots);
00496     uint8_t tx_slot_up_limit = tx_slot_length;
00497     bool tx_allowed = false;
00498 
00499     /* FHSS Phase 1 solution. This will be updated in future since we need to be able to communicate with nodes on same hop distance.
00500      * Even (0, 2, 4,...) hops starts with TX slot and uneven (1, 3, 5, ...) hops starts with RX slot. This way we are able to communicate to our parent and child nodes.
00501      *
00502      * If number of superframes is 16 and number of TX slots is 2, this will be generated (Note: hop 0 is always border router):
00503      *
00504      * Hop         Superframe
00505      *  0  |TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|
00506      *  1  |RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|
00507      *  2  |TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|
00508      *  3  |RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|
00509      *
00510      */
00511 
00512     if ((fhss_structure->own_hop % 2)) {
00513         tx_slot_up_limit += tx_slot_length;
00514     }
00515     while(number_of_tx_slots--)
00516     {
00517         if ((cur_superframe >= (tx_slot_up_limit - tx_slot_length)) && (cur_superframe < tx_slot_up_limit)) {
00518             tx_allowed = true;
00519             break;
00520         } else {
00521             tx_slot_up_limit += (tx_slot_length * 2);
00522         }
00523     }
00524     fhss_structure->tx_allowed = tx_allowed;
00525     return 0;
00526 }
00527 
00528 static int fhss_update_drift_compensation(fhss_structure_t *fhss_structure)
00529 {
00530     int retval = 0;
00531     int channels_per_synch_period;
00532     uint16_t bc_density;
00533     uint16_t channel_dwell_time;
00534     uint32_t synch_period;
00535 
00536     if (!fhss_structure) {
00537         return 0;
00538     }
00539     bc_density = (fhss_structure->number_of_channels / fhss_structure->synch_configuration.fhss_number_of_bc_channels);
00540     channel_dwell_time = ((uint32_t)fhss_structure->synch_configuration.fhss_superframe_length * fhss_structure->synch_configuration.fhss_number_of_superframes) / 1000;
00541     // Calculate last synchronisation period
00542     if (fhss_structure->synch_interval != ((uint32_t)fhss_structure->fhss_configuration.fhss_max_synch_interval * 1000)) {
00543         // Last period was half of the current started period and max random period is shorter
00544         synch_period = (fhss_structure->synch_interval / 2) + (bc_density * channel_dwell_time) * (fhss_structure->synch_configuration.fhss_number_of_bc_channels / 2);
00545     } else {
00546         synch_period = fhss_structure->synch_interval + (bc_density * channel_dwell_time) * fhss_structure->synch_configuration.fhss_number_of_bc_channels;
00547     }
00548 
00549     // E.g. 240000ms / (50000us * 8) = 600 channels per fhss_beacon_send_interval
00550     channels_per_synch_period = (synch_period * 1000) / ((uint32_t)fhss_structure->synch_configuration.fhss_superframe_length * fhss_structure->synch_configuration.fhss_number_of_superframes);
00551     // Calculate compensation value: how much to compensate on each channel. E.g. 6000us / 600channels = 10us/channel
00552     fhss_structure->synch_monitor.drift_compensation += (fhss_structure->synch_monitor.avg_synch_fix / channels_per_synch_period);
00553     fhss_stats_update(fhss_structure, STATS_FHSS_DRIFT_COMP, fhss_structure->synch_monitor.drift_compensation);
00554     if ((fhss_structure->synch_monitor.avg_synch_fix > FHSS_SYNCH_DRIFT_TOO_HIGH_LIMIT) || (fhss_structure->synch_monitor.avg_synch_fix < -FHSS_SYNCH_DRIFT_TOO_HIGH_LIMIT)) {
00555         // Indicates that more frequent synchronization is needed
00556         retval = -1;
00557     }
00558     return retval;
00559 }
00560 
00561 static int fhss_update_synch_monitor(fhss_structure_t *fhss_structure, const fhss_synchronization_beacon_payload_s *payload, uint8_t superframe_own, int32_t remaining_time_own, const int32_t time_to_next_superframe)
00562 {
00563     fhss_synch_configuration_t *configuration = &fhss_structure->synch_configuration;
00564     int super_frame_changed = payload->current_superframe - superframe_own;
00565     int retval = 0;
00566     if (((super_frame_changed < 0) && ((super_frame_changed * -1) < (payload->number_of_superframes_per_channel / 2))) || (super_frame_changed > payload->number_of_superframes_per_channel / 2)) {
00567         /* Our superframe has changed before parent superframe -> we are running too fast
00568          * Own channel:     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00569          * Parent channel:    | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00570          * Time:            ----------------------------------->
00571          */
00572         if (super_frame_changed > 0) {
00573             super_frame_changed = (superframe_own + payload->number_of_superframes_per_channel) - payload->current_superframe;
00574         }
00575     } else {
00576         /* Parent superframe has changed before our superframe -> we are running too slow
00577          * Own channel:       | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00578          * Parent channel:  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00579          * Time:            ----------------------------------->
00580          */
00581         if (super_frame_changed < 0) {
00582             super_frame_changed = (payload->current_superframe + payload->number_of_superframes_per_channel) - superframe_own;
00583         }
00584     }
00585 
00586     /* If superframe changed during synchronization but remaining time to next superframe is high, it is likely that
00587      * superframe change is not valid anymore. Don't use this Beacon for syncronization monitoring.
00588      */
00589     if ((configuration->fhss_superframe_length - remaining_time_own) > CLOSE_TO_SUPERFRAME_LENGTH) {
00590         remaining_time_own += (int32_t) configuration->fhss_superframe_length * super_frame_changed;
00591 
00592         int32_t prev_synch_fix = (time_to_next_superframe - remaining_time_own);
00593         // After network scan counter was initialized to -1 to drop this fix from monitoring
00594         if (fhss_structure->synch_monitor.avg_synch_fix_counter >= 0) {
00595             fhss_structure->synch_monitor.avg_synch_fix += prev_synch_fix;
00596         }
00597         fhss_structure->synch_monitor.avg_synch_fix_counter++;
00598         if (fhss_structure->synch_monitor.avg_synch_fix_counter == SYNCH_MONITOR_AVG_SAMPLES) {
00599             fhss_structure->synch_monitor.avg_synch_fix /= SYNCH_MONITOR_AVG_SAMPLES;
00600             fhss_stats_update(fhss_structure, STATS_FHSS_AVG_SYNCH_FIX, fhss_structure->synch_monitor.avg_synch_fix);
00601             retval = fhss_update_drift_compensation(fhss_structure);
00602             fhss_structure->synch_monitor.avg_synch_fix_counter = 0;
00603             fhss_structure->synch_monitor.avg_synch_fix = 0;
00604         }
00605     }
00606     return retval;
00607 }
00608 
00609 int fhss_sync_with_beacon(fhss_structure_t *fhss_structure,
00610         const fhss_synchronization_beacon_payload_s *payload)
00611 {
00612     int ret_val = -1;
00613     int32_t remaining_time_own;
00614     uint8_t superframe_own;
00615 
00616     if (fhss_structure) {
00617         // Do not allow synchronising devices above 253 hops.
00618         if (payload->hop_count > 253) {
00619             return 0;
00620         }
00621         // To make synchronization monitoring more effective, drop extra Beacons.
00622         if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED && (fhss_is_current_channel_broadcast(fhss_structure) == false || (fhss_structure->beacon_received_on_this_bc_channel == true))) {
00623             return 0;
00624         }
00625 
00626         fhss_synch_configuration_t *configuration = &fhss_structure->synch_configuration;
00627         fhss_structure->beacon_received_on_this_bc_channel = true;
00628 
00629         superframe_own = fhss_structure->current_superframe;
00630         fhss_structure->current_superframe = payload->current_superframe;
00631         // Clone the static config values from parent which has the authority.
00632         configuration->fhss_number_of_bc_channels = payload->number_of_broadcast_channels;
00633         configuration->fhss_number_of_tx_slots = payload->number_of_tx_slots;
00634         configuration->fhss_superframe_length = payload->superframe_length;
00635         configuration->fhss_number_of_superframes = payload->number_of_superframes_per_channel;
00636         // todo:
00637         // * payload->time_since_last_beacon
00638         uint8_t own_hop_tmp = fhss_structure->own_hop;
00639         if (fhss_is_synch_root(fhss_structure) == false) {
00640             // my own hop count is one more than the parent's
00641             fhss_structure->own_hop = payload->hop_count + 1;
00642         }
00643         fhss_stats_update(fhss_structure, STATS_FHSS_HOP_COUNT, fhss_structure->own_hop);
00644         fhss_structure->channel_list_counter = payload->channel_list_counter;
00645         fhss_structure->current_channel_index = payload->channel_index;
00646         uint8_t mac_address[8];
00647         fhss_structure->callbacks.read_mac_address(fhss_structure->fhss_api, mac_address);
00648 
00649         fhss_structure->uc_channel_index = fhss_calculate_uc_index(fhss_structure->current_channel_index, fhss_structure->number_of_channels,
00650                 payload->number_of_broadcast_channels) + fhss_get_offset(fhss_structure, mac_address);
00651 
00652         // If current channel is not broadcast, fhss_update_channel will increase UC channel index, otherwise do it here
00653         if (fhss_is_current_channel_broadcast(fhss_structure) == true || (fhss_structure->fhss_state == FHSS_SYNCHRONIZED)) {
00654             fhss_structure->uc_channel_index += 1;
00655         }
00656         if (fhss_structure->uc_channel_index >= (fhss_structure->number_of_channels - payload->number_of_broadcast_channels)) {
00657             fhss_structure->uc_channel_index -= (fhss_structure->number_of_channels - payload->number_of_broadcast_channels);
00658         }
00659 
00660         fhss_structure->platform_functions.fhss_timer_stop(fhss_structure->fhss_api);
00661         // start timer to elapse at approximately same time as the parent will.
00662         const int32_t time_to_next_superframe = payload->remaining_slots;
00663         remaining_time_own = fhss_get_remaining_time_to_next_superframe(fhss_structure);
00664         fhss_start_timer(fhss_structure, time_to_next_superframe, fhss_superframe_handler);
00665         // Reset beacon received timer when FHSS synchronization is updated
00666         fhss_structure->beacons_received_timer = 0;
00667         uint16_t bc_density = (fhss_structure->number_of_channels / fhss_structure->synch_configuration.fhss_number_of_bc_channels);
00668         uint8_t fhss_number_of_bc_channels = fhss_structure->synch_configuration.fhss_number_of_bc_channels;
00669         uint16_t channel_dwell_time = ((uint32_t)fhss_structure->synch_configuration.fhss_superframe_length * fhss_structure->synch_configuration.fhss_number_of_superframes) / 1000;
00670 
00671         if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00672             fhss_structure->fhss_state = FHSS_SYNCHRONIZED;
00673             fhss_update_channel(fhss_structure);
00674         }
00675         if (fhss_is_synch_root(fhss_structure) == false) {
00676             // Initially synch drift might be massive. Request first few Beacons more frequently until compensation starts fixing the error.
00677             uint32_t beacon_interval_random;
00678 
00679             if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED) {
00680                 if (fhss_update_synch_monitor(fhss_structure, payload, superframe_own, remaining_time_own, time_to_next_superframe)) {
00681                     fhss_structure->synch_interval = (uint32_t) (fhss_structure->fhss_configuration.fhss_max_synch_interval/BEACON_INTERVAL_INIT_DIVIDER) * 1000;
00682                 }
00683             }
00684 
00685             if (fhss_structure->synch_interval != ((uint32_t)fhss_structure->fhss_configuration.fhss_max_synch_interval * 1000)) {
00686                 fhss_structure->synch_interval *= 2;
00687                 if (fhss_structure->synch_interval > ((uint32_t)fhss_structure->fhss_configuration.fhss_max_synch_interval * 1000)) {
00688                     fhss_structure->synch_interval = ((uint32_t)fhss_structure->fhss_configuration.fhss_max_synch_interval * 1000);
00689                 }
00690                 beacon_interval_random = (bc_density * channel_dwell_time) * randLIB_get_random_in_range(0, fhss_number_of_bc_channels/2);
00691             } else {
00692                 beacon_interval_random = (bc_density * channel_dwell_time) * randLIB_get_random_in_range(0, fhss_number_of_bc_channels);
00693             }
00694             fhss_stats_update(fhss_structure, STATS_FHSS_SYNCH_INTERVAL, fhss_structure->synch_interval / 1000);
00695             fhss_beacon_periodic_start(fhss_structure, fhss_structure->synch_interval + beacon_interval_random);
00696 
00697 #ifdef FHSS_MASSIVE_TRACE
00698             tr_debug("start timer, time now: %"PRIu32", sfr: %"PRIu8", ch-ind: %"PRIu8", time after: %"PRIu32,
00699                     fhss_structure->fhss_api->read_timestamp(fhss_structure->fhss_api), fhss_structure->current_superframe,
00700                     payload->channel_index, time_to_next_superframe);
00701 #endif
00702         }
00703         // Our hop has changed, needs to inform possible children by sending Beacon
00704         if ((own_hop_tmp != 0) && (own_hop_tmp != fhss_structure->own_hop)) {
00705             fhss_structure->send_synch_info_on_next_broadcast_channel = true;
00706         }
00707         ret_val = 0;
00708     }
00709     return ret_val;
00710 }
00711 
00712 static uint32_t fhss_get_remaining_tx_time(fhss_structure_t *fhss_structure)
00713 {
00714     /* To get the remaining TX time, following calculation is performed
00715      *
00716      *         rem. time(Y)
00717      *        |----------------|
00718      *...|    TX    |    TX    |    RX    |    RX    |...
00719      *...|   SF n   |   SF n+1 |   SF n+2 |   SF n+3 |...
00720      *
00721      * Y = remaining time of SF(n) + length of SF(n+1)
00722      *
00723      */
00724 
00725     uint32_t remaining_tx_time = 0;
00726 
00727     if (fhss_structure) {
00728         uint8_t cur_superframe = fhss_structure->current_superframe;
00729         uint8_t number_of_tx_slots = fhss_structure->synch_configuration.fhss_number_of_tx_slots;
00730         uint8_t number_of_superframes = fhss_structure->synch_configuration.fhss_number_of_superframes;
00731         uint8_t tx_slot_length = ((number_of_superframes / 2) / number_of_tx_slots);
00732         uint8_t tx_slot_up_limit = tx_slot_length;
00733         uint16_t superframe_length = fhss_structure->synch_configuration.fhss_superframe_length;
00734 
00735         if ((fhss_structure->own_hop % 2)) {
00736             tx_slot_up_limit += tx_slot_length;
00737         }
00738         while(number_of_tx_slots--)
00739         {
00740             if ((cur_superframe >= (tx_slot_up_limit - tx_slot_length)) && (cur_superframe < tx_slot_up_limit)) {
00741                 remaining_tx_time = ((uint32_t)((tx_slot_up_limit - 1) - cur_superframe) * superframe_length) + fhss_get_remaining_time_to_next_superframe(fhss_structure);
00742                 break;
00743             } else {
00744                 tx_slot_up_limit += (tx_slot_length * 2);
00745             }
00746         }
00747     }
00748     return remaining_tx_time;
00749 }
00750 
00751 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)
00752 {
00753     return ((1000000 / (fhss_structure->datarate / 8)) * (bytes_to_send + phy_header_length + phy_tail_length));
00754 }
00755 
00756 // CCA adds extra 2ms with FHSS
00757 #define CCA_FHSS_PERIOD 2000
00758 // Ack frame length
00759 #define ACK_LENGTH  5
00760 
00761 static bool fhss_check_remaining_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_length, uint8_t phy_header_length, uint8_t phy_tail_length)
00762 {
00763     bool retval = false;
00764     uint32_t remaining_tx_time;
00765     uint32_t needed_tx_time;
00766     uint32_t tx_processing_delay;
00767     uint32_t ack_processing_delay;
00768 
00769     if (!fhss_structure) {
00770         return retval;
00771     }
00772 
00773     // Don't care when FHSS is unsynchronized
00774     if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00775         retval = true;
00776     } else {
00777         tx_processing_delay = fhss_structure->fhss_configuration.fhss_tuning_parameters.tx_processing_delay;
00778         ack_processing_delay = fhss_structure->fhss_configuration.fhss_tuning_parameters.ack_processing_delay;
00779         // Calculate needed TX time (us): CCA static period + TX processing delays + transmission time + Ack processing delays + Ack transmission time
00780         needed_tx_time = CCA_FHSS_PERIOD + tx_processing_delay + fhss_get_tx_time(fhss_structure, tx_length, phy_header_length, phy_tail_length)
00781                         + ack_processing_delay + fhss_get_tx_time(fhss_structure, ACK_LENGTH, phy_header_length, phy_tail_length);
00782         remaining_tx_time = fhss_get_remaining_tx_time(fhss_structure);
00783         if(needed_tx_time <= remaining_tx_time) {
00784             retval = true;
00785         }
00786     }
00787     return retval;
00788 }
00789 
00790 int fhss_update_synch_parent_address(fhss_structure_t *fhss_structure)
00791 {
00792     uint8_t parent_address[8];
00793 
00794     if (!fhss_get_parent_address(fhss_structure, parent_address)) {
00795         memcpy(fhss_structure->synch_parent, parent_address, 8);
00796         return 0;
00797     }
00798     return -1;
00799 }
00800 
00801 void fhss_trig_event(fhss_structure_t *fhss_structure, uint8_t event_type)
00802 {
00803     if (fhss_read_active_event(fhss_structure, event_type) == true) {
00804         return;
00805     }
00806     arm_event_s event;
00807     event.receiver = fhss_structure->beacon_tasklet_id;
00808     event.sender = 0;
00809     event.event_type = event_type;
00810     event.event_id = 0;
00811     event.data_ptr = fhss_structure;
00812     event.priority = ARM_LIB_HIGH_PRIORITY_EVENT;
00813     event.event_data = 0;
00814     if (eventOS_event_send(&event) != 0) {
00815         tr_error("Event trigger failed: eventOS_event_send() failed");
00816     } else {
00817         fhss_set_active_event(fhss_structure, event_type);
00818     }
00819 }
00820 
00821 int fhss_get_parent_address(fhss_structure_t *fhss_structure, uint8_t *p_addr)
00822 {
00823     int ret_val = -1;
00824     if (!fhss_structure || !p_addr) {
00825         return -1;
00826     }
00827 
00828     ret_val = fhss_structure->callbacks.read_coord_mac_address(fhss_structure->fhss_api, p_addr);
00829 
00830     if (ret_val) {
00831         // Use default synchronization parent when RPL parent not found
00832         memcpy(p_addr, fhss_structure->synch_parent, 8);
00833         ret_val = 0;
00834     }
00835     return ret_val;
00836 }
00837 
00838 int fhss_compare_with_synch_parent_address(fhss_structure_t *fhss_structure, const uint8_t *source_addr)
00839 {
00840     int ret_val = -1;
00841     if (!fhss_structure || !source_addr) {
00842         return ret_val;
00843     }
00844     uint8_t parent_address[8];
00845 
00846     if (fhss_is_synch_root(fhss_structure) == false) {
00847         if (!fhss_get_parent_address(fhss_structure, parent_address)) {
00848             ret_val = memcmp(source_addr, parent_address, 8);
00849         }
00850     }
00851     return ret_val;
00852 }
00853 
00854 static void fhss_update_channel(fhss_structure_t *fhss_structure)
00855 {
00856     // If channel is broadcast channel (true), send event
00857     if (fhss_change_to_next_channel(fhss_structure) == true) {
00858         // Only if device is border router
00859         if (fhss_structure->own_hop == 0) {
00860             fhss_trig_event(fhss_structure, FHSS_BROADCAST_CHANNEL);
00861         }
00862     }
00863 }
00864 
00865 static bool fhss_is_there_common_divisor(uint16_t i, uint8_t j)
00866 {
00867     if (i < j) {
00868         uint_fast8_t t = j; j = (uint8_t) i; i = t;
00869     }
00870     for(uint_fast8_t k=2; k<=j; k++) {
00871         if (i % k == 0 && j % k == 0) {
00872             return true;
00873         }
00874     }
00875     return false;
00876 }
00877 
00878 
00879 static int fhss_generate_scramble_table(fhss_structure_t *fhss_structure)
00880 {
00881     uint8_t j = 2;
00882     // Generate indexes to extend the channel sequence. Generated indexes cannot have common divisors with value number_of_channels.
00883     for(int i=0; i<MAX_SCRAMBLE_TABLE_INDEXES;)
00884     {
00885         // Common divisors are skipped
00886         if (fhss_is_there_common_divisor(fhss_structure->number_of_channels, j) == false) {
00887             fhss_structure->fhss_scramble_table[i] = j;
00888             i++;
00889         }
00890         j++;
00891     }
00892     return 0;
00893 }
00894 
00895 static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots)
00896 {
00897     (void) slots;
00898     fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id);
00899     if (fhss_structure) {
00900         fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api);
00901     }
00902 }
00903 
00904 fhss_beacon_info_t *fhss_get_beacon_info(fhss_structure_t *fhss_structure, uint16_t pan_id)
00905 {
00906     fhss_beacon_info_t *beacon_info;
00907     beacon_info = fhss_structure->fhss_beacon_info_store;
00908     while (beacon_info) {
00909         if (beacon_info->pan_id == pan_id) {
00910             break;
00911         }
00912         beacon_info = beacon_info->next;
00913     }
00914     return beacon_info;
00915 }
00916 
00917 static void fhss_store_beacon_info(fhss_structure_t *fhss_structure, fhss_beacon_info_t *beacon_info)
00918 {
00919     fhss_beacon_info_t *beacon_info_cur;
00920     beacon_info->next = NULL;
00921     if (!fhss_structure->fhss_beacon_info_store) {
00922         fhss_structure->fhss_beacon_info_store = beacon_info;
00923         return;
00924     }
00925     beacon_info_cur = fhss_structure->fhss_beacon_info_store;
00926     while (beacon_info_cur->next != NULL) {
00927         beacon_info_cur = beacon_info_cur->next;
00928     }
00929     beacon_info_cur->next = beacon_info;
00930 }
00931 
00932 static void fhss_write_beacon_info(fhss_beacon_info_t *beacon_info, uint16_t pan_id, uint8_t *source_address, uint32_t timestamp, uint8_t *synch_info)
00933 {
00934     beacon_info->pan_id = pan_id;
00935     memcpy(beacon_info->source_address, source_address, 8);
00936     beacon_info->timestamp = timestamp;
00937     memcpy(beacon_info->synch_info, synch_info, sizeof(beacon_info->synch_info));
00938 }
00939 
00940 static fhss_beacon_info_t *fhss_create_beacon_info(fhss_structure_t *fhss_structure)
00941 {
00942     fhss_beacon_info_t *beacon_info = ns_dyn_mem_temporary_alloc(sizeof(fhss_beacon_info_t));
00943     if (!beacon_info) {
00944         return NULL;
00945     }
00946     fhss_store_beacon_info(fhss_structure, beacon_info);
00947     return beacon_info;
00948 }
00949 
00950 static int fhss_remove_beacon_info(fhss_structure_t *fhss_structure, uint16_t pan_id)
00951 {
00952     if (!fhss_structure || !fhss_structure->fhss_beacon_info_store) {
00953         return -1;
00954     }
00955 
00956     if (fhss_structure->fhss_beacon_info_store->pan_id == pan_id) {
00957         fhss_beacon_info_t *next = fhss_structure->fhss_beacon_info_store->next;
00958         ns_dyn_mem_free(fhss_structure->fhss_beacon_info_store);
00959         fhss_structure->fhss_beacon_info_store = next;
00960         return 0;
00961     }
00962 
00963     fhss_beacon_info_t *removed_beacon_info = fhss_structure->fhss_beacon_info_store->next;
00964     fhss_beacon_info_t *prev_beacon_info = fhss_structure->fhss_beacon_info_store;
00965 
00966     while (removed_beacon_info) {
00967         if (removed_beacon_info->pan_id == pan_id) {
00968             fhss_beacon_info_t *next = removed_beacon_info->next;
00969             ns_dyn_mem_free(removed_beacon_info);
00970             prev_beacon_info->next = next;
00971             return 0;
00972         }
00973         prev_beacon_info = removed_beacon_info;
00974         removed_beacon_info = removed_beacon_info->next;
00975     }
00976     return -1;
00977 }
00978 
00979 int fhss_flush_beacon_info_storage(fhss_structure_t *fhss_structure)
00980 {
00981     if (!fhss_structure) {
00982         return -1;
00983     }
00984     fhss_beacon_info_t *beacon_info = fhss_structure->fhss_beacon_info_store;
00985     while (beacon_info) {
00986         fhss_beacon_info_t *next = beacon_info->next;
00987         ns_dyn_mem_free(beacon_info);
00988         beacon_info = next;
00989     }
00990     fhss_structure->fhss_beacon_info_store = NULL;
00991     return 0;
00992 }
00993 
00994 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)
00995 {
00996     if (!fhss_structure || !source_address || !synch_info) {
00997         return -1;
00998     }
00999     fhss_beacon_info_t *beacon_info = fhss_get_beacon_info(fhss_structure, pan_id);
01000     if (!beacon_info) {
01001         beacon_info = fhss_create_beacon_info(fhss_structure);
01002     }
01003     if (!beacon_info) {
01004         tr_error("Beacon data not allocated");
01005         return -2;
01006     }
01007     fhss_write_beacon_info(beacon_info, pan_id, source_address, timestamp, synch_info);
01008     return 0;
01009 }
01010 
01011 void fhss_update_beacon_info_lifetimes(fhss_structure_t *fhss_structure, uint32_t timestamp)
01012 {
01013     fhss_beacon_info_t *beacon_info;
01014     beacon_info = fhss_structure->fhss_beacon_info_store;
01015     while (beacon_info) {
01016         uint32_t time_since_added = timestamp - beacon_info->timestamp;
01017         // timestamp is microseconds, lifetime is seconds
01018         if (time_since_added >= ((uint32_t)BEACON_INFO_LIFETIME * 1000000)) {
01019             if (fhss_remove_beacon_info(fhss_structure, beacon_info->pan_id) == 0) {
01020                 return;
01021             }
01022         }
01023         beacon_info = beacon_info->next;
01024     }
01025 }
01026 
01027 fhss_failed_tx_t *fhss_failed_handle_find(fhss_structure_t *fhss_structure, uint8_t handle)
01028 {
01029     ns_list_foreach(fhss_failed_tx_t, cur, &fhss_structure->fhss_failed_tx_list) {
01030         if (cur->handle == handle) {
01031             return cur;
01032         }
01033     }
01034     return NULL;
01035 }
01036 
01037 int fhss_failed_handle_add(fhss_structure_t *fhss_structure, uint8_t handle)
01038 {
01039     fhss_failed_tx_t *failed_tx = ns_dyn_mem_alloc(sizeof(fhss_failed_tx_t));
01040     if (!failed_tx) {
01041         return -2;
01042     }
01043     failed_tx->bad_channel = fhss_structure->rx_channel;
01044     failed_tx->retries_done = 0;
01045     failed_tx->handle = handle;
01046     ns_list_add_to_end(&fhss_structure->fhss_failed_tx_list, failed_tx);
01047     return 0;
01048 }
01049 
01050 int fhss_failed_handle_remove(fhss_structure_t *fhss_structure, uint8_t handle)
01051 {
01052     fhss_failed_tx_t *failed_tx = fhss_failed_handle_find(fhss_structure, handle);
01053     if (!failed_tx) {
01054         return -1;
01055     }
01056     ns_list_remove(&fhss_structure->fhss_failed_tx_list, failed_tx);
01057     ns_dyn_mem_free(failed_tx); // Free entry
01058     return 0;
01059 }
01060 
01061 static void fhss_failed_list_free(fhss_structure_t *fhss_structure)
01062 {
01063     for (uint16_t i = 0; i<256; i++) {
01064         fhss_failed_handle_remove(fhss_structure, i);
01065     }
01066 }