Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fhss_mac_interface.c Source File

fhss_mac_interface.c

00001 /*
00002  * Copyright (c) 2016-2017, 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 <string.h>
00019 #include "ns_types.h"
00020 #include "fhss_api.h "
00021 #include "fhss_config.h "
00022 #include "Service_Libs/fhss/fhss.h"
00023 #include "Service_Libs/fhss/fhss_channel.h"
00024 #include "Service_Libs/fhss/fhss_beacon.h"
00025 #include "platform/arm_hal_interrupt.h"
00026 #include "randLIB.h"
00027 #include "ns_trace.h"
00028 
00029 #define TRACE_GROUP "fhss"
00030 
00031 
00032 bool fhss_is_broadcast_channel_cb(const fhss_api_t *api)
00033 {
00034     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00035     if (!fhss_structure) {
00036         return false;
00037     }
00038     // FHSS is unsynchronized, broadcasts allowed
00039     if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00040         return true;
00041     }
00042     return fhss_is_current_channel_broadcast(fhss_structure);
00043 }
00044 
00045 bool fhss_use_broadcast_queue_cb(const fhss_api_t *api, bool is_broadcast_addr, int frame_type)
00046 {
00047     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00048     if (!fhss_structure) {
00049         return false;
00050     }
00051     // Synch requests are always stored in unicast queue
00052     if (frame_type == FHSS_SYNCH_REQUEST_FRAME) {
00053         return false;
00054     }
00055     // Broadcast packets are stored in broadcast queue
00056     return is_broadcast_addr;
00057 }
00058 
00059 int fhss_tx_handle_cb(const fhss_api_t *api, bool is_broadcast_addr, uint8_t *destination_address, int frame_type, uint8_t *synch_info, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length)
00060 {
00061     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00062     if (!fhss_structure) {
00063         return -2;
00064     }
00065     // TODO: needs some more logic to push buffer back to queue
00066     if (frame_type == FHSS_DATA_FRAME) {
00067         if (is_broadcast_addr == true) {
00068             if (fhss_is_current_channel_broadcast(fhss_structure) == false) {
00069                 tr_info("Broadcast on UC channel -> Back to queue");
00070                 return -3;
00071             }
00072         }
00073     }
00074     if (frame_type == FHSS_SYNCH_FRAME) {
00075         if (!synch_info) {
00076             return -4;
00077         }
00078         fhss_beacon_build(fhss_structure, synch_info);
00079     } else if (fhss_check_tx_allowed(fhss_structure, is_broadcast_addr, frame_length, frame_type, phy_header_length, phy_tail_length) == false) {
00080         return -1;
00081     }
00082     // If sending Beacon request on parents Unicast channel
00083     if (frame_type == FHSS_SYNCH_REQUEST_FRAME && fhss_structure->fhss_state == FHSS_SYNCHRONIZED) {
00084         fhss_change_to_parent_channel(fhss_structure);
00085     } else if (frame_type == FHSS_DATA_FRAME) {
00086         fhss_change_to_tx_channel(fhss_structure, destination_address);
00087     }
00088     return 0;
00089 }
00090 
00091 bool fhss_check_tx_conditions_cb(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)
00092 {
00093     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00094     if (!fhss_structure) {
00095         return false;
00096     }
00097     // This condition will check that message is not sent on bad channel
00098     if (fhss_check_bad_channel(fhss_structure, handle) == false) {
00099         return false;
00100     }
00101 
00102     // This condition will check that broadcast messages are sent only broadcast channels
00103     if (fhss_check_channel_type(fhss_structure, is_broadcast_addr, frame_type) == false) {
00104         return false;
00105     }
00106 
00107     // This condition will check that FHSS is on TX slot and there is enough time to transmit before channel or slot change
00108     if (fhss_check_tx_allowed(fhss_structure, is_broadcast_addr, frame_length, frame_type, phy_header_length, phy_tail_length) == false) {
00109         return false;
00110     }
00111 
00112     return true;
00113 }
00114 
00115 void fhss_receive_frame_cb(const fhss_api_t *api, uint16_t pan_id, uint8_t *source_address, uint32_t timestamp, uint8_t *synch_info, int frame_type)
00116 {
00117     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00118     if (!fhss_structure) {
00119         return;
00120     }
00121     if (FHSS_SYNCH_FRAME == frame_type) {
00122         if ((fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) || fhss_structure->synch_panid != pan_id) {
00123             fhss_add_beacon_info(fhss_structure, pan_id, source_address, timestamp, synch_info);
00124         } else {
00125             if (!fhss_compare_with_synch_parent_address(fhss_structure, source_address)) {
00126                 // Synch parent address needs to be updated in case parent has changed
00127                 fhss_update_synch_parent_address(fhss_structure);
00128                 platform_enter_critical();
00129                 // Calculate time since the Beacon was received
00130                 uint32_t elapsed_time = api->read_timestamp(api) - timestamp;
00131                 // Synchronize to given PAN
00132                 fhss_beacon_received(fhss_structure, synch_info, elapsed_time);
00133                 platform_exit_critical();
00134             }
00135         }
00136     } else if (FHSS_SYNCH_REQUEST_FRAME == frame_type) {
00137         // If current channel is broadcast, we don't need to send another synch info on next broadcast channel.
00138         // Only send number of MAX_SYNCH_INFOS_PER_CHANNEL_LIST synch infos per one channel list cycle
00139         if ((fhss_structure->fhss_state == FHSS_SYNCHRONIZED) && (fhss_is_current_channel_broadcast(fhss_structure) == false)
00140                 && (fhss_structure->synch_infos_sent_counter < MAX_SYNCH_INFOS_PER_CHANNEL_LIST)) {
00141             fhss_structure->send_synch_info_on_next_broadcast_channel = true;
00142         }
00143     }
00144 }
00145 
00146 void fhss_data_tx_done_cb(const fhss_api_t *api, bool waiting_ack, bool tx_completed, uint8_t handle)
00147 {
00148     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00149     if (!fhss_structure) {
00150         return;
00151     }
00152     if (waiting_ack == false) {
00153         fhss_change_to_rx_channel(fhss_structure);
00154     }
00155     // Buffer was successfully transmitted. Remove stored failure handle if exists.
00156     if (tx_completed == true) {
00157         fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle);
00158         if (fhss_failed_tx) {
00159             fhss_failed_handle_remove(fhss_structure, handle);
00160         }
00161     }
00162 }
00163 
00164 bool fhss_data_tx_fail_cb(const fhss_api_t *api, uint8_t handle, int frame_type)
00165 {
00166     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00167     if (!fhss_structure) {
00168         return false;
00169     }
00170     // Only use channel retries when device is synchronized
00171     if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
00172         return false;
00173     }
00174     // Channel retries are disabled -> return
00175     if (fhss_structure->fhss_configuration.fhss_number_of_channel_retries == 0) {
00176         return false;
00177     }
00178     // Use channel retries only for data frames
00179     if (FHSS_DATA_FRAME != frame_type) {
00180         return false;
00181     }
00182 
00183     fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle);
00184     if (fhss_failed_tx) {
00185         fhss_failed_tx->retries_done++;
00186         if (fhss_failed_tx->retries_done >= fhss_structure->fhss_configuration.fhss_number_of_channel_retries) {
00187             // No more retries. Return false to stop retransmitting.
00188             fhss_failed_handle_remove(fhss_structure, handle);
00189             return false;
00190         }
00191     } else {
00192         // Create new failure handle and return true to retransmit
00193         fhss_failed_handle_add(fhss_structure, handle);
00194     }
00195     return true;
00196 }
00197 
00198 void fhss_synch_state_set_cb(const fhss_api_t *api, fhss_states fhss_state, uint16_t pan_id)
00199 {
00200     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00201     if (!fhss_structure) {
00202         return;
00203     }
00204 
00205     // State is already set
00206     if (fhss_structure->fhss_state == fhss_state) {
00207         tr_debug("Synch same state %u", fhss_state);
00208         return;
00209     }
00210 
00211     if (fhss_state == FHSS_UNSYNCHRONIZED) {
00212         tr_debug("FHSS down");
00213         fhss_down(fhss_structure);
00214     } else {
00215         // Do not synchronize to current pan
00216         if (fhss_structure->synch_panid == pan_id) {
00217             tr_debug("Synch same panid %u", pan_id);
00218             return;
00219         }
00220         uint32_t datarate = fhss_structure->callbacks.read_datarate(api);
00221         fhss_set_datarate(fhss_structure, datarate);
00222         uint8_t mac_address[8];
00223         fhss_structure->callbacks.read_mac_address(fhss_structure->fhss_api, mac_address);
00224         fhss_structure->uc_channel_index = fhss_get_offset(fhss_structure, mac_address);
00225         // Get Beacon info from storage
00226         fhss_beacon_info_t *beacon_info = fhss_get_beacon_info(fhss_structure, pan_id);
00227         if (beacon_info) {
00228             memcpy(fhss_structure->synch_parent, beacon_info->source_address, 8);
00229             platform_enter_critical();
00230             // Calculate time since the Beacon was received
00231             uint32_t elapsed_time = api->read_timestamp(api) - beacon_info->timestamp;
00232             // Synchronize to given PAN
00233             fhss_beacon_received(fhss_structure, beacon_info->synch_info, elapsed_time);
00234             platform_exit_critical();
00235             // Delete stored Beacon infos
00236             fhss_flush_beacon_info_storage(fhss_structure);
00237             fhss_structure->synch_panid = pan_id;
00238         } else if (fhss_is_synch_root(fhss_structure) == true) {
00239             // Synch root will start new network
00240             fhss_start_timer(fhss_structure, fhss_structure->synch_configuration.fhss_superframe_length, fhss_superframe_handler);
00241         } else {
00242             tr_error("Synch info not find");
00243         }
00244     }
00245     fhss_structure->fhss_state = fhss_state;
00246 }
00247 
00248 uint32_t fhss_read_timestamp_cb(const fhss_api_t *api)
00249 {
00250     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00251     if (!fhss_structure) {
00252         return 0;
00253     }
00254     return (fhss_structure->platform_functions.fhss_get_timestamp(api) * fhss_structure->platform_functions.fhss_resolution_divider);
00255 }
00256 
00257 uint16_t fhss_get_retry_period_cb(const fhss_api_t *api, uint8_t *destination_address, uint16_t phy_mtu)
00258 {
00259     uint16_t retry_period = 0;
00260     uint16_t random_number = randLIB_get_16bit();
00261     uint16_t rnd_mask;
00262 
00263     /* Generate retry back-off period. FHSS is using the known synchronization parent info to delay retransmissions upstream.
00264      *
00265      */
00266     if (phy_mtu < 128) {
00267         // Max. random when PHY MTU below 128 is 6.4ms
00268         rnd_mask = 0x7f;
00269     } else if (phy_mtu < 256) {
00270         // Max. random when PHY MTU below 256 is 12.8ms
00271         rnd_mask = 0xff;
00272     } else {
00273         // Max. random when PHY MTU above 255 is 25.6ms
00274         rnd_mask = 0x1ff;
00275     }
00276 
00277     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00278     if (fhss_structure) {
00279         uint32_t datarate = fhss_structure->datarate;
00280         uint16_t max_tx_length;
00281 
00282         if (datarate && phy_mtu) {
00283             if (fhss_compare_with_synch_parent_address(fhss_structure, destination_address) == 0) {
00284                 // E.g. (1000000 / (250000bit/s / 8 bits)) * 255 bytes = 8160us
00285                 max_tx_length = ((1000000 / (datarate / 8)) * phy_mtu);
00286                 /* Retrying upstream: delay the transmission until assumed hidden node has retried downstream:
00287                  * Static period: max random + max tx length
00288                  * 50 comes from MAC timer resolution (50us)
00289                  */
00290                 retry_period = (rnd_mask + (max_tx_length / 50));
00291             }
00292         }
00293     }
00294 
00295     // Add 1 to not to ever return zero value.
00296     retry_period += ((random_number & rnd_mask) + 1);
00297     return retry_period;
00298 }
00299 
00300 int fhss_init_callbacks_cb(const fhss_api_t *api, fhss_callback_t *callbacks)
00301 {
00302     fhss_structure_t *fhss_structure = fhss_get_object_with_api(api);
00303     if (!fhss_structure || !callbacks) {
00304         return -1;
00305     }
00306     fhss_structure->callbacks = *callbacks;
00307     return 0;
00308 }