mirror of https://github.com/ARMmbed/mbed-os.git
560 lines
16 KiB
C
560 lines
16 KiB
C
/*
|
|
* Copyright (c) 2014-2018, Pelion and affiliates.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* \file mac_data_poll.c
|
|
* \brief Add short description about this file!!!
|
|
*
|
|
*/
|
|
|
|
#include "nsconfig.h"
|
|
#include "ns_types.h"
|
|
#include "eventOS_event.h"
|
|
#include "eventOS_scheduler.h"
|
|
#include "eventOS_callback_timer.h"
|
|
#include "string.h"
|
|
#include "ns_trace.h"
|
|
#include "nsdynmemLIB.h"
|
|
#include "mac_api.h"
|
|
#include "mlme.h"
|
|
|
|
#include "NWK_INTERFACE/Include/protocol_stats.h"
|
|
#include "NWK_INTERFACE/Include/protocol.h"
|
|
#include "platform/arm_hal_interrupt.h"
|
|
#include "common_functions.h"
|
|
#include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
|
|
#include "6LoWPAN/Bootstraps/network_lib.h"
|
|
#include "6LoWPAN/Thread/thread_common.h"
|
|
#include "6LoWPAN/Thread/thread_bootstrap.h"
|
|
#ifndef NO_MLE
|
|
#include "MLE/mle.h"
|
|
#endif
|
|
#include "6LoWPAN/MAC/mac_helper.h"
|
|
#include "6LoWPAN/MAC/mac_data_poll.h"
|
|
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
|
|
|
|
#define TRACE_GROUP "mPol"
|
|
|
|
#define MAC_DATA_POLL_DEFAULT_RATE 20
|
|
|
|
#define MAC_DATA_POLL_REQUEST_EVENT 1
|
|
|
|
static int8_t mac_data_poll_tasklet = -1;
|
|
|
|
static void mac_data_poll_cb_run(int8_t interface_id);
|
|
|
|
|
|
static void mac_data_poll_cb(arm_event_s *event)
|
|
{
|
|
uint8_t event_type = event->event_type;
|
|
|
|
switch (event_type) {
|
|
case MAC_DATA_POLL_REQUEST_EVENT:
|
|
mac_data_poll_cb_run((int8_t)event->event_id);
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int8_t mac_data_poll_tasklet_init(void)
|
|
{
|
|
if (mac_data_poll_tasklet < 0) {
|
|
mac_data_poll_tasklet = eventOS_event_handler_create(&mac_data_poll_cb, 0);
|
|
}
|
|
|
|
return mac_data_poll_tasklet;
|
|
}
|
|
|
|
static int8_t host_link_configuration(bool rx_on_idle, protocol_interface_info_entry_t *cur)
|
|
{
|
|
bool backUp_bool = cur->mac_parameters->RxOnWhenIdle;
|
|
if (rx_on_idle) {
|
|
cur->lowpan_info &= ~INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE;
|
|
} else {
|
|
tr_debug("Enable Poll state by host Link");
|
|
cur->lowpan_info |= INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE;
|
|
}
|
|
mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, rx_on_idle);
|
|
|
|
if (thread_info(cur)) {
|
|
if (rx_on_idle != backUp_bool) {
|
|
//If mode have been changed, send child update
|
|
thread_bootstrap_child_update_trig(cur);
|
|
}
|
|
return 0;
|
|
} else {
|
|
if (protocol_6lowpan_child_update(cur) == 0) {
|
|
mac_data_poll_init_protocol_poll(cur);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//Swap back If Send Fail
|
|
if (!backUp_bool) {
|
|
cur->lowpan_info |= INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE;
|
|
} else {
|
|
cur->lowpan_info &= ~INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE;
|
|
}
|
|
mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, backUp_bool);
|
|
return -1;
|
|
}
|
|
|
|
static void mac_data_poll_protocol_internal(protocol_interface_info_entry_t *cur)
|
|
{
|
|
if (cur->rfd_poll_info->protocol_poll == 0) {
|
|
if (cur->rfd_poll_info->host_mode == NET_HOST_SLOW_POLL_MODE) {
|
|
if (!cur->rfd_poll_info->pollActive) {
|
|
mac_poll_timer_trig(1, cur);
|
|
}
|
|
}
|
|
}
|
|
cur->rfd_poll_info->protocol_poll++;
|
|
tr_debug("Protocol Poll: %02x", cur->rfd_poll_info->protocol_poll);
|
|
}
|
|
|
|
static void mac_data_poll_protocol_poll_internal_cancel(struct protocol_interface_info_entry *cur)
|
|
{
|
|
nwk_rfd_poll_setups_s *rf_ptr = cur->rfd_poll_info;
|
|
|
|
if (rf_ptr->protocol_poll == 0) {
|
|
return;
|
|
}
|
|
|
|
if (--rf_ptr->protocol_poll == 0) {
|
|
tr_debug("Disable Protocol Poll");
|
|
if (!rf_ptr->pollActive) {
|
|
if (rf_ptr->nwk_app_poll_time) {
|
|
mac_poll_timer_trig(1, cur);
|
|
} else {
|
|
eventOS_event_timer_cancel(cur->id, mac_data_poll_tasklet);
|
|
tr_debug("Stop Poll");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void mac_data_poll_init_protocol_poll(protocol_interface_info_entry_t *cur)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info || !(cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE)) {
|
|
return;
|
|
}
|
|
|
|
mac_data_poll_protocol_internal(cur);
|
|
|
|
}
|
|
|
|
uint32_t mac_data_poll_host_poll_time_max(protocol_interface_info_entry_t *cur)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info) {
|
|
return 0;
|
|
}
|
|
|
|
return cur->rfd_poll_info->slow_poll_rate_seconds;
|
|
}
|
|
|
|
uint32_t mac_data_poll_host_timeout(protocol_interface_info_entry_t *cur)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info) {
|
|
return 0;
|
|
}
|
|
|
|
return cur->rfd_poll_info->timeOutInSeconds;
|
|
}
|
|
|
|
uint32_t mac_data_poll_get_max_sleep_period(protocol_interface_info_entry_t *cur)
|
|
{
|
|
if (cur && cur->if_stack_buffer_handler && (cur->rfd_poll_info && !cur->rfd_poll_info->pollActive)) { // Verify That TX is not active
|
|
if (cur->rfd_poll_info->protocol_poll) {
|
|
return 300;
|
|
} else {
|
|
return cur->rfd_poll_info->nwk_app_poll_time;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mac_data_poll_protocol_poll_mode_decrement(struct protocol_interface_info_entry *cur)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info) {
|
|
return;
|
|
}
|
|
|
|
if (!(cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE)) {
|
|
return;
|
|
}
|
|
|
|
mac_data_poll_protocol_poll_internal_cancel(cur);
|
|
}
|
|
|
|
void mac_data_poll_protocol_poll_mode_disable(struct protocol_interface_info_entry *cur)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info) {
|
|
return;
|
|
}
|
|
|
|
if (!(cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE)) {
|
|
return;
|
|
}
|
|
|
|
mac_data_poll_protocol_poll_internal_cancel(cur);
|
|
}
|
|
|
|
void mac_data_poll_disable(struct protocol_interface_info_entry *cur)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info) {
|
|
return;
|
|
}
|
|
|
|
eventOS_event_timer_cancel(cur->id, mac_data_poll_tasklet);
|
|
cur->rfd_poll_info->protocol_poll = 0;
|
|
cur->rfd_poll_info->pollActive = false;
|
|
}
|
|
|
|
void mac_data_poll_enable_check(protocol_interface_info_entry_t *cur)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info) {
|
|
return;
|
|
}
|
|
|
|
if (!(cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE)) {
|
|
return;
|
|
}
|
|
|
|
mac_data_poll_protocol_internal(cur);
|
|
}
|
|
|
|
int8_t mac_data_poll_host_mode_get(struct protocol_interface_info_entry *cur, net_host_mode_t *mode)
|
|
{
|
|
if (!cur || !cur->rfd_poll_info) {
|
|
return -1;
|
|
}
|
|
|
|
*mode = cur->rfd_poll_info->host_mode;
|
|
return 0;
|
|
}
|
|
|
|
void mac_poll_timer_trig(uint32_t poll_time, protocol_interface_info_entry_t *cur)
|
|
{
|
|
if (!cur) {
|
|
return;
|
|
}
|
|
eventOS_event_timer_cancel(cur->id, mac_data_poll_tasklet);
|
|
|
|
if (poll_time) {
|
|
if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) {
|
|
|
|
if (poll_time < 20) {
|
|
arm_event_s event = {
|
|
.receiver = mac_data_poll_tasklet,
|
|
.sender = mac_data_poll_tasklet,
|
|
.event_id = cur->id,
|
|
.data_ptr = NULL,
|
|
.event_type = MAC_DATA_POLL_REQUEST_EVENT,
|
|
.priority = ARM_LIB_MED_PRIORITY_EVENT,
|
|
};
|
|
|
|
if (eventOS_event_send(&event) != 0) {
|
|
tr_error("eventOS_event_send() failed");
|
|
}
|
|
} else {
|
|
if (eventOS_event_timer_request(cur->id, MAC_DATA_POLL_REQUEST_EVENT, mac_data_poll_tasklet, poll_time) != 0) {
|
|
tr_error("Poll Timer start Fail");
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
static mac_neighbor_table_entry_t *neighbor_data_poll_referesh(protocol_interface_info_entry_t *cur, uint8_t *address, addrtype_t type)
|
|
{
|
|
mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur), address, type);
|
|
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!entry->connected_device) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!entry->nud_active) {
|
|
entry->lifetime = entry->link_lifetime;
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
void mac_mlme_poll_confirm(protocol_interface_info_entry_t *cur, const mlme_poll_conf_t *confirm)
|
|
{
|
|
if (!cur || !confirm) {
|
|
return;
|
|
}
|
|
|
|
uint32_t poll_time = 1;
|
|
nwk_rfd_poll_setups_s *rf_ptr = cur->rfd_poll_info;
|
|
if (!rf_ptr) {
|
|
return;
|
|
}
|
|
|
|
rf_ptr->pollActive = false;
|
|
mac_neighbor_table_entry_t *entry = NULL;
|
|
|
|
switch (confirm->status) {
|
|
case MLME_SUCCESS:
|
|
//tr_debug("Poll Confirm: Data with Data");
|
|
rf_ptr->nwk_parent_poll_fail = 0;
|
|
//Trig new Data Poll immediately
|
|
entry = neighbor_data_poll_referesh(cur, rf_ptr->poll_req.CoordAddress, (addrtype_t)rf_ptr->poll_req.CoordAddrMode);
|
|
poll_time = 1;
|
|
break;
|
|
|
|
case MLME_NO_DATA:
|
|
//Start next case timer
|
|
rf_ptr->nwk_parent_poll_fail = 0;
|
|
entry = neighbor_data_poll_referesh(cur, rf_ptr->poll_req.CoordAddress, (addrtype_t)rf_ptr->poll_req.CoordAddrMode);
|
|
//tr_debug("Poll Confirm: No Data");
|
|
|
|
if (rf_ptr->protocol_poll == 0) {
|
|
poll_time = rf_ptr->nwk_app_poll_time;
|
|
} else {
|
|
poll_time = 300;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
tr_debug("Poll Confirm: fail %x", confirm->status);
|
|
rf_ptr->nwk_parent_poll_fail++;
|
|
if (rf_ptr->nwk_parent_poll_fail > 3) {
|
|
//tr_debug("Parent Poll Fail");
|
|
poll_time = 0;
|
|
rf_ptr->nwk_parent_poll_fail = 0;
|
|
if (rf_ptr->pollFailCb) {
|
|
rf_ptr->pollFailCb(cur->id);
|
|
}
|
|
} else {
|
|
poll_time = 2000;
|
|
}
|
|
break;
|
|
}
|
|
if (thread_info(cur) && entry) {
|
|
thread_neighbor_communication_update(cur, entry->index);
|
|
}
|
|
|
|
mac_poll_timer_trig(poll_time, cur);
|
|
|
|
|
|
}
|
|
|
|
|
|
static void mac_data_poll_cb_run(int8_t interface_id)
|
|
{
|
|
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!cur) {
|
|
return;
|
|
}
|
|
nwk_rfd_poll_setups_s *rf_ptr = cur->rfd_poll_info;
|
|
|
|
if (!rf_ptr) {
|
|
return;
|
|
}
|
|
|
|
rf_ptr->poll_req.CoordAddrMode = (unsigned)mac_helper_coordinator_address_get(cur, rf_ptr->poll_req.CoordAddress);
|
|
|
|
if (rf_ptr->poll_req.CoordAddrMode == MAC_ADDR_MODE_NONE) {
|
|
return;
|
|
}
|
|
|
|
memset(&rf_ptr->poll_req.Key, 0, sizeof(mlme_security_t));
|
|
rf_ptr->poll_req.CoordPANId = mac_helper_panid_get(cur);
|
|
|
|
rf_ptr->poll_req.Key.SecurityLevel = mac_helper_default_security_level_get(cur);
|
|
if (rf_ptr->poll_req.Key.SecurityLevel) {
|
|
|
|
rf_ptr->poll_req.Key.KeyIndex = mac_helper_default_key_index_get(cur);
|
|
rf_ptr->poll_req.Key.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur);
|
|
}
|
|
|
|
if (cur->mac_api && cur->mac_api->mlme_req) {
|
|
rf_ptr->pollActive = true;
|
|
cur->mac_api->mlme_req(cur->mac_api, MLME_POLL, (void *) &rf_ptr->poll_req);
|
|
} else {
|
|
tr_error("MAC not registered to interface");
|
|
}
|
|
}
|
|
|
|
int8_t mac_data_poll_host_mode_set(struct protocol_interface_info_entry *cur, net_host_mode_t mode, uint32_t poll_time)
|
|
{
|
|
#ifndef NO_MLE
|
|
if (!cur) {
|
|
return -1;
|
|
}
|
|
int8_t ret_val = 0;
|
|
nwk_rfd_poll_setups_s *rf_ptr = cur->rfd_poll_info;
|
|
//Check IF Bootsrap Ready and type is Host
|
|
if (!rf_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) {
|
|
return -3;
|
|
}
|
|
|
|
|
|
switch (mode) {
|
|
case NET_HOST_SLOW_POLL_MODE:
|
|
//slow mode
|
|
//Check Host current sleep state
|
|
if (rf_ptr->host_mode == NET_HOST_FAST_POLL_MODE || rf_ptr->host_mode == NET_HOST_SLOW_POLL_MODE || rf_ptr->host_mode == NET_HOST_RX_ON_IDLE) {
|
|
uint32_t new_poll_time;
|
|
uint32_t new_Timeout;
|
|
|
|
if (poll_time == 0 || poll_time > 864001) {
|
|
return -2;
|
|
}
|
|
|
|
//Calculate
|
|
//Timeout from Poll Time
|
|
new_Timeout = poll_time * 4;
|
|
|
|
if (new_Timeout < 32) { //Keep Timeout always to 32 seconds min
|
|
new_Timeout = 32;
|
|
}
|
|
|
|
if (new_Timeout != rf_ptr->timeOutInSeconds) {
|
|
rf_ptr->timeOutInSeconds = new_Timeout;
|
|
}
|
|
|
|
rf_ptr->slow_poll_rate_seconds = poll_time;
|
|
|
|
new_poll_time = (poll_time * 1000);
|
|
if (rf_ptr->host_mode == NET_HOST_RX_ON_IDLE) {
|
|
tr_debug("Init Poll timer and period");
|
|
}
|
|
|
|
rf_ptr->nwk_app_poll_time = new_poll_time;
|
|
tr_debug("Enable Poll state slow poll");
|
|
if (host_link_configuration(false, cur) != 0) {
|
|
return -3;
|
|
}
|
|
mac_poll_timer_trig(1, cur);
|
|
rf_ptr->host_mode = NET_HOST_SLOW_POLL_MODE;
|
|
}
|
|
break;
|
|
case NET_HOST_FAST_POLL_MODE:
|
|
//fast mode
|
|
//Check Host current sleep state
|
|
if (rf_ptr->host_mode == NET_HOST_FAST_POLL_MODE || rf_ptr->host_mode == NET_HOST_SLOW_POLL_MODE || rf_ptr->host_mode == NET_HOST_RX_ON_IDLE) {
|
|
if (rf_ptr->host_mode != NET_HOST_FAST_POLL_MODE) {
|
|
tr_debug("Enable Fast poll mode");
|
|
if (rf_ptr->host_mode == NET_HOST_RX_ON_IDLE) {
|
|
tr_debug("Init Poll timer and period");
|
|
if (host_link_configuration(false, cur) != 0) {
|
|
return -3;
|
|
}
|
|
}
|
|
}
|
|
tr_debug("Enable Poll By APP");
|
|
mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, false);
|
|
mac_poll_timer_trig(1, cur);
|
|
rf_ptr->nwk_app_poll_time = 300;
|
|
rf_ptr->host_mode = NET_HOST_FAST_POLL_MODE;
|
|
|
|
}
|
|
break;
|
|
|
|
case NET_HOST_RX_ON_IDLE:
|
|
// Non-sleep mode
|
|
if (rf_ptr->host_mode == NET_HOST_FAST_POLL_MODE || rf_ptr->host_mode == NET_HOST_SLOW_POLL_MODE) {
|
|
if (host_link_configuration(true, cur) == 0) {
|
|
rf_ptr->host_mode = NET_HOST_RX_ON_IDLE;
|
|
rf_ptr->nwk_app_poll_time = 0;
|
|
} else {
|
|
ret_val = -3;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ret_val = -1;
|
|
break;
|
|
}
|
|
|
|
return ret_val;
|
|
#else /* MLE_DRAFT */
|
|
return -1;
|
|
#endif /* MLE_DRAFT */
|
|
}
|
|
|
|
void mac_data_poll_init(struct protocol_interface_info_entry *cur)
|
|
{
|
|
if (!cur) {
|
|
return;
|
|
}
|
|
|
|
if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) {
|
|
if (cur->rfd_poll_info) {
|
|
ns_dyn_mem_free(cur->rfd_poll_info);
|
|
cur->rfd_poll_info = NULL;
|
|
}
|
|
mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, true);
|
|
return;
|
|
}
|
|
|
|
//Allocate and Init
|
|
nwk_rfd_poll_setups_s *rfd_ptr = cur->rfd_poll_info;
|
|
|
|
if (!rfd_ptr) {
|
|
if (mac_data_poll_tasklet_init() < 0) {
|
|
tr_error("Mac data poll tasklet init fail");
|
|
} else {
|
|
rfd_ptr = ns_dyn_mem_alloc(sizeof(nwk_rfd_poll_setups_s));
|
|
if (rfd_ptr) {
|
|
rfd_ptr->timeOutInSeconds = 0;
|
|
rfd_ptr->nwk_parent_poll_fail = false;
|
|
rfd_ptr->protocol_poll = 0;
|
|
rfd_ptr->slow_poll_rate_seconds = 0;
|
|
rfd_ptr->pollActive = false;
|
|
cur->rfd_poll_info = rfd_ptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!rfd_ptr) {
|
|
return;
|
|
}
|
|
|
|
//Set MAc Data poll Fail Callback
|
|
rfd_ptr->pollFailCb = nwk_parent_poll_fail_cb;
|
|
|
|
if (cur->mac_parameters->RxOnWhenIdle) {
|
|
tr_debug("Set Non-Sleepy HOST");
|
|
rfd_ptr->host_mode = NET_HOST_RX_ON_IDLE;
|
|
} else {
|
|
|
|
rfd_ptr->protocol_poll = 1;
|
|
mac_poll_timer_trig(200, cur);
|
|
tr_debug("Set Sleepy HOST configure");
|
|
rfd_ptr->host_mode = NET_HOST_FAST_POLL_MODE;
|
|
rfd_ptr->slow_poll_rate_seconds = 3;
|
|
rfd_ptr->timeOutInSeconds = 32;
|
|
rfd_ptr->nwk_app_poll_time = 300;
|
|
rfd_ptr->nwk_parent_poll_fail = 0;
|
|
}
|
|
}
|