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_channel.c Source File

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 }