Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51_Vdd TextLCD BME280
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 }
Generated on Tue Jul 12 2022 15:15:44 by
