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
etx.c
00001 /* 00002 * Copyright (c) 2014-2019, 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 "common_functions.h" 00020 #include "ns_trace.h" 00021 #include "string.h" 00022 #include "nsdynmemLIB.h" 00023 #include "platform/arm_hal_phy.h" 00024 #include "net_interface.h" 00025 00026 #include "Core/include/ns_address_internal.h" 00027 #include "MLE/mle.h" 00028 #include "NWK_INTERFACE/Include/protocol_abstract.h" 00029 #include "NWK_INTERFACE/Include/protocol.h" 00030 #include "NWK_INTERFACE/Include/protocol_stats.h" 00031 #include "Service_Libs/etx/etx.h" 00032 #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" 00033 #include "Service_Libs/utils/isqrt.h" 00034 00035 //TODO: Refactor this away! 00036 #include "MAC/rf_driver_storage.h" 00037 00038 #define TRACE_GROUP "etx" 00039 00040 static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures); 00041 static uint16_t etx_dbm_lqi_calc(uint8_t lqi, int8_t dbm); 00042 static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index); 00043 static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8_t attribute_index); 00044 static void etx_cache_entry_init(uint8_t attribute_index); 00045 00046 #if ETX_ACCELERATED_SAMPLE_COUNT == 0 || ETX_ACCELERATED_SAMPLE_COUNT > 6 00047 #error "ETX_ACCELERATED_SAMPLE_COUNT accepted values 1-6" 00048 #endif 00049 00050 #if ETX_ACCELERATED_INTERVAL == 0 00051 #error "ETX_ACCELERATED_INTERVAL can't be zero" 00052 #endif 00053 00054 #if ETX_ACCELERATED_INTERVAL >= ETX_ACCELERATED_SAMPLE_COUNT 00055 #error "ETX_ACCELERATED_INTERVAL must be < ETX_ACCELERATED_SAMPLE_COUNT" 00056 #endif 00057 00058 00059 typedef struct { 00060 etx_value_change_handler_t *callback_ptr; 00061 etx_accum_failures_handler_t *accum_cb_ptr; 00062 etx_storage_t *etx_storage_list; 00063 etx_sample_storage_t *etx_cache_storage_list; 00064 uint32_t max_etx_update; 00065 uint16_t hysteresis; // 12 bit fraction 00066 uint8_t accum_threshold; 00067 uint8_t etx_min_sampling_time; 00068 uint8_t ext_storage_list_size; 00069 uint8_t min_sample_count; 00070 bool cache_sample_requested; 00071 int8_t interface_id; 00072 } ext_info_t; 00073 00074 static ext_info_t etx_info = { 00075 .hysteresis = 0, 00076 .accum_threshold = 0, 00077 .callback_ptr = NULL, 00078 .accum_cb_ptr = NULL, 00079 .etx_storage_list = NULL, 00080 .etx_cache_storage_list = NULL, 00081 .ext_storage_list_size = 0, 00082 .min_sample_count = 0, 00083 .max_etx_update = 0, 00084 .cache_sample_requested = false, 00085 .etx_min_sampling_time = 0, 00086 .interface_id = -1 00087 }; 00088 00089 static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, uint8_t attribute_index) 00090 { 00091 if (etx_info.hysteresis && !entry->stored_diff_etx) { 00092 entry->stored_diff_etx = entry->etx; 00093 } 00094 00095 uint32_t etx = attempts << (12 - ETX_MOVING_AVERAGE_FRACTION); 00096 00097 if (acks_rx) { 00098 etx /= acks_rx; 00099 } else { 00100 etx = 0xffff; 00101 } 00102 if ((etx_info.max_etx_update) && etx > etx_info.max_etx_update) { 00103 etx = etx_info.max_etx_update; 00104 } 00105 00106 if (etx_info.cache_sample_requested && entry->etx_samples == 1) { 00107 // skip the initial value as RSSI generated ETX is not valid 00108 etx = etx << 3; 00109 } else { 00110 //Add old etx 7/8 to new one 00111 etx += entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION); 00112 } 00113 00114 if (etx > 0xffff) { 00115 etx = 0xffff; 00116 } 00117 00118 // If real ETX value has been received do not update based on LQI or dBm 00119 entry->tmp_etx = false; 00120 entry->etx = etx; 00121 00122 etx_cache_entry_init(attribute_index); 00123 00124 // Checks if ETX value change callback is needed 00125 etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); 00126 } 00127 00128 static void etx_cache_entry_init(uint8_t attribute_index) 00129 { 00130 if (!etx_info.cache_sample_requested) { 00131 return; 00132 } 00133 00134 etx_sample_storage_t *storage = etx_info.etx_cache_storage_list + attribute_index; 00135 storage->attempts_count = 0; 00136 storage->etx_timer = etx_info.etx_min_sampling_time; 00137 storage->received_acks = 0; 00138 storage->sample_count = 0; 00139 } 00140 00141 static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *entry, uint16_t time_update) 00142 { 00143 if (storage->etx_timer && time_update) { 00144 if (time_update >= storage->etx_timer) { 00145 storage->etx_timer = 0; 00146 } else { 00147 storage->etx_timer -= time_update; 00148 } 00149 } 00150 00151 if (entry->etx_samples > ETX_ACCELERATED_SAMPLE_COUNT) { 00152 //Slower ETX update phase 00153 if (storage->sample_count < etx_info.min_sample_count || storage->etx_timer) { 00154 if (storage->sample_count < 0xff) { 00155 return false; 00156 } 00157 } 00158 } else { 00159 //Accelerated ETX at for new neighbor 00160 if (storage->sample_count < ETX_ACCELERATED_INTERVAL) { 00161 return false; 00162 } 00163 } 00164 00165 //tr_debug("ETX update possible %u attempts, %u rx ack", storage->attempts_count, storage->received_acks); 00166 00167 return true; 00168 00169 } 00170 00171 00172 static etx_sample_storage_t *etx_cache_sample_update(uint8_t attribute_index, uint8_t attempts, bool ack_rx) 00173 { 00174 etx_sample_storage_t *storage = etx_info.etx_cache_storage_list + attribute_index; 00175 storage->attempts_count += attempts; 00176 if (ack_rx) { 00177 storage->received_acks++; 00178 } 00179 storage->sample_count++; 00180 return storage; 00181 00182 } 00183 00184 00185 00186 /** 00187 * \brief A function to update ETX value based on transmission attempts 00188 * 00189 * Update is made based on failed and successful message sending 00190 * attempts for a message. 00191 * 00192 * \param attempts number of attempts to send message 00193 * \param success was message sending successful 00194 * \param addr_type address type, ADDR_802_15_4_SHORT or ADDR_802_15_4_LONG 00195 * \param addr_ptr PAN ID with 802.15.4 address 00196 */ 00197 void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index) 00198 { 00199 uint8_t accumulated_failures; 00200 // Gets table entry 00201 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00202 if (!entry) { 00203 return; 00204 } 00205 if (entry->etx_samples < 7) { 00206 entry->etx_samples++; 00207 } 00208 00209 if (etx_info.cache_sample_requested) { 00210 00211 etx_sample_storage_t *storage = etx_cache_sample_update(attribute_index, attempts, success); 00212 entry->accumulated_failures = 0; 00213 00214 if (!entry->etx || (entry->etx_samples > 1 && !etx_update_possible(storage, entry, 0))) { 00215 return; 00216 } 00217 00218 etx_calculation(entry, storage->attempts_count, storage->received_acks, attribute_index); 00219 return; 00220 } 00221 00222 accumulated_failures = entry->accumulated_failures; 00223 00224 if (!success) { 00225 /* Stores failed attempts to estimate ETX and to calculate 00226 new ETX after successful sending */ 00227 if (accumulated_failures + attempts < 32) { 00228 entry->accumulated_failures += attempts; 00229 } else { 00230 success = true; 00231 } 00232 } 00233 00234 if (success) { 00235 entry->accumulated_failures = 0; 00236 } else { 00237 etx_accum_failures_callback_needed_check(entry, attribute_index); 00238 } 00239 00240 if (entry->etx) { 00241 00242 if (success) { 00243 etx_calculation(entry, attempts + accumulated_failures, 1, attribute_index); 00244 } 00245 } 00246 } 00247 00248 /** 00249 * \brief A function to update ETX value based on remote incoming IDR 00250 * 00251 * Update is made based on remote incoming IDR received from 00252 * neighbor. 00253 * 00254 * \param remote_incoming_idr Remote incoming IDR 00255 * \param mac64_addr_ptr long MAC address 00256 */ 00257 void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index) 00258 { 00259 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00260 00261 if (entry) { 00262 // If ETX has been set 00263 if (entry->etx) { 00264 // If hysteresis is set stores ETX value to enable comparison 00265 if (etx_info.hysteresis && !entry->stored_diff_etx) { 00266 entry->stored_diff_etx = entry->etx; 00267 } 00268 // remote EXT = remote incoming IDR^2 (12 bit fraction) 00269 uint32_t remote_ext = ((uint32_t)remote_incoming_idr * remote_incoming_idr) << 2; 00270 00271 // ETX = 7/8 * current ETX + 1/8 * remote ETX */ 00272 uint32_t etx = entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION); 00273 etx += remote_ext >> ETX_MOVING_AVERAGE_FRACTION; 00274 00275 if (etx > 0xffff) { 00276 entry->etx = 0xffff; 00277 } else { 00278 entry->etx = etx; 00279 } 00280 00281 // Checks if ETX value change callback is needed 00282 etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); 00283 } 00284 entry->remote_incoming_idr = remote_incoming_idr; 00285 } 00286 } 00287 00288 /** 00289 * \brief A function to read ETX value 00290 * 00291 * Returns ETX value for an address 00292 * 00293 * \param interface_id network interface id 00294 * \param addr_type address type, ADDR_802_15_4_SHORT or ADDR_802_15_4_LONG 00295 * \param addr_ptr PAN ID with 802.15.4 address 00296 * 00297 * \return 0x0100 to 0xFFFF ETX value (8 bit fraction) 00298 * \return 0xFFFF address not associated 00299 * \return 0x0000 address unknown or other error 00300 * \return 0x0001 no ETX statistics on this interface 00301 */ 00302 uint16_t etx_read(int8_t interface_id, addrtype_t addr_type, const uint8_t *addr_ptr) 00303 { 00304 protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(interface_id); 00305 00306 if (!addr_ptr || !interface) { 00307 return 0; 00308 } 00309 00310 if (interface->etx_read_override) { 00311 // Interface has modified ETX calculation 00312 return interface->etx_read_override(interface, addr_type, addr_ptr); 00313 } 00314 00315 uint8_t attribute_index; 00316 if (interface->nwk_id == IF_IPV6) { 00317 return 1; 00318 } 00319 00320 //Must Support old MLE table and new still same time 00321 mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), addr_ptr + PAN_ID_LEN, addr_type); 00322 if (!mac_neighbor) { 00323 return 0xffff; 00324 } 00325 attribute_index = mac_neighbor->index ; 00326 00327 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00328 00329 if (!entry) { 00330 return 0xffff; 00331 } 00332 00333 uint16_t etx = etx_current_calc(entry->etx, entry->accumulated_failures); 00334 etx >>= 4; 00335 00336 return etx; 00337 } 00338 00339 /** 00340 * \brief A function to read local incoming IDR value 00341 * 00342 * Returns local incoming IDR value for an address 00343 * 00344 * \param mac64_addr_ptr long MAC address 00345 * 00346 * \return 0x0100 to 0xFFFF incoming IDR value (8 bit fraction) 00347 * \return 0x0000 address unknown 00348 */ 00349 uint16_t etx_local_incoming_idr_read(int8_t interface_id, uint8_t attribute_index) 00350 { 00351 uint32_t local_incoming_idr = 0; 00352 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00353 if (entry) { 00354 uint16_t local_etx = etx_current_calc(entry->etx, entry->accumulated_failures); 00355 00356 local_incoming_idr = isqrt32((uint32_t)local_etx << 16); 00357 // divide by sqrt(2^12) 00358 local_incoming_idr = local_incoming_idr >> 6; 00359 } 00360 00361 return local_incoming_idr; 00362 } 00363 00364 /** 00365 * \brief A function to read local incoming IDR value 00366 * 00367 * Returns local incoming IDR value for an address 00368 * 00369 * \param mac64_addr_ptr long MAC address 00370 * 00371 * \return 0x0100 to 0xFFFF incoming IDR value (8 bit fraction) 00372 * \return 0x0000 address unknown 00373 */ 00374 uint16_t etx_local_etx_read(int8_t interface_id, uint8_t attribute_index) 00375 { 00376 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00377 if (!entry) { 00378 return 0; 00379 } 00380 return etx_current_calc(entry->etx, entry->accumulated_failures) >> 4; 00381 } 00382 00383 /** 00384 * \brief A function to calculate current ETX 00385 * 00386 * Returns current ETX value based on ETX and failed attempts. Return 00387 * value is scaled by scaling factor 00388 * 00389 * \param etx ETX (12 bit fraction) 00390 * \param accumulated_failures failed attempts 00391 * 00392 * \return ETX value (12 bit fraction) 00393 */ 00394 static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures) 00395 { 00396 uint32_t current_etx; 00397 00398 // If there is no failed attempts 00399 if (accumulated_failures == 0) { 00400 current_etx = etx; 00401 } else { 00402 /* Calculates ETX estimate based on failed attempts 00403 ETX = current ETX + 1/8 * (failed attempts << 12) */ 00404 current_etx = etx + (accumulated_failures << (12 - ETX_MOVING_AVERAGE_FRACTION)); 00405 if (current_etx > 0xffff) { 00406 current_etx = 0xffff; 00407 } 00408 } 00409 00410 return current_etx; 00411 } 00412 00413 /** 00414 * \brief A function to update ETX value based on LQI and dBm 00415 * 00416 * Update is made based on dBM and LQI of received message. 00417 * 00418 * \param lqi link quality indicator 00419 * \param dbm measured dBm 00420 * \param mac64_addr_ptr long MAC address 00421 * 00422 * \return 0x0100 to 0xFFFF local incoming IDR value (8 bit fraction) 00423 */ 00424 uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index) 00425 { 00426 uint32_t local_incoming_idr = 0; 00427 uint32_t etx = 0; 00428 00429 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00430 00431 if (entry) { 00432 // If local ETX is not set calculate it based on LQI and dBm 00433 if (!entry->etx) { 00434 etx = etx_dbm_lqi_calc(lqi, dbm); 00435 entry->etx = etx; 00436 entry->tmp_etx = true; 00437 } 00438 // If local ETX has been calculated without remote incoming IDR and 00439 // remote incoming IDR is available update it by remote incoming IDR value 00440 if (entry->remote_incoming_idr && entry->tmp_etx) { 00441 entry->tmp_etx = false; 00442 00443 local_incoming_idr = isqrt32((uint32_t)entry->etx << 16); 00444 // divide by sqrt(2^12) and scale to 12 bit fraction 00445 local_incoming_idr = local_incoming_idr >> 2; 00446 00447 etx = local_incoming_idr * (((uint16_t)entry->remote_incoming_idr) << 7); 00448 entry->etx = etx >> 12; 00449 00450 local_incoming_idr >>= 4; 00451 } 00452 00453 // If local ETX has been calculated indicates new neighbor 00454 if (etx) { 00455 etx_neighbor_add(interface_id, attribute_index); 00456 } 00457 } 00458 00459 // If local ETX is not set return temporary ETX based on LQI and dB, 00460 if (!local_incoming_idr) { 00461 if (!etx) { 00462 etx = etx_dbm_lqi_calc(lqi, dbm); 00463 } 00464 00465 local_incoming_idr = isqrt32(etx << 16); 00466 // divide by sqrt(2^12) 00467 local_incoming_idr >>= 6; 00468 } 00469 00470 return local_incoming_idr; 00471 } 00472 00473 /** 00474 * \brief A function to calculate ETX value based on dBm and LQI 00475 * 00476 * Calculation is made using RF driver service. If service does not 00477 * exists then local function is used. 00478 * 00479 * \param lqi link quality indicator 00480 * \param dbm measured dBm 00481 * 00482 * \return ETX value (12 bit fraction) 00483 */ 00484 static uint16_t etx_dbm_lqi_calc(uint8_t lqi, int8_t dbm) 00485 { 00486 protocol_interface_info_entry_t *cur = 0; 00487 int8_t driver_ret_value = -1; 00488 uint16_t etx; 00489 00490 phy_signal_info_s signal_info; 00491 signal_info.type = PHY_SIGNAL_INFO_ETX; 00492 signal_info.lqi = lqi; 00493 signal_info.dbm = dbm; 00494 signal_info.result = 0xffff; 00495 00496 //TODO: This is needed, but RF driver cannot be accessed directly! Figure out MAC extension for this. 00497 cur = protocol_stack_interface_info_get(IF_6LoWPAN); 00498 if ((cur) && (cur->dev_driver) && (cur->dev_driver->phy_driver)) { 00499 phy_device_driver_s *dev_driver = cur->dev_driver->phy_driver; 00500 if (dev_driver->extension) { 00501 driver_ret_value = dev_driver->extension(PHY_EXTENSION_CONVERT_SIGNAL_INFO, (uint8_t *)&signal_info); 00502 } 00503 } 00504 00505 if ((driver_ret_value != -1) && (signal_info.result != 0xffff)) { 00506 etx = signal_info.result; 00507 etx <<= 4; 00508 } else { 00509 /* Atmel version 00510 dBm = RSSI base value [dBm] + 1.03 [dB] x ED level 00511 LQI = errors in received frame */ 00512 00513 // for dBm -90 and LQI 0 ETX will be 2.4 00514 etx = ((dbm * -1) * (256 - lqi)); 00515 etx >>= 1; // scale result to 12 bits 00516 etx += 1 << 12; // add one (perfect link) 00517 } 00518 00519 return etx; 00520 } 00521 00522 /** 00523 * \brief A function to register ETX value change callback 00524 * 00525 * Register ETX value change callback. When ETX value has changed more or equal 00526 * to hysteresis value ETX module calls ETX value change callback. 00527 * 00528 * \param nwk_interface_id network interface id 00529 * \param hysteresis hysteresis value (8 bit fraction) 00530 * \param callback_ptr callback function pointer 00531 * 00532 * \return 0 not 6LowPAN interface 00533 * \return 1 success 00534 */ 00535 uint8_t etx_value_change_callback_register(nwk_interface_id nwk_id, int8_t interface_id, uint16_t hysteresis, etx_value_change_handler_t *callback_ptr) 00536 { 00537 if ((nwk_id == IF_6LoWPAN) && hysteresis && callback_ptr) { 00538 etx_info.hysteresis = hysteresis << 4; 00539 etx_info.callback_ptr = callback_ptr; 00540 etx_info.interface_id = interface_id; 00541 return 1; 00542 } else { 00543 return 0; 00544 } 00545 } 00546 00547 bool etx_storage_list_allocate(int8_t interface_id, uint8_t etx_storage_size) 00548 { 00549 if (!etx_storage_size) { 00550 ns_dyn_mem_free(etx_info.etx_storage_list); 00551 ns_dyn_mem_free(etx_info.etx_cache_storage_list); 00552 etx_info.etx_cache_storage_list = NULL; 00553 etx_info.cache_sample_requested = false; 00554 etx_info.etx_storage_list = NULL; 00555 etx_info.ext_storage_list_size = 0; 00556 return true; 00557 } 00558 00559 if (etx_info.ext_storage_list_size == etx_storage_size) { 00560 return true; 00561 } 00562 00563 ns_dyn_mem_free(etx_info.etx_storage_list); 00564 etx_info.cache_sample_requested = false; 00565 etx_info.ext_storage_list_size = 0; 00566 etx_info.etx_storage_list = ns_dyn_mem_alloc(sizeof(etx_storage_t) * etx_storage_size); 00567 00568 if (!etx_info.etx_storage_list) { 00569 ns_dyn_mem_free(etx_info.etx_storage_list); 00570 etx_info.etx_storage_list = NULL; 00571 etx_info.ext_storage_list_size = 0; 00572 return false; 00573 } 00574 00575 00576 etx_info.ext_storage_list_size = etx_storage_size; 00577 etx_info.interface_id = interface_id; 00578 etx_storage_t *list_ptr = etx_info.etx_storage_list; 00579 for (uint8_t i = 0; i < etx_storage_size; i++) { 00580 memset(list_ptr, 0, sizeof(etx_storage_t)); 00581 00582 list_ptr++; 00583 } 00584 return true; 00585 00586 } 00587 00588 bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_count) 00589 { 00590 //No ini ETX allocation done yet 00591 if (etx_info.ext_storage_list_size == 0) { 00592 return false; 00593 } 00594 00595 if (min_wait_time || etx_min_sample_count) { 00596 if (!etx_info.etx_cache_storage_list) { 00597 //allocate 00598 etx_info.etx_cache_storage_list = ns_dyn_mem_alloc(sizeof(etx_sample_storage_t) * etx_info.ext_storage_list_size); 00599 00600 if (!etx_info.etx_cache_storage_list) { 00601 return false; 00602 } 00603 etx_info.cache_sample_requested = true; 00604 etx_sample_storage_t *sample_list = etx_info.etx_cache_storage_list; 00605 for (uint8_t i = 0; i < etx_info.ext_storage_list_size; i++) { 00606 memset(sample_list, 0, sizeof(etx_sample_storage_t)); 00607 sample_list++; 00608 } 00609 } 00610 00611 } else { 00612 //Free Cache table we not need that anymore 00613 etx_info.cache_sample_requested = false; 00614 ns_dyn_mem_free(etx_info.etx_cache_storage_list); 00615 etx_info.etx_cache_storage_list = NULL; 00616 } 00617 00618 etx_info.min_sample_count = etx_min_sample_count; 00619 etx_info.etx_min_sampling_time = min_wait_time; 00620 00621 return true; 00622 } 00623 00624 void etx_max_update_set(uint16_t etx_max_update) 00625 { 00626 if (etx_max_update) { 00627 etx_info.max_etx_update = (etx_max_update / 128) << (12 - ETX_MOVING_AVERAGE_FRACTION); 00628 } else { 00629 etx_info.max_etx_update = 0; 00630 } 00631 } 00632 00633 etx_storage_t *etx_storage_entry_get(int8_t interface_id, uint8_t attribute_index) 00634 { 00635 if (etx_info.interface_id != interface_id || !etx_info.etx_storage_list || attribute_index >= etx_info.ext_storage_list_size) { 00636 return NULL; 00637 } 00638 00639 etx_storage_t *entry = etx_info.etx_storage_list + attribute_index; 00640 return entry; 00641 } 00642 00643 00644 /** 00645 * \brief A function to register accumulated failures callback 00646 * 00647 * When the number of accumulated failures has reached the threshold 00648 * value, the ETX module calls the accumulated failures callback on 00649 * every transmission failure. 00650 * 00651 * \param nwk_id network ID (6LoWPAN) 00652 * \param interface_id interface ID 00653 * \param threshold threshold value for accumulated failures 00654 * \param callback_ptr callback function pointer 00655 * 00656 * \return 0 not 6LowPAN interface 00657 * \return 1 success 00658 */ 00659 uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t interface_id, uint8_t threshold, etx_accum_failures_handler_t *callback_ptr) 00660 { 00661 if ((nwk_id == IF_6LoWPAN) && threshold && callback_ptr) { 00662 etx_info.interface_id = interface_id; 00663 etx_info.accum_threshold = threshold; 00664 etx_info.accum_cb_ptr = callback_ptr; 00665 return 1; 00666 } else { 00667 return 0; 00668 } 00669 } 00670 00671 /** 00672 * \brief A function to check if ETX value change callback is needed 00673 * 00674 * Calculates current ETX and compares it against stored ETX. If change 00675 * of the values is more than hysteresis calls ETX value change 00676 * callback. 00677 * 00678 * \param etx ETX (12 bit fraction) 00679 * \param stored_diff_etx stored ETX value 00680 * \param accumulated_failures failed attempts 00681 * \param mac64_addr_ptr long MAC address 00682 * \param mac16_addr short MAC address or 0xffff address is not set 00683 * 00684 * \return ETX value (12 bit fraction) 00685 */ 00686 static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index) 00687 { 00688 uint16_t current_etx; 00689 bool callback = false; 00690 if (!etx_info.hysteresis) { 00691 return; 00692 } 00693 00694 // Calculates current ETX 00695 current_etx = etx_current_calc(etx, accumulated_failures); 00696 00697 // If difference is more than hysteresis 00698 if (current_etx > *stored_diff_etx) { 00699 if (current_etx - *stored_diff_etx >= etx_info.hysteresis) { 00700 callback = true; 00701 } 00702 } else if (current_etx < *stored_diff_etx) { 00703 if (*stored_diff_etx - current_etx >= etx_info.hysteresis) { 00704 callback = true; 00705 } 00706 } 00707 00708 // Calls callback function 00709 if (callback) { 00710 etx_info.callback_ptr(etx_info.interface_id, (*stored_diff_etx) >> 4, current_etx >> 4, attribute_index); 00711 *stored_diff_etx = current_etx; 00712 } 00713 } 00714 00715 /** 00716 * \brief A function to check if accumulated failures callback is needed 00717 * 00718 * If the current number of accumulated failures is equal or greater than 00719 * the set threshold value, the function calls accumulated failures callback. 00720 * 00721 * \param neigh_table_ptr the neighbor node in question 00722 */ 00723 static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8_t attribute_index) 00724 { 00725 if (!etx_info.accum_threshold) { 00726 return; 00727 } 00728 00729 if (entry->accumulated_failures < etx_info.accum_threshold) { 00730 return; 00731 } 00732 00733 etx_info.accum_cb_ptr(etx_info.interface_id, entry->accumulated_failures, attribute_index); 00734 } 00735 00736 /** 00737 * \brief A function to remove ETX neighbor 00738 * 00739 * Notifies ETX module that neighbor has been removed. Calls ETX value change callback 00740 * if that is set. 00741 * 00742 * \param mac64_addr_ptr long MAC address 00743 * 00744 */ 00745 void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) 00746 { 00747 00748 //tr_debug("Remove attribute %u", attribute_index); 00749 uint16_t stored_diff_etx; 00750 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00751 if (entry && etx_info.callback_ptr) { 00752 00753 if (entry->etx) { 00754 stored_diff_etx = entry->stored_diff_etx >> 4; 00755 if (!stored_diff_etx) { 00756 stored_diff_etx = 0xffff; 00757 } 00758 etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx, 0xffff, attribute_index); 00759 } 00760 00761 if (etx_info.cache_sample_requested) { 00762 //Clear cached values 00763 etx_sample_storage_t *cache_entry = etx_info.etx_cache_storage_list + attribute_index; 00764 memset(cache_entry, 0, sizeof(etx_sample_storage_t)); 00765 } 00766 //Clear all data base back to zero for new user 00767 memset(entry, 0, sizeof(etx_storage_t)); 00768 } 00769 } 00770 00771 /** 00772 * \brief A function to add ETX neighbor 00773 * 00774 * Notifies ETX module that neighbor has been added. Calls ETX value change callback 00775 * if that is set. 00776 * 00777 * \param mac64_addr_ptr long MAC address 00778 * 00779 */ 00780 void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index) 00781 { 00782 00783 //tr_debug("Add attribute %u", attribute_index); 00784 uint16_t stored_diff_etx; 00785 etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); 00786 if (entry && etx_info.callback_ptr) { 00787 // Gets table entry 00788 00789 if (entry->etx) { 00790 stored_diff_etx = entry->stored_diff_etx; 00791 if (!stored_diff_etx) { 00792 stored_diff_etx = entry->etx; 00793 } 00794 etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx >> 4, entry->etx >> 4, 00795 attribute_index); 00796 } 00797 } 00798 } 00799 00800 void etx_cache_timer(int8_t interface_id, uint16_t seconds_update) 00801 { 00802 if (!etx_info.cache_sample_requested) { 00803 return; 00804 } 00805 00806 protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(interface_id); 00807 if (!interface || !mac_neighbor_info(interface)) { 00808 return; 00809 } 00810 00811 ns_list_foreach(mac_neighbor_table_entry_t, neighbour, &mac_neighbor_info(interface)->neighbour_list) { 00812 00813 etx_storage_t *etx_entry = etx_storage_entry_get(interface_id, neighbour->index); 00814 00815 if (!etx_entry || etx_entry->tmp_etx) { 00816 continue; 00817 } 00818 etx_sample_storage_t *storage = etx_info.etx_cache_storage_list + neighbour->index; 00819 00820 if (etx_update_possible(storage, etx_entry, seconds_update)) { 00821 etx_calculation(etx_entry, storage->attempts_count, storage->received_acks, neighbour->index); 00822 } 00823 } 00824 00825 }
Generated on Tue Jul 12 2022 13:54:19 by
