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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
fhss_channel.c
00001 /* 00002 * Copyright (c) 2016-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 "randLIB.h" 00026 #include "ns_trace.h" 00027 00028 #define TRACE_GROUP "fhss" 00029 00030 #ifdef FHSS_CHANNEL_DEBUG_CBS 00031 void (*fhss_uc_switch)(void) = NULL; 00032 void (*fhss_bc_switch)(void) = NULL; 00033 #endif /*FHSS_CHANNEL_DEBUG_CBS*/ 00034 00035 #ifdef FHSS_CHANNEL_DEBUG 00036 uint8_t debug_destination_channel = 0; 00037 #endif /*FHSS_CHANNEL_DEBUG*/ 00038 00039 static uint8_t fhss_get_bc_index(const fhss_structure_t *fhss_structure); 00040 00041 uint8_t fhss_calc_channel_shuffle(uint8_t index, uint16_t number_of_channels, uint8_t number_of_broadcast_channels) 00042 { 00043 /* To break the ...1, 2, 3, 4,... hopping sequence and to spread broadcast channels equally on frequency band. 00044 * 00045 * Also to randomise the sequence, for Unicast channels: 00046 * - Even indexes are divided by 2 00047 * - Odd indexes are divided by 2 and result is subtracted from highest Unicast index (which is (number_of_channels-number_of_broadcast_channels) - 1) 00048 * 00049 * 00050 * Example: 00051 * Hopping sequence: Without Unicast randomising: With Unicast randomising: 00052 * 0, 1, 2, 3, 0, 4, 8, 12, 0, 14, 4, 10, 00053 * 4, 5, 6, 7, 1, 5, 9, 13, 8, 6, 12, 2, 00054 * 8, 9, 10, 11, 2, 6, 10, 14, 1, 13, 5, 9, 00055 * 12, 13, 14, 15 3, 7, 11, 15, 3, 7, 11, 15, 00056 * 00057 * If number of broadcast channels is 4 (last 4 indexes 3, 7, 11, 15), the hopping sequence is: 3, 0, 14, 4, 7, 10, 8, 6, 11, 12, 2, 1, 15, 13, 5, 9 00058 */ 00059 #ifndef DISABLE_CHANNEL_SHUFFLE 00060 // Unicast randomising 00061 if (index < (number_of_channels - number_of_broadcast_channels)) { 00062 if (!(index % 2)) { 00063 index /= 2; 00064 } else { 00065 index = ((number_of_channels - number_of_broadcast_channels) - 1) - (index / 2); 00066 } 00067 } 00068 // Spread Broadcast channels 00069 index = (index % number_of_broadcast_channels) * (number_of_channels / number_of_broadcast_channels) + (index / number_of_broadcast_channels); 00070 #endif /*DISABLE_CHANNEL_SHUFFLE*/ 00071 return index; 00072 } 00073 00074 uint8_t fhss_add_channel_list_counter(uint8_t index, uint16_t number_of_channels, uint16_t channel_list_counter, uint8_t *scramble_table) 00075 { 00076 /* To avoid repeating same channel list constantly, channel list counter is added to given index*/ 00077 #ifndef DISABLE_CHANNEL_COUNTER 00078 00079 /* Break repeating cycle when channel list counter reaches the number of channels. 00080 * Using known channel list counter and generated scramble table, create pseudo-random index that changes the repeated cycle longer. 00081 * All channels are equally used as broadcast and unicast channels 00082 * 00083 * If number of channels is 50, number of scramble table indexes is 10 and channel dwell time is 400ms, the repeated cycle starts from beginning after 50 * 50 * 10 * 400ms = 166min 00084 */ 00085 uint32_t index_tmp; 00086 uint8_t calc_tmp = (channel_list_counter / number_of_channels) % MAX_SCRAMBLE_TABLE_INDEXES; 00087 index_tmp = (uint32_t) channel_list_counter * scramble_table[calc_tmp]; 00088 00089 index_tmp += index; 00090 index_tmp %= number_of_channels; 00091 index = index_tmp; 00092 #endif /*DISABLE_CHANNEL_COUNTER*/ 00093 return index; 00094 } 00095 00096 static void fhss_generate_broadcast_start_superframe(fhss_structure_t *fhss_structure) 00097 { 00098 // If the number of superframes is low, allow broadcast on any superframe 00099 if (fhss_structure->bs->synch_configuration.fhss_number_of_superframes < 8) { 00100 fhss_structure->bs->broadcast_start_superframe = 0; 00101 } else { 00102 fhss_structure->bs->broadcast_start_superframe = randLIB_get_random_in_range(0, NUMBER_OF_BC_START_SUPERFRAMES - 1); 00103 } 00104 } 00105 00106 /** 00107 * Update channel 00108 * 00109 * This function is called by superframe handler on first(0) superframe 00110 * of every channel to resolve and change new channel. 00111 * 00112 * @param cur network interface to work on 00113 * @return true if changed to broadcast channel, false otherwise 00114 */ 00115 bool fhss_change_to_next_channel(fhss_structure_t *fhss_structure) 00116 { 00117 int next_channel; 00118 bool broadcast_channel = false; 00119 00120 uint16_t number_of_channels = fhss_structure->number_of_channels; 00121 uint8_t number_of_broadcast_channels = fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels; 00122 uint8_t unicast_channel_index = fhss_structure->bs->uc_channel_index; 00123 uint8_t channel_index_tmp; 00124 00125 /* Get the channel number using channel index. Latter (number_of_broadcast_channels) indexes in channel table are broadcast channels and 00126 * first (number_of_channels - number_of_broadcast_channels) are unicast channels. 00127 * In channel hopping sequence, every (number_of_channels / number_of_broadcast_channels) channel is broadcast channel and 00128 * channel hopping sequence is e.g. |uc0|uc1|uc2|bc0|uc3|uc4|uc5|bc1|uc6|... 00129 */ 00130 /* Get broadcast channel */ 00131 if (fhss_is_current_channel_broadcast(fhss_structure) == true) { 00132 channel_index_tmp = fhss_calc_channel_shuffle((number_of_channels - number_of_broadcast_channels) + fhss_get_bc_index(fhss_structure), fhss_structure->number_of_channels, fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels); 00133 fhss_generate_broadcast_start_superframe(fhss_structure); 00134 broadcast_channel = true; 00135 } else { /* Get unicast channel */ 00136 channel_index_tmp = fhss_calc_channel_shuffle(unicast_channel_index, fhss_structure->number_of_channels, fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels); 00137 if (++fhss_structure->bs->uc_channel_index >= number_of_channels - number_of_broadcast_channels) { 00138 fhss_structure->bs->uc_channel_index = 0; 00139 } 00140 } 00141 // Reset Beacon received flag when channel has changed 00142 fhss_structure->bs->beacon_received_on_this_bc_channel = false; 00143 channel_index_tmp = fhss_add_channel_list_counter(channel_index_tmp, fhss_structure->number_of_channels, fhss_structure->bs->channel_list_counter, fhss_structure->bs->fhss_scramble_table); 00144 next_channel = channel_list_get_channel(fhss_structure->bs->fhss_configuration.channel_mask, channel_index_tmp); 00145 00146 fhss_structure->rx_channel = next_channel; 00147 00148 if (fhss_is_current_channel_broadcast(fhss_structure) == true) { 00149 #ifdef FHSS_CHANNEL_DEBUG 00150 tr_info("%"PRIu32" BC %u", fhss_structure->platform_functions.fhss_get_timestamp(fhss_structure->fhss_api), next_channel); 00151 #endif /*FHSS_CHANNEL_DEBUG*/ 00152 } else { 00153 #ifdef FHSS_CHANNEL_DEBUG_CBS 00154 if (fhss_uc_switch) { 00155 fhss_uc_switch(); 00156 } 00157 #endif /*FHSS_CHANNEL_DEBUG_CBS*/ 00158 #ifdef FHSS_CHANNEL_DEBUG 00159 tr_info("%"PRIu32" UC %u", fhss_structure->platform_functions.fhss_get_timestamp(fhss_structure->fhss_api), next_channel); 00160 #endif /*FHSS_CHANNEL_DEBUG*/ 00161 } 00162 00163 fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel); 00164 return broadcast_channel; 00165 } 00166 00167 static uint8_t fhss_get_bc_index(const fhss_structure_t *fhss_structure) 00168 { 00169 uint16_t number_of_channels = fhss_structure->number_of_channels; 00170 uint8_t number_of_bc_channels = fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels; 00171 uint8_t cur_channel_index = fhss_structure->bs->current_channel_index; 00172 00173 return cur_channel_index / (number_of_channels / number_of_bc_channels); 00174 } 00175 00176 uint8_t fhss_get_offset(fhss_structure_t *fhss_structure, const uint8_t *ptr) 00177 { 00178 uint8_t i; 00179 uint8_t index = *ptr++; 00180 00181 if (fhss_structure->number_of_channels == fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels) { 00182 // If all channels are defined as broadcast channels then return 0 to avoid division by 0. 00183 // This could happen e.g. in OTA case when fast download is needed. 00184 return 0; 00185 } 00186 00187 // Offset to unicast channel index is calculated using XOR operation 00188 for (i = 0; i < 7; i++) { 00189 index ^= *ptr++; 00190 } 00191 // Offset must be < number of unicast channels 00192 index %= (fhss_structure->number_of_channels - fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels); 00193 00194 return index; 00195 } 00196 00197 bool fhss_is_current_channel_broadcast(fhss_structure_t *fhss_structure) 00198 { 00199 // Every channel is broadcast channel when FHSS is not enabled 00200 if (!fhss_structure) { 00201 return true; 00202 } 00203 00204 // Should always have broadcast channels with FHSS 00205 if (!fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels) { 00206 return true; 00207 } 00208 00209 uint8_t channel_index = fhss_structure->bs->current_channel_index; 00210 uint16_t number_of_channels = fhss_structure->number_of_channels; 00211 uint8_t number_of_broadcast_channels = fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels; 00212 00213 if (!(channel_index % (number_of_channels / number_of_broadcast_channels))) { 00214 return true; 00215 } 00216 return false; 00217 } 00218 00219 static uint8_t fhss_get_destination_channel(fhss_structure_t *fhss_structure, uint8_t *destination_address) 00220 { 00221 uint8_t destination_offset; 00222 uint8_t uc_index; 00223 00224 if (fhss_structure) { 00225 if (fhss_is_current_channel_broadcast(fhss_structure) == false) { 00226 destination_offset = fhss_get_offset(fhss_structure, destination_address); 00227 uc_index = fhss_calculate_uc_index(fhss_structure->bs->current_channel_index, fhss_structure->number_of_channels, 00228 fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels) + destination_offset; 00229 if (uc_index >= (fhss_structure->number_of_channels - fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels)) { 00230 uc_index -= (fhss_structure->number_of_channels - fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels); 00231 } 00232 00233 uc_index = fhss_calc_channel_shuffle(uc_index, fhss_structure->number_of_channels, fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels); 00234 uc_index = fhss_add_channel_list_counter(uc_index, fhss_structure->number_of_channels, fhss_structure->bs->channel_list_counter, fhss_structure->bs->fhss_scramble_table); 00235 return channel_list_get_channel(fhss_structure->bs->fhss_configuration.channel_mask, uc_index); 00236 } 00237 return fhss_structure->rx_channel; 00238 } 00239 return 0; 00240 } 00241 00242 int fhss_change_to_tx_channel(fhss_structure_t *fhss_structure, uint8_t *destination_address) 00243 { 00244 if (fhss_structure) { 00245 if (fhss_structure->fhss_state != FHSS_UNSYNCHRONIZED) { 00246 uint8_t destination_channel = fhss_get_destination_channel(fhss_structure, destination_address); 00247 fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, destination_channel); 00248 #ifdef FHSS_CHANNEL_DEBUG 00249 debug_destination_channel = destination_channel; 00250 #endif /*FHSS_CHANNEL_DEBUG*/ 00251 } 00252 } 00253 return 0; 00254 } 00255 00256 int fhss_change_to_parent_channel(fhss_structure_t *fhss_structure) 00257 { 00258 uint8_t uc_index; 00259 uint8_t destination_channel; 00260 uint8_t destination_offset; 00261 if (fhss_structure) { 00262 if (fhss_structure->number_of_channels != fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels) { 00263 uint8_t parent_address[8]; 00264 if (fhss_get_parent_address(fhss_structure, parent_address)) { 00265 return -1; 00266 } 00267 00268 destination_offset = fhss_get_offset(fhss_structure, parent_address); 00269 00270 uc_index = fhss_calculate_uc_index(fhss_structure->bs->current_channel_index, fhss_structure->number_of_channels, 00271 fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels) + destination_offset; 00272 if (uc_index >= (fhss_structure->number_of_channels - fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels)) { 00273 uc_index -= (fhss_structure->number_of_channels - fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels); 00274 } 00275 uc_index = fhss_calc_channel_shuffle(uc_index, fhss_structure->number_of_channels, fhss_structure->bs->synch_configuration.fhss_number_of_bc_channels); 00276 uc_index = fhss_add_channel_list_counter(uc_index, fhss_structure->number_of_channels, fhss_structure->bs->channel_list_counter, fhss_structure->bs->fhss_scramble_table); 00277 destination_channel = channel_list_get_channel(fhss_structure->bs->fhss_configuration.channel_mask, uc_index); 00278 fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, destination_channel); 00279 #ifdef FHSS_CHANNEL_DEBUG 00280 tr_info("Parent channel: %u", destination_channel); 00281 #endif /*FHSS_CHANNEL_DEBUG*/ 00282 } 00283 } 00284 return 0; 00285 } 00286 00287 int fhss_change_to_rx_channel(fhss_structure_t *fhss_structure) 00288 { 00289 if (fhss_structure) { 00290 if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED) { 00291 fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, fhss_structure->rx_channel); 00292 } 00293 return 0; 00294 } 00295 return -1; 00296 }
Generated on Tue Jul 12 2022 13:54:21 by
