Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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