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.
load_balance.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 00018 00019 #include "nsconfig.h" 00020 #include "ns_types.h" 00021 #include "eventOS_event.h" 00022 #include "eventOS_scheduler.h" 00023 #include "eventOS_callback_timer.h" 00024 #include "load_balance_api.h" 00025 #include "string.h" 00026 #include "ns_trace.h" 00027 #include "nsdynmemLIB.h" 00028 #include "randLIB.h" 00029 #include "mlme.h" 00030 00031 typedef enum { 00032 LB_NWK_SWITCH_IDLE = 0, 00033 LB_NWK_SWITCH_ROUTER_LEAVE, 00034 LB_NWK_SWITCH_NEIGHBOUR_LEAVE 00035 } lb_nwk_switch_state_t; 00036 00037 typedef enum { 00038 LB_IDLE_STATE = 0, 00039 LB_BLOCK_STATE, 00040 LB_ACCEPT_STATE, 00041 LB_BLOCK_COMPARE, 00042 LB_BLOCK_NETWORK_SELECT, 00043 } lb_state_t; 00044 00045 /** 00046 * @brief struct lb_network_s Load balance network information 00047 * 00048 */ 00049 typedef struct lb_network_s { 00050 struct mlme_pan_descriptor_s PANDescriptor; 00051 uint8_t priority; 00052 bool network_switch_accepted; 00053 lb_nwk_switch_state_t state; 00054 uint16_t state_timer; 00055 uint16_t beacon_data_length; 00056 uint8_t beacon_data[]; 00057 } lb_network_t; 00058 00059 /** get pointer to Mac header start point*/ 00060 #define beacon_payload_start_pointer(x) (&(x)->beacon_data[0]) 00061 00062 typedef struct lb_monitor_internal_s { 00063 load_balance_api_get_node_count *get_count_cb; 00064 load_balance_api_set_load_level *set_new_load_cb; 00065 uint16_t expected_node_count; 00066 uint8_t network_load_scaler; 00067 uint8_t last_load_level; 00068 uint16_t timer2update; 00069 }lb_monitor_internal_t; 00070 00071 00072 typedef struct lb_internal_s { 00073 load_balance_api_t *lb_api; 00074 lb_monitor_internal_t *lb_border_router; 00075 //user spesific callback 00076 load_balance_beacon_tx *load_balance_beacon_tx_cb; 00077 load_balance_priority_get *lb_priority_get_cb; 00078 load_balance_network_switch_req *lb_nwk_switch_cb; 00079 load_balance_network_switch_notify *lb_nwk_switch_notify; //Can be NULL if app not want to control 00080 //APP defined nwk switch callback 00081 net_load_balance_network_switch_notify *lb_access_switch_cb; 00082 void *lb_user_parent_id; 00083 lb_network_t *notified_network; 00084 uint32_t triggle_period; 00085 uint32_t lb_state_timer; 00086 uint32_t time_to_next_beacon; 00087 uint16_t beacon_max_payload_length; 00088 uint8_t nwk_switch_threshold_min; 00089 uint8_t nwk_switch_threshold_max; 00090 uint8_t nwk_maX_P; 00091 lb_state_t lb_state; 00092 bool load_balance_activate; 00093 bool periodic_beacon_activated; 00094 }lb_internal_t; 00095 00096 00097 /** 00098 * Load balance internal variables 00099 */ 00100 static load_balance_api_t lb_api; 00101 static lb_internal_t *lb_store = NULL; 00102 00103 /** 00104 * Load balance internal used functions 00105 */ 00106 static lb_internal_t * load_balance_class_allocate(void); 00107 static void load_balance_class_free(lb_internal_t *api); 00108 static lb_internal_t *lb_api_get(const load_balance_api_t* api); 00109 static bool load_balance_network_class_allocate(lb_internal_t *lb_store_ptr, uint16_t beacon_max_payload_length); 00110 static void lb_network_switch_handle(lb_internal_t *this); 00111 static void lb_load_level_poll(lb_internal_t * this, uint32_t trigle_period); 00112 00113 /** 00114 * Load balance shared functions to user 00115 */ 00116 static void lb_beacon_notify(const load_balance_api_t* api, const struct mlme_beacon_ind_s *beacon_ind, uint8_t priority); 00117 static void lb_enable(const load_balance_api_t* api, bool active_state, uint32_t network_triggle_max_period, uint32_t network_route_life_time); 00118 static int8_t lb_api_initialize(load_balance_api_t *api, load_balance_beacon_tx *lb_beacon_tx, 00119 load_balance_priority_get *priority_get_cb, load_balance_network_switch_req *lb_nwk_switch_cb, uint16_t baecon_max_payload_length, void *lb_user); 00120 static void lb_second_ticks(const load_balance_api_t* api); 00121 00122 #define TRACE_GROUP "lba" 00123 00124 /** 00125 * Load balance border router class allocate 00126 */ 00127 static lb_monitor_internal_t *lb_border_router_api_allocate(lb_internal_t* api) 00128 { 00129 if (!api->lb_border_router) { 00130 api->lb_border_router = ns_dyn_mem_alloc(sizeof(lb_monitor_internal_t)); 00131 } 00132 return api->lb_border_router; 00133 } 00134 00135 /** 00136 * Load balance border router class free 00137 */ 00138 static int8_t lb_border_router_api_free(lb_internal_t* api) 00139 { 00140 if (api->lb_border_router) { 00141 ns_dyn_mem_free(api->lb_border_router); 00142 api->lb_border_router = NULL; 00143 return 0; 00144 } 00145 return -1; 00146 } 00147 00148 /** 00149 * Allocate Load balance class base 00150 */ 00151 static lb_internal_t * load_balance_class_allocate(void) 00152 { 00153 if (lb_store) { 00154 if (lb_store->lb_user_parent_id) { 00155 return NULL; 00156 } 00157 return lb_store; 00158 } 00159 00160 lb_internal_t *store = ns_dyn_mem_alloc(sizeof(lb_internal_t)); 00161 if (store) { 00162 00163 store->lb_api = &lb_api; 00164 lb_api.lb_beacon_notify = lb_beacon_notify; 00165 lb_api.lb_enable = lb_enable; 00166 lb_api.lb_initialize = lb_api_initialize; 00167 lb_api.lb_seconds_tick_update = lb_second_ticks; 00168 00169 store->lb_border_router = NULL; 00170 store->load_balance_beacon_tx_cb = NULL; 00171 store->lb_nwk_switch_cb = NULL; 00172 store->lb_priority_get_cb = NULL; 00173 store->lb_user_parent_id = NULL; 00174 store->notified_network = NULL; 00175 store->lb_access_switch_cb = NULL; 00176 store->beacon_max_payload_length = 0; 00177 store->nwk_switch_threshold_max = 0; 00178 store->nwk_switch_threshold_min = 0; 00179 store->nwk_maX_P = 25; 00180 store->load_balance_activate = false; 00181 store->time_to_next_beacon = 0; 00182 store->triggle_period = 0; 00183 lb_store = store; 00184 } 00185 00186 return store; 00187 } 00188 00189 /** 00190 * Free allocated load balance class 00191 */ 00192 static void load_balance_class_free(lb_internal_t *api) 00193 { 00194 //Clean heared networks 00195 ns_dyn_mem_free(api->notified_network); 00196 lb_border_router_api_free(api); 00197 ns_dyn_mem_free(api); 00198 } 00199 00200 /** 00201 * Load balance class get by user API pointer 00202 */ 00203 static lb_internal_t *lb_api_get(const load_balance_api_t* api) 00204 { 00205 if (!api || !lb_store || lb_store->lb_api != api) { 00206 return NULL; 00207 } 00208 return lb_store; 00209 } 00210 00211 00212 00213 /** 00214 * Allocate notified network class 00215 */ 00216 static bool load_balance_network_class_allocate(lb_internal_t *lb_store_ptr, uint16_t beacon_max_payload_length) 00217 { 00218 ns_dyn_mem_free(lb_store_ptr->notified_network); 00219 lb_store_ptr->beacon_max_payload_length = 0; 00220 if (beacon_max_payload_length) { 00221 lb_store_ptr->notified_network = ns_dyn_mem_alloc(sizeof(lb_network_t) + beacon_max_payload_length); 00222 if (!lb_store_ptr->notified_network) { 00223 return false; 00224 } 00225 lb_store_ptr->notified_network->network_switch_accepted = false; 00226 lb_store_ptr->notified_network->priority = 0xff; 00227 lb_store_ptr->notified_network->state = LB_NWK_SWITCH_IDLE; 00228 lb_store_ptr->notified_network->state_timer = 0; 00229 lb_store_ptr->beacon_max_payload_length = beacon_max_payload_length; 00230 00231 } 00232 return true; 00233 } 00234 00235 /** 00236 * Switch to notified and selected network 00237 */ 00238 static void lb_network_switch_handle(lb_internal_t *this) 00239 { 00240 lb_network_t *network_class = this->notified_network; 00241 if (network_class->state_timer) { 00242 network_class->state_timer--; 00243 return; 00244 } 00245 00246 switch (network_class->state) { 00247 case LB_NWK_SWITCH_IDLE: 00248 if (!this->notified_network->network_switch_accepted) { 00249 if (this->lb_access_switch_cb && !this->lb_access_switch_cb() ) { 00250 return; 00251 } 00252 this->notified_network->network_switch_accepted = true; 00253 } 00254 tr_info("Start NWK switch statemachine!"); 00255 this->lb_nwk_switch_notify(this->lb_user_parent_id, LB_ROUTER_LEAVE, &network_class->state_timer); 00256 network_class->state = LB_NWK_SWITCH_ROUTER_LEAVE; 00257 break; 00258 00259 case LB_NWK_SWITCH_ROUTER_LEAVE: 00260 tr_info("Router leave state!"); 00261 this->lb_nwk_switch_notify(this->lb_user_parent_id, LB_NEIGHBOUR_LEAVE, &network_class->state_timer); 00262 network_class->state = LB_NWK_SWITCH_NEIGHBOUR_LEAVE; 00263 break; 00264 00265 case LB_NWK_SWITCH_NEIGHBOUR_LEAVE: 00266 tr_info("Neighbour leave state!"); 00267 //Disable beacon send 00268 lb_enable(this->lb_api, false, 0, 0); 00269 this->lb_nwk_switch_cb(this->lb_user_parent_id, &network_class->PANDescriptor, beacon_payload_start_pointer(network_class), network_class->beacon_data_length); 00270 break; 00271 } 00272 00273 } 00274 00275 static bool lb_accept_beacon_state(lb_state_t lb_state) 00276 { 00277 //Check state 00278 switch (lb_state) { 00279 case LB_IDLE_STATE: 00280 case LB_BLOCK_STATE: 00281 case LB_BLOCK_COMPARE: 00282 return false; 00283 default: 00284 break; 00285 00286 } 00287 return true; 00288 } 00289 00290 /** 00291 * Beacon notify handler 00292 */ 00293 static void lb_beacon_notify(const load_balance_api_t* api, const struct mlme_beacon_ind_s *beacon_ind, uint8_t priority) 00294 { 00295 lb_internal_t * this = lb_api_get(api); 00296 if (!beacon_ind || !this || !this->nwk_switch_threshold_max || !this->nwk_switch_threshold_min) { 00297 return; 00298 } else if (!lb_accept_beacon_state(this->lb_state)) { 00299 return; 00300 } else if (beacon_ind->beacon_data_length > this->beacon_max_payload_length) { 00301 return; 00302 } 00303 00304 lb_network_t *nwk = this->notified_network; 00305 //Get current global part joining priority 00306 uint8_t current_priority = this->lb_priority_get_cb(this->lb_user_parent_id); 00307 00308 if (this->lb_state == LB_ACCEPT_STATE) { 00309 //Compare new network priority 00310 if (current_priority < priority) { 00311 return; 00312 } 00313 00314 uint16_t diff = current_priority - priority; 00315 uint16_t switch_prob; // 256 * percent (0-25600) 00316 00317 if (diff >= this->nwk_switch_threshold_max) { 00318 switch_prob = this->nwk_maX_P * 256; 00319 tr_debug("diff %"PRIu16", tmax %"PRIu8" %"PRIu16, diff, this->nwk_switch_threshold_max, switch_prob); 00320 } else if (diff <= this->nwk_switch_threshold_min) { 00321 tr_debug("diff %"PRIu16", tmin %"PRIu8, diff, this->nwk_switch_threshold_min); 00322 switch_prob = 0; 00323 } else { 00324 // The multiplication could overflow 16-bit, even though the final result will be 16-bit 00325 switch_prob = (uint32_t) this->nwk_maX_P * 256 * (diff - this->nwk_switch_threshold_min) / (this->nwk_switch_threshold_max - this->nwk_switch_threshold_min); 00326 tr_debug("diff between min & max, diff %"PRIu16", tmax %"PRIu8" prob%"PRIu16, diff, this->nwk_switch_threshold_max, switch_prob); 00327 } 00328 00329 if (switch_prob > randLIB_get_random_in_range(0, 25599)) { 00330 this->lb_state_timer = randLIB_get_random_in_range(1, 32); 00331 this->lb_state = LB_BLOCK_NETWORK_SELECT; 00332 } 00333 else { 00334 //Enter Block state 00335 this->lb_state_timer = this->triggle_period; 00336 this->lb_state = LB_BLOCK_COMPARE; 00337 return; 00338 } 00339 00340 } else { 00341 //Compare priority to saved network 00342 if (priority > nwk->priority) { 00343 return; 00344 } else if (priority == nwk->priority && nwk->PANDescriptor.LinkQuality > beacon_ind->PANDescriptor.LinkQuality) { 00345 return; 00346 } 00347 } 00348 00349 //Copy network info 00350 nwk->priority = priority; 00351 nwk->PANDescriptor = beacon_ind->PANDescriptor; 00352 memcpy(beacon_payload_start_pointer(nwk), beacon_ind->beacon_data, beacon_ind->beacon_data_length); 00353 nwk->beacon_data_length = beacon_ind->beacon_data_length; 00354 } 00355 /** 00356 * Load balance activate or disable 00357 */ 00358 static void lb_enable(const load_balance_api_t* api, bool active_state, uint32_t network_triggle_max_period, uint32_t network_route_life_time) 00359 { 00360 lb_internal_t * this = lb_api_get(api); 00361 if (!this || !this->lb_user_parent_id) { 00362 return; 00363 } 00364 00365 this->load_balance_activate = active_state; 00366 00367 if (active_state) { 00368 //Start Block_period 00369 this->triggle_period = network_triggle_max_period; 00370 this->lb_state = LB_BLOCK_STATE; 00371 tr_debug("Enable Network Triggle max time %"PRIu32" %"PRIu32" route life time", network_triggle_max_period, network_route_life_time); 00372 if (this->nwk_switch_threshold_min && this->nwk_switch_threshold_max) { 00373 this->lb_state_timer = network_route_life_time > network_triggle_max_period ? network_route_life_time : network_triggle_max_period; 00374 } else { 00375 this->lb_state_timer = 10; 00376 if (this->lb_border_router) { 00377 this->lb_border_router->timer2update = 0; 00378 lb_load_level_poll(this, this->triggle_period); 00379 } 00380 } 00381 00382 } else { 00383 this->lb_state = LB_IDLE_STATE; 00384 } 00385 00386 if (this->notified_network) { 00387 this->notified_network->priority = 0xff; 00388 this->notified_network->network_switch_accepted = false; 00389 this->notified_network->state = LB_NWK_SWITCH_IDLE; 00390 this->notified_network->state_timer = 0; 00391 } 00392 } 00393 00394 /** 00395 * Load balance activate or disable 00396 */ 00397 static int8_t lb_api_initialize(load_balance_api_t *api, load_balance_beacon_tx *lb_beacon_tx, 00398 load_balance_priority_get *priority_get_cb, load_balance_network_switch_req *lb_nwk_switch_cb, uint16_t beacon_max_payload_length, void *lb_user) 00399 { 00400 lb_internal_t * this = lb_api_get(api); 00401 if (!this || !lb_beacon_tx || !priority_get_cb || !lb_nwk_switch_cb || !lb_user) { 00402 return -1; 00403 } 00404 00405 //Allocate beacon payload here 00406 if (!load_balance_network_class_allocate(this, beacon_max_payload_length)) { 00407 return -2; 00408 } 00409 00410 this->lb_user_parent_id = lb_user; 00411 this->load_balance_beacon_tx_cb = lb_beacon_tx; 00412 this->lb_nwk_switch_cb = lb_nwk_switch_cb; 00413 this->lb_priority_get_cb = priority_get_cb; 00414 return 0; 00415 } 00416 00417 static void lb_load_level_poll(lb_internal_t * this, uint32_t trigle_period) 00418 { 00419 if (!this->lb_border_router || !this->lb_user_parent_id) { 00420 return; 00421 } 00422 00423 if (this->lb_border_router->timer2update) { 00424 this->lb_border_router->timer2update--; 00425 return; 00426 } 00427 00428 uint16_t node_count; 00429 if (this->lb_border_router->get_count_cb(this->lb_user_parent_id, &node_count) != 0) { 00430 this->lb_border_router->last_load_level = 0xff; 00431 this->lb_border_router->timer2update = 10; 00432 return; 00433 } 00434 //Calculate 00435 uint8_t new_load; 00436 if (node_count >= this->lb_border_router->expected_node_count) { 00437 new_load = this->lb_border_router->network_load_scaler - 1; 00438 } else { 00439 uint16_t scaled_level = this->lb_border_router->expected_node_count / this->lb_border_router->network_load_scaler; 00440 new_load = node_count / scaled_level; 00441 } 00442 00443 if (this->lb_border_router->last_load_level != new_load) { 00444 00445 if (this->lb_border_router->set_new_load_cb(this->lb_user_parent_id, new_load) == 0) { 00446 this->lb_border_router->last_load_level = new_load; 00447 } 00448 } 00449 this->lb_border_router->timer2update = trigle_period >> 1; //Update Every block period / 2 00450 } 00451 00452 static void lb_second_ticks(const load_balance_api_t* api) 00453 { 00454 lb_internal_t * this = lb_api_get(api); 00455 if (!this || this->lb_state == LB_IDLE_STATE) { 00456 return; 00457 } 00458 00459 lb_load_level_poll(this, this->triggle_period); 00460 00461 //Update Next beacon generation timer 00462 if (this->periodic_beacon_activated && this->lb_state != LB_BLOCK_STATE && --this->time_to_next_beacon == 0) { 00463 this->time_to_next_beacon = this->triggle_period; 00464 this->load_balance_beacon_tx_cb(this->lb_user_parent_id); 00465 } 00466 00467 if (this->lb_state_timer == 0) { 00468 00469 switch (this->lb_state) { 00470 case LB_BLOCK_STATE: 00471 //Enter block state to accept state 00472 this->lb_state = LB_ACCEPT_STATE; 00473 this->time_to_next_beacon = randLIB_get_random_in_range(1, 32); 00474 break; 00475 case LB_BLOCK_COMPARE: 00476 this->lb_state = LB_ACCEPT_STATE; 00477 break; 00478 case LB_BLOCK_NETWORK_SELECT: 00479 lb_network_switch_handle(this); 00480 break; 00481 default: 00482 break; 00483 } 00484 } else { 00485 this->lb_state_timer--; 00486 } 00487 } 00488 00489 load_balance_api_t *load_balance_create(load_balance_network_switch_notify *lb_notify_cb, bool activate_periodic_beacon) 00490 { 00491 //validate beacon period & beacon_notify 00492 if (!lb_notify_cb) { 00493 return NULL; 00494 } 00495 00496 //allocate load balance class 00497 lb_internal_t * this = load_balance_class_allocate(); 00498 if (!this) { 00499 return NULL; 00500 } 00501 this->lb_state = LB_IDLE_STATE; 00502 this->lb_nwk_switch_notify = lb_notify_cb; 00503 this->periodic_beacon_activated = activate_periodic_beacon; 00504 00505 return this->lb_api; 00506 } 00507 00508 int load_balance_delete(load_balance_api_t *api) 00509 { 00510 if (!lb_store || lb_store->lb_api != api) { 00511 return -1; 00512 } 00513 00514 load_balance_class_free(lb_store); 00515 lb_store = NULL; 00516 return 0; 00517 } 00518 00519 int load_balance_network_threshold_set(load_balance_api_t *api, uint8_t threshold_min, uint8_t threshold_max) 00520 { 00521 lb_internal_t * this = lb_api_get(api); 00522 if (!this) { 00523 return -1; 00524 } 00525 00526 this->nwk_switch_threshold_min = threshold_min; 00527 this->nwk_switch_threshold_max = threshold_max; 00528 return 0; 00529 } 00530 00531 int load_balance_network_load_monitor_enable(load_balance_api_t *api, uint16_t expected_node_count, uint8_t network_load_scaler, load_balance_api_get_node_count *get_count_cb, load_balance_api_set_load_level *set_new_load_cb) 00532 { 00533 lb_internal_t * this = lb_api_get(api); 00534 if (!this) { 00535 return -1; 00536 } 00537 if (expected_node_count == 0 || network_load_scaler == 0 || expected_node_count < network_load_scaler) { 00538 return -1; 00539 } 00540 00541 if (!get_count_cb || !set_new_load_cb) { 00542 return -1; 00543 } 00544 00545 lb_monitor_internal_t *border_router = lb_border_router_api_allocate(this); 00546 if (!border_router) { 00547 return -2; 00548 } 00549 border_router->expected_node_count = expected_node_count; 00550 border_router->network_load_scaler = network_load_scaler; 00551 border_router->get_count_cb = get_count_cb; 00552 border_router->last_load_level = 0xff; 00553 border_router->set_new_load_cb = set_new_load_cb; 00554 border_router->timer2update = 10; 00555 return 0; 00556 } 00557 00558 int load_balance_network_load_monitor_disable(load_balance_api_t *api) 00559 { 00560 lb_internal_t * this = lb_api_get(api); 00561 if (!this) { 00562 return -1; 00563 } 00564 return lb_border_router_api_free(this); 00565 } 00566 00567 int load_balance_set_max_probability(load_balance_api_t *api, uint8_t max_p) 00568 { 00569 lb_internal_t * this = lb_api_get(api); 00570 if (!this) { 00571 return -1; 00572 } 00573 if (max_p > 100 || max_p == 0) { 00574 return -1; 00575 } 00576 00577 this->nwk_maX_P = max_p; 00578 00579 return 0; 00580 00581 } 00582 00583 int load_balance_network_switch_cb_set(load_balance_api_t *api, net_load_balance_network_switch_notify *network_switch_notify) 00584 { 00585 lb_internal_t * this = lb_api_get(api); 00586 if (!this) { 00587 return -1; 00588 } 00589 00590 this->lb_access_switch_cb = network_switch_notify; 00591 00592 return 0; 00593 } 00594 00595
Generated on Tue Jul 12 2022 14:23:51 by
