Kenji Arai / TYBLE16_mbedlized_os5_several_examples_1st

Dependencies:   nRF51_Vdd TextLCD BME280

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fhss.c Source File

fhss.c

00001 /*
00002  * Copyright (c) 2015-2018, 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_common.h"
00023 #include "fhss_channel.h"
00024 #include "channel_list.h"
00025 #include "nsdynmemLIB.h"
00026 #include "fhss_statistics.h"
00027 #include "ns_trace.h"
00028 #include "eventOS_event.h"
00029 #include "eventOS_callback_timer.h"
00030 #include "platform/arm_hal_interrupt.h"
00031 #include "randLIB.h"
00032 #include "common_functions.h"
00033 #include <string.h>
00034 
00035 #define TRACE_GROUP "fhss"
00036 
00037 static int fhss_reset(fhss_structure_t *fhss_structure);
00038 static bool fhss_is_bc_sending_superframe(fhss_structure_t *fhss_structure);
00039 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);
00040 static bool fhss_is_there_common_divisor(uint16_t i, uint8_t j);
00041 static void fhss_beacon_received(fhss_structure_t *fhss_structure, const uint8_t *synch_info, const uint32_t elapsed_time);
00042 static void fhss_superframe_handler(const fhss_api_t *fhss_api, uint16_t delay);
00043 static int8_t fhss_beacon_create_tasklet(fhss_structure_t *fhss_structure);
00044 static void fhss_beacon_tasklet_func(arm_event_s* event);
00045 static int fhss_beacon_periodic_start(fhss_structure_t *fhss_structure, uint32_t time_to_first_beacon);
00046 static void fhss_beacon_periodic_stop(fhss_structure_t *fhss_structure);
00047 
00048 fhss_structure_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)
00049 {
00050     if (!fhss_api || !fhss_configuration || !fhss_timer) {
00051         tr_err("Invalid FHSS enable configuration");
00052         return NULL;
00053     }
00054     int channel_count = channel_list_count_channels(fhss_configuration->channel_mask);
00055     if (channel_count <= 0) {
00056         // There must be at least one configured channel in channel list
00057         return NULL;
00058     }
00059     fhss_structure_t *fhss_struct = fhss_allocate_instance(fhss_api, fhss_timer);
00060     if (!fhss_struct) {
00061         return NULL;
00062     }
00063     fhss_struct->bs = ns_dyn_mem_alloc(sizeof(fhss_bs_t));
00064     if (!fhss_struct->bs) {
00065         fhss_free_instance(fhss_api);
00066         return NULL;
00067     }
00068     memset(fhss_struct->bs, 0, sizeof(fhss_bs_t));
00069 
00070     fhss_struct->bs->fhss_configuration = *fhss_configuration;
00071     fhss_struct->bs->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     // Default synch interval is 240 seconds
00078     if (!fhss_struct->bs->fhss_configuration.fhss_max_synch_interval) {
00079         fhss_struct->bs->fhss_configuration.fhss_max_synch_interval = 240;
00080     }
00081     ns_list_init(&fhss_struct->fhss_failed_tx_list);
00082     fhss_struct->own_hop = 0xff;
00083     fhss_reset(fhss_struct);
00084 
00085     if (fhss_beacon_create_tasklet(fhss_struct) < 0) {
00086         ns_dyn_mem_free(fhss_struct->bs);
00087         fhss_free_instance(fhss_api);
00088         return NULL;
00089     }
00090 
00091     return fhss_struct;
00092 }
00093 
00094 bool fhss_is_synch_root(fhss_structure_t *fhss_structure)
00095 {
00096     if (fhss_structure->own_hop > 0) {
00097         return false;
00098     }
00099     return true;
00100 }
00101 
00102 static bool fhss_is_bc_sending_superframe(fhss_structure_t *fhss_structure)
00103 {
00104     if (fhss_structure->bs->current_superframe >= fhss_structure->bs->broadcast_start_superframe) {
00105         return true;
00106     }
00107 
00108     return false;
00109 }
00110 
00111 static bool fhss_check_bad_channel(fhss_structure_t *fhss_structure, uint8_t handle)
00112 {
00113     if (!fhss_structure) {
00114         return false;
00115     }
00116     fhss_failed_tx_t *failed_tx = fhss_failed_handle_find(fhss_structure, handle);
00117     if (!failed_tx) {
00118         return true;
00119     }
00120     if (failed_tx->bad_channel == fhss_structure->rx_channel) {
00121         return false;
00122     }
00123     return true;
00124 }
00125 
00126 static bool fhss_check_channel_type(fhss_structure_t *fhss_structure, bool is_bc, int frame_type)
00127 {
00128     if (!fhss_structure) {
00129         return false;
00130     }
00131 
00132     // Channel type check is valid only when FHSS is synchronized
00133     if(fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00134         return true;
00135     }
00136 
00137     if (frame_type == FHSS_DATA_FRAME) {
00138         if (is_bc == true) {
00139             // Drop: if packet has broadcast destination but current channel is unicast channel or current superframe is not broadcast sending superframe
00140             if ((fhss_is_current_channel_broadcast(fhss_structure) == false) || (fhss_is_bc_sending_superframe(fhss_structure) == false)) {
00141                 return false;
00142             }
00143         } else if (fhss_is_current_channel_broadcast(fhss_structure) == true) {
00144             // Drop: If waiting synchronization Beacon and packet has unicast destination
00145             if (fhss_structure->bs->beacons_received_timer) {
00146                 return false;
00147             }
00148         }
00149     }
00150     if (frame_type == FHSS_SYNCH_FRAME) {
00151 
00152     }
00153     if (frame_type == FHSS_SYNCH_REQUEST_FRAME) {
00154         // Drop: If we have unicast channels in our configuration and current channel is broadcast channel
00155         if ((fhss_structure->number_of_channels > fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels) && (fhss_is_current_channel_broadcast(fhss_structure) == true)) {
00156             return false;
00157         }
00158 
00159         uint8_t current_superframe = fhss_structure->bs->current_superframe;
00160         uint8_t synch_attempt = fhss_structure->bs->beacons_received_timer;
00161         if (fhss_structure->bs->synch_configuration.fhss_number_of_tx_slots > 1) {
00162             // Send synch request either before or after the middle of the channel depending on attempt number.
00163             uint8_t middle_of_superframes = fhss_structure->bs->synch_configuration.fhss_number_of_superframes / 2;
00164 
00165             if (synch_attempt & 1) {
00166                 if (fhss_structure->bs->current_superframe < middle_of_superframes) {
00167                     return false;
00168                 }
00169             } else {
00170                 if (fhss_structure->bs->current_superframe >= middle_of_superframes) {
00171                     return false;
00172                 }
00173             }
00174         } else if ((current_superframe == 0) || (current_superframe == (fhss_structure->bs->synch_configuration.fhss_number_of_superframes - 1))){
00175             return false;
00176         }
00177     }
00178     return true;
00179 
00180 }
00181 
00182 static 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)
00183 {
00184     if (!fhss_structure) {
00185         return false;
00186     }
00187     // Check is valid only when FHSS is synchronized
00188     if(fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00189         return true;
00190     }
00191     // Allow: If sending synchronization frame
00192     if (frame_type == FHSS_SYNCH_FRAME) {
00193         return true;
00194     }
00195     // Allow: If sending broadcast (on broadcast channel)
00196     if (is_bc == true) {
00197         return true;
00198     }
00199     // Deny: If FHSS is not on TX slot
00200     if (fhss_structure->bs->tx_allowed == false) {
00201         return false;
00202     }
00203     // Deny: If not enough time before TX slot end
00204     if (fhss_check_remaining_tx_time(fhss_structure, frame_length, phy_header_length, phy_tail_length) == false) {
00205         return false;
00206     }
00207     return true;
00208 }
00209 
00210 static int fhss_reset_synch_monitor(fhss_synch_monitor_s *synch_monitor)
00211 {
00212     if (synch_monitor) {
00213         synch_monitor->avg_synch_fix = 0;
00214         // Initialize to -1 instead of 0 to drop the first beacon after network scan (from synch monitoring)
00215         synch_monitor->avg_synch_fix_counter = -1;
00216         synch_monitor->channel_counter = 0;
00217         return 0;
00218     }
00219     return -1;
00220 }
00221 
00222 static int fhss_update_txrx_slots(fhss_structure_t *fhss_structure)
00223 {
00224     uint8_t cur_superframe = fhss_structure->bs->current_superframe;
00225     uint8_t number_of_tx_slots = fhss_structure->bs->synch_configuration.fhss_number_of_tx_slots;
00226     uint8_t number_of_superframes = fhss_structure->bs->synch_configuration.fhss_number_of_superframes;
00227     uint8_t tx_slot_length = ((number_of_superframes / 2) / number_of_tx_slots);
00228     uint8_t tx_slot_up_limit = tx_slot_length;
00229     bool tx_allowed = false;
00230 
00231     /* FHSS Phase 1 solution. This will be updated in future since we need to be able to communicate with nodes on same hop distance.
00232      * 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.
00233      *
00234      * If number of superframes is 16 and number of TX slots is 2, this will be generated (Note: hop 0 is always border router):
00235      *
00236      * Hop         Superframe
00237      *  0  |TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|
00238      *  1  |RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|
00239      *  2  |TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|
00240      *  3  |RX|RX|RX|RX|TX|TX|TX|TX|RX|RX|RX|RX|TX|TX|TX|TX|
00241      *
00242      */
00243 
00244     if ((fhss_structure->own_hop % 2)) {
00245         tx_slot_up_limit += tx_slot_length;
00246     }
00247     while(number_of_tx_slots--)
00248     {
00249         if ((cur_superframe >= (tx_slot_up_limit - tx_slot_length)) && (cur_superframe < tx_slot_up_limit)) {
00250             tx_allowed = true;
00251             break;
00252         } else {
00253             tx_slot_up_limit += (tx_slot_length * 2);
00254         }
00255     }
00256     fhss_structure->bs->tx_allowed = tx_allowed;
00257     return 0;
00258 }
00259 
00260 static int fhss_update_drift_compensation(fhss_structure_t *fhss_structure)
00261 {
00262     int retval = 0;
00263     int channels_per_synch_period;
00264     uint16_t bc_density;
00265     uint16_t channel_dwell_time;
00266     uint32_t synch_period;
00267 
00268     if (!fhss_structure) {
00269         return 0;
00270     }
00271     bc_density = (fhss_structure->number_of_channels / fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels);
00272     channel_dwell_time = ((uint32_t)fhss_structure->bs->synch_configuration.fhss_superframe_length * fhss_structure->bs->synch_configuration.fhss_number_of_superframes) / 1000;
00273     // Calculate last synchronisation period
00274     if (fhss_structure->bs->synch_interval != ((uint32_t)fhss_structure->bs->fhss_configuration.fhss_max_synch_interval * 1000)) {
00275         // Last period was half of the current started period and max random period is shorter
00276         synch_period = (fhss_structure->bs->synch_interval / 2) + (bc_density * channel_dwell_time) * (fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels / 2);
00277     } else {
00278         synch_period = fhss_structure->bs->synch_interval + (bc_density * channel_dwell_time) * fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels;
00279     }
00280 
00281     // E.g. 240000ms / (50000us * 8) = 600 channels per fhss_beacon_send_interval
00282     channels_per_synch_period = (synch_period * 1000) / ((uint32_t)fhss_structure->bs->synch_configuration.fhss_superframe_length * fhss_structure->bs->synch_configuration.fhss_number_of_superframes);
00283     // Calculate compensation value: how much to compensate on each channel. E.g. 6000us / 600channels = 10us/channel
00284     fhss_structure->bs->synch_monitor.drift_compensation += (fhss_structure->bs->synch_monitor.avg_synch_fix / channels_per_synch_period);
00285     fhss_stats_update(fhss_structure, STATS_FHSS_DRIFT_COMP, fhss_structure->bs->synch_monitor.drift_compensation);
00286     if ((fhss_structure->bs->synch_monitor.avg_synch_fix > FHSS_SYNCH_DRIFT_TOO_HIGH_LIMIT) || (fhss_structure->bs->synch_monitor.avg_synch_fix < -FHSS_SYNCH_DRIFT_TOO_HIGH_LIMIT)) {
00287         // Indicates that more frequent synchronization is needed
00288         retval = -1;
00289     }
00290     return retval;
00291 }
00292 
00293 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)
00294 {
00295     fhss_synch_configuration_t *configuration = &fhss_structure->bs->synch_configuration;
00296     int super_frame_changed = payload->current_superframe - superframe_own;
00297     int retval = 0;
00298     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)) {
00299         /* Our superframe has changed before parent superframe -> we are running too fast
00300          * Own channel:     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00301          * Parent channel:    | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00302          * Time:            ----------------------------------->
00303          */
00304         if (super_frame_changed > 0) {
00305             super_frame_changed = (superframe_own + payload->number_of_superframes_per_channel) - payload->current_superframe;
00306         }
00307     } else {
00308         /* Parent superframe has changed before our superframe -> we are running too slow
00309          * Own channel:       | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00310          * Parent channel:  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 |
00311          * Time:            ----------------------------------->
00312          */
00313         if (super_frame_changed < 0) {
00314             super_frame_changed = (payload->current_superframe + payload->number_of_superframes_per_channel) - superframe_own;
00315         }
00316     }
00317 
00318     /* If superframe changed during synchronization but remaining time to next superframe is high, it is likely that
00319      * superframe change is not valid anymore. Don't use this Beacon for syncronization monitoring.
00320      */
00321     if ((configuration->fhss_superframe_length - remaining_time_own) > CLOSE_TO_SUPERFRAME_LENGTH) {
00322         remaining_time_own += (int32_t) configuration->fhss_superframe_length * super_frame_changed;
00323 
00324         int32_t prev_synch_fix = (time_to_next_superframe - remaining_time_own);
00325         // After network scan counter was initialized to -1 to drop this fix from monitoring
00326         if (fhss_structure->bs->synch_monitor.avg_synch_fix_counter >= 0) {
00327             fhss_structure->bs->synch_monitor.avg_synch_fix += prev_synch_fix;
00328         }
00329         fhss_structure->bs->synch_monitor.avg_synch_fix_counter++;
00330         if (fhss_structure->bs->synch_monitor.avg_synch_fix_counter == SYNCH_MONITOR_AVG_SAMPLES) {
00331             fhss_structure->bs->synch_monitor.avg_synch_fix /= SYNCH_MONITOR_AVG_SAMPLES;
00332             fhss_stats_update(fhss_structure, STATS_FHSS_AVG_SYNCH_FIX, fhss_structure->bs->synch_monitor.avg_synch_fix);
00333             retval = fhss_update_drift_compensation(fhss_structure);
00334             fhss_structure->bs->synch_monitor.avg_synch_fix_counter = 0;
00335             fhss_structure->bs->synch_monitor.avg_synch_fix = 0;
00336         }
00337     }
00338     return retval;
00339 }
00340 
00341 static int fhss_sync_with_beacon(fhss_structure_t *fhss_structure,
00342         const fhss_synchronization_beacon_payload_s *payload)
00343 {
00344     int ret_val = -1;
00345     int32_t remaining_time_own;
00346     uint8_t superframe_own;
00347 
00348     if (fhss_structure) {
00349         // Do not allow synchronising devices above 253 hops.
00350         if (payload->hop_count > (FHSS_MAX_ALLOWED_HOPS-1)) {
00351             return 0;
00352         }
00353         // To make synchronization monitoring more effective, drop extra Beacons.
00354         if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED && (fhss_is_current_channel_broadcast(fhss_structure) == false || (fhss_structure->bs->beacon_received_on_this_bc_channel == true))) {
00355             return 0;
00356         }
00357 
00358         fhss_synch_configuration_t *configuration = &fhss_structure->bs->synch_configuration;
00359         fhss_structure->bs->beacon_received_on_this_bc_channel = true;
00360 
00361         superframe_own = fhss_structure->bs->current_superframe;
00362         fhss_structure->bs->current_superframe = payload->current_superframe;
00363         // Clone the static config values from parent which has the authority.
00364         configuration->fhss_number_of_bc_channels = payload->number_of_broadcast_channels;
00365         configuration->fhss_number_of_tx_slots = payload->number_of_tx_slots;
00366         configuration->fhss_superframe_length = payload->superframe_length;
00367         configuration->fhss_number_of_superframes = payload->number_of_superframes_per_channel;
00368         // todo:
00369         // * payload->time_since_last_beacon
00370         uint8_t own_hop_tmp = fhss_structure->own_hop;
00371         if (fhss_is_synch_root(fhss_structure) == false) {
00372             // my own hop count is one more than the parent's
00373             fhss_structure->own_hop = payload->hop_count + 1;
00374         }
00375         fhss_stats_update(fhss_structure, STATS_FHSS_HOP_COUNT, fhss_structure->own_hop);
00376         fhss_structure->bs->channel_list_counter = payload->channel_list_counter;
00377         fhss_structure->bs->current_channel_index = payload->channel_index;
00378         uint8_t mac_address[8];
00379         fhss_structure->callbacks.read_mac_address(fhss_structure->fhss_api, mac_address);
00380 
00381         fhss_structure->bs->uc_channel_index = fhss_calculate_uc_index(fhss_structure->bs->current_channel_index, fhss_structure->number_of_channels,
00382                 payload->number_of_broadcast_channels) + fhss_get_offset(fhss_structure, mac_address);
00383 
00384         // If current channel is not broadcast, fhss_update_channel will increase UC channel index, otherwise do it here
00385         if (fhss_is_current_channel_broadcast(fhss_structure) == true || (fhss_structure->fhss_state == FHSS_SYNCHRONIZED)) {
00386             fhss_structure->bs->uc_channel_index += 1;
00387         }
00388         if (fhss_structure->bs->uc_channel_index >= (fhss_structure->number_of_channels - payload->number_of_broadcast_channels)) {
00389             fhss_structure->bs->uc_channel_index -= (fhss_structure->number_of_channels - payload->number_of_broadcast_channels);
00390         }
00391 
00392         fhss_structure->platform_functions.fhss_timer_stop(fhss_superframe_handler, fhss_structure->fhss_api);
00393         // start timer to elapse at approximately same time as the parent will.
00394         const int32_t time_to_next_superframe = payload->remaining_slots;
00395         remaining_time_own = fhss_get_remaining_time_to_next_superframe(fhss_structure);
00396         fhss_start_timer(fhss_structure, time_to_next_superframe, fhss_superframe_handler);
00397         // Reset beacon received timer when FHSS synchronization is updated
00398         fhss_structure->bs->beacons_received_timer = 0;
00399         uint16_t bc_density = (fhss_structure->number_of_channels / fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels);
00400         uint8_t fhss_number_of_bc_channels = fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels;
00401         uint16_t channel_dwell_time = ((uint32_t)fhss_structure->bs->synch_configuration.fhss_superframe_length * fhss_structure->bs->synch_configuration.fhss_number_of_superframes) / 1000;
00402 
00403         if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00404             fhss_structure->fhss_state = FHSS_SYNCHRONIZED;
00405             fhss_change_to_next_channel(fhss_structure);
00406         }
00407         if (fhss_is_synch_root(fhss_structure) == false) {
00408             // Initially synch drift might be massive. Request first few Beacons more frequently until compensation starts fixing the error.
00409             uint32_t beacon_interval_random;
00410 
00411             if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED) {
00412                 if (fhss_update_synch_monitor(fhss_structure, payload, superframe_own, remaining_time_own, time_to_next_superframe)) {
00413                     fhss_structure->bs->synch_interval = (uint32_t) (fhss_structure->bs->fhss_configuration.fhss_max_synch_interval/BEACON_INTERVAL_INIT_DIVIDER) * 1000;
00414                 }
00415             }
00416 
00417             if (fhss_structure->bs->synch_interval != ((uint32_t)fhss_structure->bs->fhss_configuration.fhss_max_synch_interval * 1000)) {
00418                 fhss_structure->bs->synch_interval *= 2;
00419                 if (fhss_structure->bs->synch_interval > ((uint32_t)fhss_structure->bs->fhss_configuration.fhss_max_synch_interval * 1000)) {
00420                     fhss_structure->bs->synch_interval = ((uint32_t)fhss_structure->bs->fhss_configuration.fhss_max_synch_interval * 1000);
00421                 }
00422                 beacon_interval_random = (bc_density * channel_dwell_time) * randLIB_get_random_in_range(0, fhss_number_of_bc_channels/2);
00423             } else {
00424                 beacon_interval_random = (bc_density * channel_dwell_time) * randLIB_get_random_in_range(0, fhss_number_of_bc_channels);
00425             }
00426             fhss_stats_update(fhss_structure, STATS_FHSS_SYNCH_INTERVAL, fhss_structure->bs->synch_interval / 1000);
00427             fhss_beacon_periodic_start(fhss_structure, fhss_structure->bs->synch_interval + beacon_interval_random);
00428         }
00429         // Our hop has changed, needs to inform possible children by sending Beacon
00430         if ((own_hop_tmp != 0) && (own_hop_tmp != fhss_structure->own_hop)) {
00431             fhss_structure->bs->send_synch_info_on_next_broadcast_channel = true;
00432         }
00433         ret_val = 0;
00434     }
00435     return ret_val;
00436 }
00437 
00438 static uint32_t fhss_get_remaining_tx_time(fhss_structure_t *fhss_structure)
00439 {
00440     /* To get the remaining TX time, following calculation is performed
00441      *
00442      *         rem. time(Y)
00443      *        |----------------|
00444      *...|    TX    |    TX    |    RX    |    RX    |...
00445      *...|   SF n   |   SF n+1 |   SF n+2 |   SF n+3 |...
00446      *
00447      * Y = remaining time of SF(n) + length of SF(n+1)
00448      *
00449      */
00450 
00451     uint32_t remaining_tx_time = 0;
00452 
00453     if (fhss_structure) {
00454         uint8_t cur_superframe = fhss_structure->bs->current_superframe;
00455         uint8_t number_of_tx_slots = fhss_structure->bs->synch_configuration.fhss_number_of_tx_slots;
00456         uint8_t number_of_superframes = fhss_structure->bs->synch_configuration.fhss_number_of_superframes;
00457         uint8_t tx_slot_length = ((number_of_superframes / 2) / number_of_tx_slots);
00458         uint8_t tx_slot_up_limit = tx_slot_length;
00459         uint16_t superframe_length = fhss_structure->bs->synch_configuration.fhss_superframe_length;
00460 
00461         if ((fhss_structure->own_hop % 2)) {
00462             tx_slot_up_limit += tx_slot_length;
00463         }
00464         while(number_of_tx_slots--)
00465         {
00466             if ((cur_superframe >= (tx_slot_up_limit - tx_slot_length)) && (cur_superframe < tx_slot_up_limit)) {
00467                 remaining_tx_time = ((uint32_t)((tx_slot_up_limit - 1) - cur_superframe) * superframe_length) + fhss_get_remaining_time_to_next_superframe(fhss_structure);
00468                 break;
00469             } else {
00470                 tx_slot_up_limit += (tx_slot_length * 2);
00471             }
00472         }
00473     }
00474     return remaining_tx_time;
00475 }
00476 
00477 // CCA adds extra 2ms with FHSS
00478 #define CCA_FHSS_PERIOD 2000
00479 // Ack frame length
00480 #define ACK_LENGTH  5
00481 
00482 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)
00483 {
00484     bool retval = false;
00485     uint32_t remaining_tx_time;
00486     uint32_t needed_tx_time;
00487     uint32_t tx_processing_delay;
00488     uint32_t ack_processing_delay;
00489 
00490     if (!fhss_structure) {
00491         return retval;
00492     }
00493 
00494     // Don't care when FHSS is unsynchronized
00495     if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00496         retval = true;
00497     } else {
00498         tx_processing_delay = fhss_structure->bs->fhss_configuration.fhss_tuning_parameters.tx_processing_delay;
00499         ack_processing_delay = fhss_structure->bs->fhss_configuration.fhss_tuning_parameters.ack_processing_delay;
00500         // Calculate needed TX time (us): CCA static period + TX processing delays + transmission time + Ack processing delays + Ack transmission time
00501         needed_tx_time = CCA_FHSS_PERIOD + tx_processing_delay + fhss_get_tx_time(fhss_structure, tx_length, phy_header_length, phy_tail_length)
00502                         + ack_processing_delay + fhss_get_tx_time(fhss_structure, ACK_LENGTH, phy_header_length, phy_tail_length);
00503         remaining_tx_time = fhss_get_remaining_tx_time(fhss_structure);
00504         if(needed_tx_time <= remaining_tx_time) {
00505             retval = true;
00506         }
00507     }
00508     return retval;
00509 }
00510 
00511 static bool fhss_is_there_common_divisor(uint16_t i, uint8_t j)
00512 {
00513     if (i < j) {
00514         uint_fast8_t t = j; j = (uint8_t) i; i = t;
00515     }
00516     for(uint_fast8_t k=2; k<=j; k++) {
00517         if (i % k == 0 && j % k == 0) {
00518             return true;
00519         }
00520     }
00521     return false;
00522 }
00523 
00524 
00525 static int fhss_generate_scramble_table(fhss_structure_t *fhss_structure)
00526 {
00527     uint8_t j = 2;
00528     // Generate indexes to extend the channel sequence. Generated indexes cannot have common divisors with value number_of_channels.
00529     for(int i=0; i<MAX_SCRAMBLE_TABLE_INDEXES;)
00530     {
00531         // Common divisors are skipped
00532         if (fhss_is_there_common_divisor(fhss_structure->number_of_channels, j) == false) {
00533             fhss_structure->bs->fhss_scramble_table[i] = j;
00534             i++;
00535         }
00536         j++;
00537     }
00538     return 0;
00539 }
00540 
00541 static fhss_beacon_info_t *fhss_get_beacon_info(fhss_structure_t *fhss_structure, uint16_t pan_id)
00542 {
00543     fhss_beacon_info_t *beacon_info;
00544     beacon_info = fhss_structure->bs->fhss_beacon_info_store;
00545     while (beacon_info) {
00546         if (beacon_info->pan_id == pan_id) {
00547             break;
00548         }
00549         beacon_info = beacon_info->next;
00550     }
00551     return beacon_info;
00552 }
00553 
00554 static void fhss_store_beacon_info(fhss_structure_t *fhss_structure, fhss_beacon_info_t *beacon_info)
00555 {
00556     fhss_beacon_info_t *beacon_info_cur;
00557     beacon_info->next = NULL;
00558     if (!fhss_structure->bs->fhss_beacon_info_store) {
00559         fhss_structure->bs->fhss_beacon_info_store = beacon_info;
00560         return;
00561     }
00562     beacon_info_cur = fhss_structure->bs->fhss_beacon_info_store;
00563     while (beacon_info_cur->next != NULL) {
00564         beacon_info_cur = beacon_info_cur->next;
00565     }
00566     beacon_info_cur->next = beacon_info;
00567 }
00568 
00569 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)
00570 {
00571     beacon_info->pan_id = pan_id;
00572     memcpy(beacon_info->source_address, source_address, 8);
00573     beacon_info->timestamp = timestamp;
00574     memcpy(beacon_info->synch_info, synch_info, sizeof(beacon_info->synch_info));
00575 }
00576 
00577 static fhss_beacon_info_t *fhss_create_beacon_info(fhss_structure_t *fhss_structure)
00578 {
00579     fhss_beacon_info_t *beacon_info = ns_dyn_mem_temporary_alloc(sizeof(fhss_beacon_info_t));
00580     if (!beacon_info) {
00581         return NULL;
00582     }
00583     fhss_store_beacon_info(fhss_structure, beacon_info);
00584     return beacon_info;
00585 }
00586 
00587 static int fhss_remove_beacon_info(fhss_structure_t *fhss_structure, uint16_t pan_id)
00588 {
00589     if (!fhss_structure || !fhss_structure->bs->fhss_beacon_info_store) {
00590         return -1;
00591     }
00592 
00593     if (fhss_structure->bs->fhss_beacon_info_store->pan_id == pan_id) {
00594         fhss_beacon_info_t *next = fhss_structure->bs->fhss_beacon_info_store->next;
00595         ns_dyn_mem_free(fhss_structure->bs->fhss_beacon_info_store);
00596         fhss_structure->bs->fhss_beacon_info_store = next;
00597         return 0;
00598     }
00599 
00600     fhss_beacon_info_t *removed_beacon_info = fhss_structure->bs->fhss_beacon_info_store->next;
00601     fhss_beacon_info_t *prev_beacon_info = fhss_structure->bs->fhss_beacon_info_store;
00602 
00603     while (removed_beacon_info) {
00604         if (removed_beacon_info->pan_id == pan_id) {
00605             fhss_beacon_info_t *next = removed_beacon_info->next;
00606             ns_dyn_mem_free(removed_beacon_info);
00607             prev_beacon_info->next = next;
00608             return 0;
00609         }
00610         prev_beacon_info = removed_beacon_info;
00611         removed_beacon_info = removed_beacon_info->next;
00612     }
00613     return -1;
00614 }
00615 
00616 static int fhss_flush_beacon_info_storage(fhss_structure_t *fhss_structure)
00617 {
00618     if (!fhss_structure) {
00619         return -1;
00620     }
00621     fhss_beacon_info_t *beacon_info = fhss_structure->bs->fhss_beacon_info_store;
00622     while (beacon_info) {
00623         fhss_beacon_info_t *next = beacon_info->next;
00624         ns_dyn_mem_free(beacon_info);
00625         beacon_info = next;
00626     }
00627     fhss_structure->bs->fhss_beacon_info_store = NULL;
00628     return 0;
00629 }
00630 
00631 static int fhss_reset(fhss_structure_t *fhss_structure)
00632 {
00633     if (!fhss_structure) {
00634         return -1;
00635     }
00636     fhss_structure->platform_functions.fhss_timer_stop(fhss_superframe_handler, fhss_structure->fhss_api);
00637     fhss_structure->bs->synch_panid = 0xffff;
00638     fhss_beacon_periodic_stop(fhss_structure);
00639     fhss_structure->bs->current_superframe = 0;
00640     fhss_structure->bs->current_channel_index = 0;
00641     fhss_structure->bs->channel_list_counter = 0;
00642     if (fhss_is_synch_root(fhss_structure) == false) {
00643         fhss_structure->own_hop = 0xff;
00644     }
00645     fhss_structure->bs->tx_allowed = false;
00646     fhss_structure->bs->synch_interval = (uint32_t) (fhss_structure->bs->fhss_configuration.fhss_max_synch_interval/BEACON_INTERVAL_INIT_DIVIDER) * 1000;
00647     fhss_structure->rx_channel = 0;
00648     fhss_structure->bs->beacons_received_timer = 0;
00649     memset(fhss_structure->synch_parent, 0xff, 8);
00650     fhss_structure->bs->send_synch_info_on_next_broadcast_channel = false;
00651     memset(&fhss_structure->bs->synch_configuration, 0, sizeof(fhss_synch_configuration_t));
00652     fhss_structure->bs->synch_infos_sent_counter = 0;
00653     fhss_structure->bs->broadcast_start_superframe = 0;
00654     fhss_failed_list_free(fhss_structure);
00655     fhss_structure->fhss_state = FHSS_UNSYNCHRONIZED;
00656     return 0;
00657 }
00658 
00659 static 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)
00660 {
00661     if (!fhss_structure || !source_address || !synch_info) {
00662         return -1;
00663     }
00664     fhss_beacon_info_t *beacon_info = fhss_get_beacon_info(fhss_structure, pan_id);
00665     if (!beacon_info) {
00666         beacon_info = fhss_create_beacon_info(fhss_structure);
00667     }
00668     if (!beacon_info) {
00669         tr_error("Beacon data not allocated");
00670         return -2;
00671     }
00672     fhss_write_beacon_info(beacon_info, pan_id, source_address, timestamp, synch_info);
00673     return 0;
00674 }
00675 
00676 static void fhss_update_beacon_info_lifetimes(fhss_structure_t *fhss_structure, uint32_t timestamp)
00677 {
00678     fhss_beacon_info_t *beacon_info;
00679     beacon_info = fhss_structure->bs->fhss_beacon_info_store;
00680     while (beacon_info) {
00681         uint32_t time_since_added = timestamp - beacon_info->timestamp;
00682         // timestamp is microseconds, lifetime is seconds
00683         if (time_since_added >= ((uint32_t)BEACON_INFO_LIFETIME * 1000000)) {
00684             if (fhss_remove_beacon_info(fhss_structure, beacon_info->pan_id) == 0) {
00685                 return;
00686             }
00687         }
00688         beacon_info = beacon_info->next;
00689     }
00690 }
00691 
00692 static void fhss_synch_state_set_callback(const fhss_api_t *api, fhss_states fhss_state, uint16_t pan_id)
00693 {
00694     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00695     if (!fhss_structure) {
00696         return;
00697     }
00698     // State is already set
00699     if (fhss_structure->fhss_state == fhss_state) {
00700         tr_debug("Synch same state %u", fhss_state);
00701         return;
00702     }
00703 
00704     if (fhss_state == FHSS_UNSYNCHRONIZED) {
00705         tr_debug("FHSS down");
00706         fhss_reset(fhss_structure);
00707         fhss_reset_synch_monitor(&fhss_structure->bs->synch_monitor);
00708         fhss_stats_update(fhss_structure, STATS_FHSS_DRIFT_COMP, fhss_structure->bs->synch_monitor.drift_compensation);
00709         fhss_stats_update(fhss_structure, STATS_FHSS_AVG_SYNCH_FIX, fhss_structure->bs->synch_monitor.avg_synch_fix);
00710         fhss_stats_update(fhss_structure, STATS_FHSS_SYNCH_INTERVAL, fhss_structure->bs->synch_interval / 1000);
00711     } else {
00712         // Do not synchronize to current pan
00713         if (fhss_structure->bs->synch_panid == pan_id) {
00714             tr_debug("Synch same panid %u", pan_id);
00715             return;
00716         }
00717         fhss_generate_scramble_table(fhss_structure);
00718 
00719         uint8_t mac_address[8];
00720         fhss_structure->callbacks.read_mac_address(fhss_structure->fhss_api, mac_address);
00721         fhss_structure->bs->uc_channel_index = fhss_get_offset(fhss_structure, mac_address);
00722         // Get Beacon info from storage
00723         fhss_beacon_info_t *beacon_info = fhss_get_beacon_info(fhss_structure, pan_id);
00724         if (beacon_info) {
00725             memcpy(fhss_structure->synch_parent, beacon_info->source_address, 8);
00726             platform_enter_critical();
00727             // Calculate time since the Beacon was received
00728             uint32_t elapsed_time = fhss_structure->fhss_api->read_timestamp(fhss_structure->fhss_api) - beacon_info->timestamp;
00729             // Synchronize to given PAN
00730             fhss_beacon_received(fhss_structure, beacon_info->synch_info, elapsed_time);
00731             platform_exit_critical();
00732             // Delete stored Beacon infos
00733             fhss_flush_beacon_info_storage(fhss_structure);
00734             fhss_structure->bs->synch_panid = pan_id;
00735         } else if (fhss_is_synch_root(fhss_structure) == true) {
00736             // Synch root will start new network
00737             fhss_start_timer(fhss_structure, fhss_structure->bs->synch_configuration.fhss_superframe_length, fhss_superframe_handler);
00738         } else {
00739             tr_error("Synch info not found");
00740             return;
00741         }
00742     }
00743     fhss_structure->fhss_state = fhss_state;
00744     return;
00745 }
00746 
00747 static void fhss_beacon_decode_raw(fhss_synchronization_beacon_payload_s* dest, const uint8_t* buffer)
00748 {
00749     dest->data_start_delimeter = *buffer++;
00750     dest->channel_index = *buffer++;
00751     dest->sender_unicast_channel = *buffer++;
00752     dest->current_superframe = common_read_16_bit(buffer);
00753     buffer += BEACON_FIELD_SIZE(current_superframe);
00754     dest->remaining_slots = common_read_16_bit(buffer);
00755     buffer += BEACON_FIELD_SIZE(remaining_slots);
00756     dest->channel_list_counter = common_read_16_bit(buffer);
00757     buffer += BEACON_FIELD_SIZE(channel_list_counter);
00758     dest->hop_count = *buffer++;
00759     dest->number_of_broadcast_channels = *buffer++;
00760     dest->number_of_tx_slots = *buffer++;
00761     dest->time_since_last_beacon = common_read_32_bit(buffer);
00762     buffer += BEACON_FIELD_SIZE(time_since_last_beacon);
00763     dest->processing_delay += common_read_16_bit(buffer);
00764     buffer += BEACON_FIELD_SIZE(processing_delay);
00765     dest->superframe_length = common_read_16_bit(buffer);
00766     buffer += BEACON_FIELD_SIZE(superframe_length);
00767     dest->number_of_superframes_per_channel = *buffer;
00768 }
00769 
00770 static uint32_t fhss_get_time_to_next_channel_change(uint16_t remaining_slots_to_next_superframe, uint8_t number_of_superframes, uint8_t current_superframe, uint16_t superframe_length)
00771 {
00772     return remaining_slots_to_next_superframe + ((uint32_t)((number_of_superframes - 1) - current_superframe) * superframe_length);
00773 }
00774 
00775 // Decode the given raw byte buffer into a struct into dest struct and calculate
00776 // the new values for elapsed_time, channel_index, current_superframe and remaining_slots
00777 // from current state and given data.
00778 static void fhss_beacon_decode(fhss_synchronization_beacon_payload_s* dest, const uint8_t* buffer, uint32_t elapsed_time, uint16_t number_of_channels)
00779 {
00780     fhss_beacon_decode_raw(dest, buffer);
00781 
00782     elapsed_time += dest->processing_delay;
00783 
00784     /* To calculate channel index after beacon scan, following calculation is performed
00785      *
00786      *                           rem. slots to channel change(X)    Channel length (V)
00787      *                              |---------------------|     |-----------------------------------------------|
00788      *    |    RX'd channel index (Y)                     | ... |                      Y+n                      |
00789      * ...|    sf1    |    sf2    |    sf3    |    sf4    | ... |    sf1    |    sf2    |    sf3    |    sf4    |...
00790      *                              ^                                     ^
00791      *                              |beacon received                      |beacon scan done
00792      *                              |-------------------------------------|
00793      *                               measured time after beacon RX'd(Z)
00794      * V = superframe length * number of superframes
00795      * X = remaining slots to superframe change + length of the remaining full superframes to channel change
00796      *
00797      * Y+n = Y + ((Z - X) / V) + 1
00798      *
00799      * Or if (Z < X)
00800      *       Y+n = Y
00801      */
00802 
00803     uint32_t remaining_slots_to_next_channel = fhss_get_time_to_next_channel_change(dest->remaining_slots, dest->number_of_superframes_per_channel, dest->current_superframe, dest->superframe_length);
00804     uint16_t temp_channel_index = dest->channel_index;
00805     if (elapsed_time >= remaining_slots_to_next_channel) {
00806         uint32_t channel_length = (uint32_t) dest->number_of_superframes_per_channel * dest->superframe_length;
00807         temp_channel_index = dest->channel_index + ((elapsed_time - remaining_slots_to_next_channel) / channel_length) + 1;
00808     }
00809     while (temp_channel_index >= number_of_channels) {
00810         temp_channel_index -= number_of_channels;
00811         dest->channel_list_counter++;
00812     }
00813     dest->channel_index = temp_channel_index;
00814     while (dest->channel_list_counter >= (number_of_channels * MAX_SCRAMBLE_TABLE_INDEXES)) {
00815         dest->channel_list_counter -= (number_of_channels * MAX_SCRAMBLE_TABLE_INDEXES);
00816     }
00817 
00818     /* To calculate superframe after beacon scan, following calculation is performed
00819      *
00820      *           rem. slots(X)         sf. length(V)
00821      *        |---------------|     |-----------------|
00822      *...| RX'd superframe (Y)| ... |      Y+n        |      Y+n+1       |....
00823      *        ^                                     ^
00824      *        |beacon received                      |beacon scan done
00825      *        |-------------------------------------|
00826      *          measured time after beacon RX'd(Z)
00827      *
00828      * Y+n = Y + ((Z - X) / V) + 1
00829      *
00830      * Or if (Z < X)
00831      *       Y+n = Y
00832      */
00833 
00834     if (elapsed_time >= dest->remaining_slots) {
00835         dest->current_superframe = dest->current_superframe + ((elapsed_time - dest->remaining_slots) / dest->superframe_length) + 1;
00836     }
00837     while (dest->current_superframe >= dest->number_of_superframes_per_channel) {
00838         dest->current_superframe -= dest->number_of_superframes_per_channel;
00839     }
00840 
00841     /* To get the remaining slots after beacon scan, following calculation is performed
00842      *
00843      *         rem. slots(Y)               sf. length(V)    new rem. slots(X)
00844      *        |----------|               |---------------| |-------------|
00845      *...| superframe 1  | superframe 2  | superframe 3  | superframe 4  |...
00846      *        ^                                            ^
00847      *        |beacon received                             |beacon scan done
00848      *        |--------------------------------------------|
00849      *          measured time after beacon RX'd(Z)
00850      *
00851      * X = V - ((Z - Y) % V)
00852      *
00853      * Or if (Z < Y)
00854      *        X = Y - Z
00855      */
00856 
00857     if (elapsed_time < dest->remaining_slots) {
00858         dest->remaining_slots = dest->remaining_slots - elapsed_time;
00859     } else {
00860         dest->remaining_slots = dest->superframe_length - ((elapsed_time - dest->remaining_slots) % dest->superframe_length);
00861     }
00862 }
00863 
00864 static int fhss_synch_info_validate(fhss_synchronization_beacon_payload_s *payload)
00865 {
00866     if (!payload) {
00867         return -1;
00868     }
00869     if (payload->data_start_delimeter != 0) {
00870         return -1;
00871     }
00872     if (payload->current_superframe >= payload->number_of_superframes_per_channel) {
00873         return -1;
00874     }
00875     if (payload->remaining_slots >= payload->superframe_length) {
00876         return -1;
00877     }
00878     if (payload->hop_count > FHSS_MAX_ALLOWED_HOPS-1) {
00879         return -1;
00880     }
00881     if (payload->number_of_broadcast_channels == 0) {
00882         return -1;
00883     }
00884     if (payload->number_of_tx_slots == 0) {
00885         return -1;
00886     }
00887     if (payload->number_of_superframes_per_channel == 0) {
00888         return -1;
00889     }
00890     return 0;
00891 }
00892 
00893 static void fhss_beacon_received(fhss_structure_t *fhss_structure, const uint8_t *synch_info, const uint32_t elapsed_time)
00894 {
00895 
00896     if (fhss_structure) {
00897 
00898         if (synch_info) {
00899             fhss_synchronization_beacon_payload_s temp_payload;
00900             temp_payload.processing_delay = fhss_structure->bs->fhss_configuration.fhss_tuning_parameters.rx_processing_delay;
00901             fhss_beacon_decode(&temp_payload, synch_info, elapsed_time, fhss_structure->number_of_channels);
00902             if (!fhss_synch_info_validate(&temp_payload)) {
00903                 fhss_sync_with_beacon(fhss_structure, &temp_payload);
00904             } else {
00905                 tr_err("Invalid synch info received");
00906             }
00907         }
00908     }
00909 }
00910 
00911 static uint32_t fhss_get_sf_timeout_callback(fhss_structure_t *fhss_structure)
00912 {
00913     uint32_t compensation = 0;
00914     /* Drift compensation doesn't work with Linux platform */
00915 #ifndef __linux__
00916     // Drift compensation on first superframe
00917     if (fhss_structure->bs->current_superframe == 0) {
00918         /* Idea is to compensate number of drift_compensation (microseconds) on each channel.
00919          * However, fhss_resolution_divider defines the minimum timer resolution.
00920          * E.g. if fhss_resolution_divider = 64, compensate (drift_compensation * 64) on each 64th channel.
00921          */
00922         if (++fhss_structure->bs->synch_monitor.channel_counter == fhss_structure->platform_functions.fhss_resolution_divider) {
00923             compensation = fhss_structure->bs->synch_monitor.drift_compensation;
00924             fhss_structure->bs->synch_monitor.channel_counter = 0;
00925         }
00926     }
00927 #else
00928     (void) fhss_structure;
00929 #endif //__linux__
00930     return (fhss_structure->bs->synch_configuration.fhss_superframe_length) + (compensation * fhss_structure->platform_functions.fhss_resolution_divider);
00931 }
00932 
00933 static void fhss_superframe_callback(fhss_structure_t *fhss_structure)
00934 {
00935     if ((fhss_structure->bs->send_synch_info_on_next_broadcast_channel == true) && (fhss_is_current_channel_broadcast(fhss_structure) == true)) {
00936         /* Randomize sending superframe of synchronization frame:
00937          * on first superframe probability is 1/number of superframes
00938          * on second superframe probability is 1/(number of superframes-1)
00939          * on third superframe probability is 1/(number of superframes-2)
00940          * on last superframe probability is 1/1
00941          */
00942         if (randLIB_get_random_in_range(1, fhss_structure->bs->synch_configuration.fhss_number_of_superframes - fhss_structure->bs->current_superframe) == 1) {
00943             fhss_structure->bs->send_synch_info_on_next_broadcast_channel = false;
00944             fhss_structure->bs->synch_infos_sent_counter++;
00945             fhss_structure->callbacks.send_fhss_frame(fhss_structure->fhss_api, FHSS_SYNCH_FRAME);
00946         }
00947     }
00948     fhss_update_txrx_slots(fhss_structure);
00949     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);
00950     if ((fhss_structure->bs->tx_allowed == true || fhss_is_current_channel_broadcast(fhss_structure) == true) && queue_size) {
00951         /* Start timer with random timeout to trigger TX queue poll event.
00952          * Max random is half of the superframe length. Event timer resolution is 50us.
00953          * Divide Max random with TX queue size to transmit faster when TX queue is growing
00954          */
00955         uint16_t max_random = ((fhss_structure->bs->synch_configuration.fhss_superframe_length / 2) / 50) / queue_size;
00956         eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(1, max_random));
00957     }
00958 }
00959 
00960 static int fhss_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_addr, uint8_t *destination_address, int frame_type, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length, uint32_t tx_time)
00961 {
00962     (void) tx_time;
00963     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00964     if (!fhss_structure) {
00965         return -2;
00966     }
00967     // TODO: needs some more logic to push buffer back to queue
00968     if (frame_type == FHSS_DATA_FRAME) {
00969         if (is_broadcast_addr == true) {
00970             if (fhss_is_current_channel_broadcast(fhss_structure) == false) {
00971                 tr_info("Broadcast on UC channel -> Back to queue");
00972                 return -3;
00973             }
00974         }
00975     }
00976     if (fhss_check_tx_allowed(fhss_structure, is_broadcast_addr, frame_length, frame_type, phy_header_length, phy_tail_length) == false) {
00977         return -1;
00978     }
00979     // If sending Beacon request on parents Unicast channel
00980     if (frame_type == FHSS_SYNCH_REQUEST_FRAME && fhss_structure->fhss_state == FHSS_SYNCHRONIZED) {
00981         fhss_change_to_parent_channel(fhss_structure);
00982     } else if (frame_type == FHSS_DATA_FRAME) {
00983         fhss_change_to_tx_channel(fhss_structure, destination_address);
00984     }
00985     return 0;
00986 }
00987 
00988 static bool fhss_check_tx_conditions_callback(const fhss_api_t *api, bool is_broadcast_addr, uint8_t handle, int frame_type, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length)
00989 {
00990     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00991     if (!fhss_structure) {
00992         return true;
00993     }
00994     // This condition will check that message is not sent on bad channel
00995     if (fhss_check_bad_channel(fhss_structure, handle) == false) {
00996         return false;
00997     }
00998 
00999     // This condition will check that broadcast messages are sent only broadcast channels
01000     if (fhss_check_channel_type(fhss_structure, is_broadcast_addr, frame_type) == false) {
01001         return false;
01002     }
01003 
01004     // This condition will check that FHSS is on TX slot and there is enough time to transmit before channel or slot change
01005     if (fhss_check_tx_allowed(fhss_structure, is_broadcast_addr, frame_length, frame_type, phy_header_length, phy_tail_length) == false) {
01006         return false;
01007     }
01008 
01009     return true;
01010 }
01011 
01012 static void fhss_update_channel_callback(fhss_structure_t *fhss_structure)
01013 {
01014     if (fhss_structure->bs->current_channel_index == 0) {
01015         fhss_structure->bs->synch_infos_sent_counter = 0;
01016         if (++fhss_structure->bs->channel_list_counter >= ((uint16_t) fhss_structure->number_of_channels * MAX_SCRAMBLE_TABLE_INDEXES)) {
01017             fhss_structure->bs->channel_list_counter = 0;
01018         }
01019         if (fhss_is_synch_root(fhss_structure) == false) {
01020             fhss_trig_event(fhss_structure, FHSS_COMPARE_SYNCH_PARENT);
01021         }
01022         fhss_trig_event(fhss_structure, FHSS_UPDATE_SYNCH_INFO_STORAGE);
01023     }
01024     // If channel is broadcast channel (true), send event
01025     if (fhss_change_to_next_channel(fhss_structure) == true) {
01026         // Only if device is border router
01027         if (fhss_structure->own_hop == 0) {
01028             fhss_trig_event(fhss_structure, FHSS_BROADCAST_CHANNEL);
01029         }
01030     }
01031 }
01032 
01033 static uint8_t* fhss_beacon_encode_raw(uint8_t* buffer, const fhss_synchronization_beacon_payload_s* source)
01034 {
01035     *buffer++ = FHSS_DATA_START_DELIMETER;
01036     *buffer++ = source->channel_index;
01037     *buffer++ = source->sender_unicast_channel;
01038     buffer = common_write_16_bit(source->current_superframe, buffer);
01039     buffer = common_write_16_bit(source->remaining_slots, buffer);
01040     buffer = common_write_16_bit(source->channel_list_counter, buffer);
01041     *buffer++ = source->hop_count;
01042     *buffer++ = source->number_of_broadcast_channels;
01043     *buffer++ = source->number_of_tx_slots;
01044     buffer = common_write_32_bit(source->time_since_last_beacon, buffer);
01045     buffer = common_write_16_bit(source->processing_delay, buffer);
01046     buffer = common_write_16_bit(source->superframe_length, buffer);
01047     *buffer++ = source->number_of_superframes_per_channel;
01048 
01049     return buffer;
01050 }
01051 
01052 static void fhss_beacon_build(fhss_structure_t *fhss_structure, uint8_t* dest)
01053 {
01054     fhss_synchronization_beacon_payload_s temp_payload;
01055     platform_enter_critical();
01056     const fhss_synch_configuration_t *config = &fhss_structure->bs->synch_configuration;
01057     temp_payload.channel_index = fhss_structure->bs->current_channel_index;
01058     temp_payload.sender_unicast_channel = 0;
01059     temp_payload.current_superframe = fhss_structure->bs->current_superframe;
01060     // This assumes that the time is always in the range of 0..2**16, which
01061     // should be the case as the superframe length field is also in that range.
01062     temp_payload.remaining_slots = (uint16_t) fhss_get_remaining_time_to_next_superframe(fhss_structure);
01063     temp_payload.channel_list_counter = fhss_structure->bs->channel_list_counter;
01064     temp_payload.hop_count = fhss_structure->own_hop;
01065     temp_payload.number_of_broadcast_channels = config->fhss_number_of_bc_channels;
01066     temp_payload.number_of_tx_slots = config->fhss_number_of_tx_slots;
01067     temp_payload.time_since_last_beacon = 0; // XXX not available yet
01068     uint32_t tx_time = fhss_get_tx_time(fhss_structure, 71, 0, 0);
01069     temp_payload.processing_delay = fhss_structure->bs->fhss_configuration.fhss_tuning_parameters.tx_processing_delay + tx_time;
01070     temp_payload.superframe_length = config->fhss_superframe_length;
01071     temp_payload.number_of_superframes_per_channel = config->fhss_number_of_superframes;
01072     platform_exit_critical();
01073     fhss_beacon_encode_raw(dest, &temp_payload);
01074 }
01075 
01076 static int16_t fhss_write_synch_info_callback(const fhss_api_t *api, uint8_t *ptr, uint8_t length, int frame_type, uint32_t tx_time)
01077 {
01078     (void) length;
01079     (void) tx_time;
01080     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
01081     if (!fhss_structure || !ptr || (frame_type != FHSS_SYNCH_FRAME)) {
01082         return -1;
01083     }
01084     fhss_beacon_build(fhss_structure, ptr);
01085     return FHSS_SYNCH_INFO_LENGTH;
01086 }
01087 
01088 static void fhss_data_tx_done_callback(const fhss_api_t *api, bool waiting_ack, bool tx_completed, uint8_t handle)
01089 {
01090     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
01091     if (!fhss_structure) {
01092         return;
01093     }
01094     if (waiting_ack == false) {
01095         fhss_change_to_rx_channel(fhss_structure);
01096     }
01097     // Buffer was successfully transmitted. Remove stored failure handle if exists.
01098     if (tx_completed == true) {
01099         fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle);
01100         if (fhss_failed_tx) {
01101             fhss_failed_handle_remove(fhss_structure, handle);
01102         }
01103     }
01104 }
01105 
01106 static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type)
01107 {
01108     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
01109     if (!fhss_structure) {
01110         return false;
01111     }
01112     // Only use channel retries when device is synchronized
01113     if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
01114         return false;
01115     }
01116     // Channel retries are disabled -> return
01117     if (fhss_structure->bs->fhss_configuration.fhss_number_of_channel_retries == 0) {
01118         return false;
01119     }
01120     // Use channel retries only for data frames
01121     if (FHSS_DATA_FRAME != frame_type) {
01122         return false;
01123     }
01124 
01125     fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle);
01126     if (fhss_failed_tx) {
01127         fhss_failed_tx->retries_done++;
01128         if (fhss_failed_tx->retries_done >= fhss_structure->bs->fhss_configuration.fhss_number_of_channel_retries) {
01129             // No more retries. Return false to stop retransmitting.
01130             fhss_failed_handle_remove(fhss_structure, handle);
01131             return false;
01132         }
01133     } else {
01134         // Create new failure handle and return true to retransmit
01135         fhss_failed_handle_add(fhss_structure, handle, fhss_structure->rx_channel);
01136     }
01137     return true;
01138 }
01139 
01140 static void fhss_receive_frame_callback(const fhss_api_t *api, uint16_t pan_id, uint8_t *source_address, uint32_t timestamp, uint8_t *synch_info, int frame_type)
01141 {
01142     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
01143     if (!fhss_structure) {
01144         return;
01145     }
01146     if (FHSS_SYNCH_FRAME == frame_type) {
01147         if ((fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) || fhss_structure->bs->synch_panid != pan_id) {
01148             fhss_add_beacon_info(fhss_structure, pan_id, source_address, timestamp, synch_info);
01149         } else {
01150             if (!fhss_compare_with_synch_parent_address(fhss_structure, source_address)) {
01151                 // Synch parent address needs to be updated in case parent has changed
01152                 fhss_update_synch_parent_address(fhss_structure);
01153                 platform_enter_critical();
01154                 // Calculate time since the Beacon was received
01155                 uint32_t elapsed_time = api->read_timestamp(api) - timestamp;
01156                 // Synchronize to given PAN
01157                 fhss_beacon_received(fhss_structure, synch_info, elapsed_time);
01158                 platform_exit_critical();
01159             }
01160         }
01161     } else if (FHSS_SYNCH_REQUEST_FRAME == frame_type) {
01162         // If current channel is broadcast, we don't need to send another synch info on next broadcast channel.
01163         // Only send number of MAX_SYNCH_INFOS_PER_CHANNEL_LIST synch infos per one channel list cycle
01164         if ((fhss_structure->fhss_state == FHSS_SYNCHRONIZED) && (fhss_is_current_channel_broadcast(fhss_structure) == false)
01165                 && (fhss_structure->bs->synch_infos_sent_counter < MAX_SYNCH_INFOS_PER_CHANNEL_LIST)) {
01166             fhss_structure->bs->send_synch_info_on_next_broadcast_channel = true;
01167         }
01168     }
01169 }
01170 
01171 static uint16_t fhss_get_retry_period_callback(const fhss_api_t *api, uint8_t *destination_address, uint16_t phy_mtu)
01172 {
01173     uint16_t retry_period = 0;
01174     uint16_t random_number = randLIB_get_16bit();
01175     uint16_t rnd_mask;
01176 
01177     /* Generate retry back-off period. FHSS is using the known synchronization parent info to delay retransmissions upstream.
01178      *
01179      */
01180     if (phy_mtu < 128) {
01181         // Max. random when PHY MTU below 128 is 6.4ms
01182         rnd_mask = 0x7f;
01183     } else if (phy_mtu < 256) {
01184         // Max. random when PHY MTU below 256 is 12.8ms
01185         rnd_mask = 0xff;
01186     } else {
01187         // Max. random when PHY MTU above 255 is 25.6ms
01188         rnd_mask = 0x1ff;
01189     }
01190 
01191     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
01192     if (fhss_structure) {
01193         uint32_t datarate = fhss_structure->callbacks.read_datarate(fhss_structure->fhss_api);
01194         uint16_t max_tx_length;
01195 
01196         if (datarate && phy_mtu) {
01197             if (fhss_compare_with_synch_parent_address(fhss_structure, destination_address) == 0) {
01198                 // E.g. (1000000 / (250000bit/s / 8 bits)) * 255 bytes = 8160us
01199                 max_tx_length = ((1000000 / (datarate / 8)) * phy_mtu);
01200                 /* Retrying upstream: delay the transmission until assumed hidden node has retried downstream:
01201                  * Static period: max random + max tx length
01202                  * 50 comes from MAC timer resolution (50us)
01203                  */
01204                 retry_period = (rnd_mask + (max_tx_length / 50));
01205             }
01206         }
01207     }
01208 
01209     // Add 1 to not to ever return zero value.
01210     retry_period += ((random_number & rnd_mask) + 1);
01211     return retry_period;
01212 }
01213 
01214 static bool fhss_is_broadcast_channel_callback(const fhss_api_t *api)
01215 {
01216     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
01217     if (!fhss_structure) {
01218         return true;
01219     }
01220     // FHSS is unsynchronized, broadcasts allowed
01221     if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
01222         return true;
01223     }
01224     return fhss_is_current_channel_broadcast(fhss_structure);
01225 }
01226 
01227 static bool fhss_use_broadcast_queue_cb(const fhss_api_t *api, bool is_broadcast_addr, int frame_type)
01228 {
01229     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
01230     if (!fhss_structure) {
01231         return false;
01232     }
01233     // Synch requests are always stored in unicast queue
01234     if (frame_type == FHSS_SYNCH_REQUEST_FRAME) {
01235         return false;
01236     }
01237     // Broadcast packets are stored in broadcast queue
01238     return is_broadcast_addr;
01239 }
01240 
01241 static void fhss_superframe_handler(const fhss_api_t *fhss_api, uint16_t delay)
01242 {
01243     uint32_t timeout = 0;
01244     fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api);
01245     if (!fhss_structure) {
01246         return;
01247     }
01248 
01249     timeout = fhss_get_sf_timeout_callback(fhss_structure);
01250 
01251     fhss_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_superframe_handler);
01252 
01253     if (fhss_structure->bs->current_superframe++ >= (fhss_structure->bs->synch_configuration.fhss_number_of_superframes - 1)) {
01254         fhss_structure->bs->current_superframe = 0;
01255         if (++fhss_structure->bs->current_channel_index >= fhss_structure->number_of_channels) {
01256             fhss_structure->bs->current_channel_index = 0;
01257         }
01258         fhss_update_channel_callback(fhss_structure);
01259     }
01260     fhss_superframe_callback(fhss_structure);
01261 
01262     if (fhss_structure->fhss_timeout) {
01263         fhss_structure->fhss_timer += fhss_structure->bs->synch_configuration.fhss_superframe_length;
01264         if (fhss_structure->fhss_timer >= fhss_structure->fhss_timeout) {
01265             fhss_trig_event(fhss_structure, FHSS_TIMER_EVENT);
01266             fhss_structure->fhss_timeout = 0;
01267             fhss_structure->fhss_timer = 0;
01268         }
01269     }
01270 }
01271 
01272 uint32_t fhss_get_remaining_time_to_next_superframe(const fhss_structure_t *fhss_structure)
01273 {
01274     const uint32_t slots = fhss_structure->platform_functions.fhss_get_remaining_slots(fhss_superframe_handler, fhss_structure->fhss_api);
01275     return (slots * fhss_structure->platform_functions.fhss_resolution_divider);
01276 }
01277 
01278 int8_t fhss_set_synch_configuration(fhss_structure_t *fhss_structure, const fhss_synch_configuration_t *fhss_synch_configuration)
01279 {
01280     if (!fhss_structure) {
01281         return -1;
01282     }
01283     if (!fhss_synch_configuration) {
01284         return -2;
01285     }
01286     // None of the configurations can be set zero
01287     if( fhss_synch_configuration->fhss_number_of_bc_channels == 0 || fhss_synch_configuration->fhss_number_of_tx_slots == 0
01288             || fhss_synch_configuration->fhss_number_of_superframes == 0 || fhss_synch_configuration->fhss_superframe_length == 0) {
01289         return -3;
01290     }
01291     // Number of channels must be divisible with the number of broadcast channels.
01292     // Number of superframes must be divisible with the number of TX slots
01293     if (((fhss_structure->number_of_channels % fhss_synch_configuration->fhss_number_of_bc_channels) != 0) ||
01294             ((fhss_synch_configuration->fhss_number_of_superframes % fhss_synch_configuration->fhss_number_of_tx_slots) != 0) ||
01295             (fhss_synch_configuration->fhss_number_of_superframes <= fhss_synch_configuration->fhss_number_of_tx_slots)) {
01296         return -4;
01297     }
01298     fhss_structure->bs->synch_configuration = *fhss_synch_configuration;
01299     fhss_structure->own_hop = 0;
01300     return 0;
01301 }
01302 
01303 uint8_t fhss_calculate_uc_index(uint8_t channel_index, uint16_t number_of_channels, uint8_t number_of_broadcast_channels)
01304 {
01305     // When channel index is 0, return last unicast index
01306     if (channel_index == 0) {
01307         return (number_of_channels - number_of_broadcast_channels - 1);
01308     }
01309     uint16_t bc_channel_density = (number_of_channels/number_of_broadcast_channels);
01310     return channel_index - (channel_index/bc_channel_density) - 1;
01311 }
01312 
01313 int fhss_set_callbacks(fhss_structure_t *fhss_structure)
01314 {
01315     // Set external API
01316     fhss_structure->fhss_api->is_broadcast_channel = &fhss_is_broadcast_channel_callback;
01317     fhss_structure->fhss_api->use_broadcast_queue = &fhss_use_broadcast_queue_cb;
01318     fhss_structure->fhss_api->tx_handle = &fhss_tx_handle_callback;
01319     fhss_structure->fhss_api->check_tx_conditions = &fhss_check_tx_conditions_callback;
01320     fhss_structure->fhss_api->receive_frame = &fhss_receive_frame_callback;
01321     fhss_structure->fhss_api->data_tx_done = &fhss_data_tx_done_callback;
01322     fhss_structure->fhss_api->data_tx_fail = &fhss_data_tx_fail_callback;
01323     fhss_structure->fhss_api->synch_state_set = &fhss_synch_state_set_callback;
01324     fhss_structure->fhss_api->read_timestamp = &fhss_read_timestamp_cb;
01325     fhss_structure->fhss_api->get_retry_period = &fhss_get_retry_period_callback;
01326     fhss_structure->fhss_api->write_synch_info = &fhss_write_synch_info_callback;
01327     fhss_structure->fhss_api->init_callbacks = &fhss_init_callbacks_cb;
01328 
01329     return 0;
01330 }
01331 
01332 static int8_t fhss_beacon_create_tasklet(fhss_structure_t *fhss_structure)
01333 {
01334     if (fhss_structure->beacon_tasklet_id < 0) {
01335         fhss_structure->beacon_tasklet_id = eventOS_event_handler_create(fhss_beacon_tasklet_func, FHSS_TASKLET_INIT_EVENT);
01336     }
01337     return fhss_structure->beacon_tasklet_id;
01338 }
01339 
01340 static int fhss_beacon_periodic_start(fhss_structure_t *fhss_structure, uint32_t time_to_first_beacon)
01341 {
01342     int ret_val = -1;
01343 
01344     if (fhss_structure) {
01345         fhss_beacon_periodic_stop(fhss_structure);
01346         ret_val = fhss_timeout_start(fhss_structure, time_to_first_beacon * 1000);
01347     }
01348     return ret_val;
01349 }
01350 
01351 static void fhss_beacon_periodic_stop(fhss_structure_t *fhss_structure)
01352 {
01353     if (fhss_structure) {
01354         fhss_timeout_stop(fhss_structure);
01355     }
01356 }
01357 
01358 static void fhss_beacon_tasklet_func(arm_event_s* event)
01359 {
01360     fhss_structure_t *fhss_structure = (fhss_structure_t *)event->data_ptr;
01361     if (!fhss_structure) {
01362         return;
01363     }
01364     uint8_t parent_address[8];
01365     fhss_clear_active_event(fhss_structure, event->event_type);
01366     // skip the init event as there will be a timer event after
01367     if (event->event_type == FHSS_TIMER_EVENT) {
01368         // Stop network when lost number of FHSS_SYNCHRONIZATION_LOST synchronization beacons from parent in a row.
01369         if (fhss_structure->bs->beacons_received_timer >= FHSS_SYNCHRONIZATION_LOST) {
01370             fhss_structure->callbacks.synch_lost_notification(fhss_structure->fhss_api);
01371             fhss_stats_update(fhss_structure, STATS_FHSS_SYNCH_LOST, 1);
01372             tr_err("FHSS synchronization lost");
01373         } else {
01374             uint16_t bc_density = (fhss_structure->number_of_channels / fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels);
01375             uint16_t channel_dwell_time = ((uint32_t)fhss_structure->bs->synch_configuration.fhss_superframe_length * fhss_structure->bs->synch_configuration.fhss_number_of_superframes) / 1000;
01376 
01377             fhss_beacon_periodic_start(fhss_structure, (bc_density * channel_dwell_time) * 2);
01378             // Send synchronization request
01379             fhss_structure->callbacks.send_fhss_frame(fhss_structure->fhss_api, FHSS_SYNCH_REQUEST_FRAME);
01380             fhss_structure->bs->beacons_received_timer++;
01381 #ifdef FEA_TRACE_SUPPORT
01382             if (!fhss_get_parent_address(fhss_structure, parent_address)) {
01383                 tr_debug("Update synch, attempt: %u, %s", fhss_structure->bs->beacons_received_timer, trace_array(parent_address, 8));
01384             } else {
01385                 tr_err("No synch parent found");
01386             }
01387 #endif /*FEA_TRACE_SUPPORT*/
01388         }
01389     }
01390     // Compare if synchronization parent has changed and request beacon if needed
01391     else if(event->event_type == FHSS_COMPARE_SYNCH_PARENT)
01392     {
01393         if (fhss_compare_with_synch_parent_address(fhss_structure, fhss_structure->synch_parent)) {
01394             fhss_structure->bs->synch_monitor.avg_synch_fix = 0;
01395             if(fhss_structure->bs->synch_monitor.avg_synch_fix_counter > 0) {
01396                 fhss_structure->bs->synch_monitor.avg_synch_fix_counter = 0;
01397             }
01398             // Send synchronization request
01399             fhss_structure->callbacks.send_fhss_frame(fhss_structure->fhss_api, FHSS_SYNCH_REQUEST_FRAME);
01400 #ifdef FEA_TRACE_SUPPORT
01401             if (!fhss_get_parent_address(fhss_structure, parent_address)) {
01402                 tr_debug("Synch parent changed, New: %s, Old: %s\n", trace_array(parent_address, 8), trace_array(fhss_structure->synch_parent, 8));
01403             } else {
01404                 tr_err("Synch parent changed : No parent found");
01405             }
01406 #endif /*FEA_TRACE_SUPPORT*/
01407         }
01408     }
01409     else if(event->event_type == FHSS_BROADCAST_CHANNEL)
01410     {
01411         uint16_t superframe_length = fhss_structure->bs->synch_configuration.fhss_superframe_length;
01412         uint8_t number_of_superframes = fhss_structure->bs->synch_configuration.fhss_number_of_superframes;
01413         // Given broadcast time is channel length minus 1 superframe
01414         fhss_structure->callbacks.broadcast_notify(fhss_structure->fhss_api, (uint32_t)superframe_length * (number_of_superframes - 1));
01415     }
01416     // Update Beacon info lifetimes
01417     else if(event->event_type == FHSS_UPDATE_SYNCH_INFO_STORAGE)
01418     {
01419         fhss_update_beacon_info_lifetimes(fhss_structure, fhss_read_timestamp_cb(fhss_structure->fhss_api));
01420     }
01421 }