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.
Fork of OmniWheels by
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 Fri Jul 22 2022 04:53:51 by
1.7.2
