Import Mbed OS hard-float snapshot
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MeshInterfaceNanostack.h"
|
||||
|
||||
#include "include/callback_handler.h"
|
||||
|
||||
static Nanostack::Interface *_handler = NULL;
|
||||
|
||||
void __mesh_handler_c_callback(mesh_connection_status_t state)
|
||||
{
|
||||
|
||||
if (_handler) {
|
||||
_handler->network_handler(state);
|
||||
}
|
||||
}
|
||||
|
||||
void __mesh_handler_set_callback(Nanostack::Interface *handler)
|
||||
{
|
||||
_handler = handler;
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "LoWPANNDInterface.h"
|
||||
#include "include/nd_tasklet.h"
|
||||
#include "callback_handler.h"
|
||||
#include "NanostackLockGuard.h"
|
||||
#include "mesh_system.h"
|
||||
#include "randLIB.h"
|
||||
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "nslp"
|
||||
|
||||
class Nanostack::LoWPANNDInterface final : public Nanostack::MeshInterface {
|
||||
public:
|
||||
nsapi_error_t bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack = IPV6_STACK,
|
||||
bool blocking = true) override;
|
||||
nsapi_error_t bringdown() override;
|
||||
nsapi_error_t get_gateway(SocketAddress *sockAddr) override;
|
||||
|
||||
friend class Nanostack;
|
||||
friend class ::LoWPANNDInterface;
|
||||
private:
|
||||
using MeshInterface::MeshInterface;
|
||||
mesh_error_t init();
|
||||
mesh_error_t mesh_connect();
|
||||
mesh_error_t mesh_disconnect();
|
||||
};
|
||||
|
||||
Nanostack::LoWPANNDInterface *LoWPANNDInterface::get_interface() const
|
||||
{
|
||||
return static_cast<Nanostack::LoWPANNDInterface *>(_interface);
|
||||
}
|
||||
|
||||
nsapi_error_t LoWPANNDInterface::do_initialize()
|
||||
{
|
||||
if (!_interface) {
|
||||
_interface = new (std::nothrow) Nanostack::LoWPANNDInterface(*_phy);
|
||||
if (!_interface) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
_interface->attach(_connection_status_cb);
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::LoWPANNDInterface::bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack, bool blocking)
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
if (register_phy() < 0) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
_blocking = blocking;
|
||||
|
||||
// After the RF is up, we can seed the random from it.
|
||||
randLIB_seed_random();
|
||||
|
||||
mesh_error_t status = init();
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
status = mesh_connect();
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
// Release mutex before blocking
|
||||
nanostack_unlock();
|
||||
|
||||
if (blocking) {
|
||||
// wait connection for ever
|
||||
connect_semaphore.acquire();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::LoWPANNDInterface::bringdown()
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
|
||||
mesh_error_t status = mesh_disconnect();
|
||||
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::LoWPANNDInterface::init()
|
||||
{
|
||||
nd_tasklet_init();
|
||||
__mesh_handler_set_callback(this);
|
||||
interface_id = nd_tasklet_network_init(_device_id);
|
||||
|
||||
if (interface_id == -2) {
|
||||
return MESH_ERROR_PARAM;
|
||||
} else if (interface_id == -3) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
} else if (interface_id < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::LoWPANNDInterface::mesh_connect()
|
||||
{
|
||||
int8_t status = -9; // init to unknown error
|
||||
tr_debug("connect()");
|
||||
|
||||
status = nd_tasklet_connect(&__mesh_handler_c_callback, interface_id);
|
||||
|
||||
if (status >= 0) {
|
||||
return MESH_ERROR_NONE;
|
||||
} else if (status == -1) {
|
||||
return MESH_ERROR_PARAM;
|
||||
} else if (status == -2) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
} else if (status == -3) {
|
||||
return MESH_ERROR_STATE;
|
||||
} else {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::LoWPANNDInterface::mesh_disconnect()
|
||||
{
|
||||
int8_t status = -1;
|
||||
|
||||
status = nd_tasklet_disconnect(true);
|
||||
|
||||
if (status >= 0) {
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::LoWPANNDInterface::get_gateway(SocketAddress *sockAddr)
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
char buf[NSAPI_IPv6_SIZE];
|
||||
if (nd_tasklet_get_router_ip_address(buf, NSAPI_IPv6_SIZE) == 0) {
|
||||
sockAddr->set_ip_address(buf);
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
return NSAPI_ERROR_NO_ADDRESS;
|
||||
}
|
||||
|
||||
bool LoWPANNDInterface::getRouterIpAddress(char *address, int8_t len)
|
||||
{
|
||||
SocketAddress sock_addr;
|
||||
if (_interface->get_gateway(&sock_addr) == NSAPI_ERROR_OK) {
|
||||
strncpy(address, sock_addr.get_ip_address(), len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define LOWPAN 0x2345
|
||||
#if MBED_CONF_NSAPI_DEFAULT_MESH_TYPE == LOWPAN && DEVICE_802_15_4_PHY
|
||||
MBED_WEAK MeshInterface *MeshInterface::get_target_default_instance()
|
||||
{
|
||||
static bool inited;
|
||||
static LoWPANNDInterface interface;
|
||||
singleton_lock();
|
||||
if (!inited) {
|
||||
nsapi_error_t result = interface.initialize(&NanostackRfPhy::get_default_instance());
|
||||
if (result != 0) {
|
||||
tr_error("LoWPANND initialize failed: %d", result);
|
||||
singleton_unlock();
|
||||
return NULL;
|
||||
}
|
||||
inited = true;
|
||||
}
|
||||
singleton_unlock();
|
||||
return &interface;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2019 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MeshInterfaceNanostack.h"
|
||||
#include "Nanostack.h"
|
||||
#include "NanostackLockGuard.h"
|
||||
#include "mesh_system.h"
|
||||
#include "nanostack/net_interface.h"
|
||||
#include "thread_management_if.h"
|
||||
#include "ip6string.h"
|
||||
#include "mbed_error.h"
|
||||
|
||||
nsapi_error_t Nanostack::Interface::get_ip_address(SocketAddress *address)
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
uint8_t binary_ipv6[16];
|
||||
|
||||
if (arm_net_address_get(interface_id, ADDR_IPV6_GP, binary_ipv6) == 0) {
|
||||
address->set_ip_bytes(binary_ipv6, NSAPI_IPv6);
|
||||
return NSAPI_ERROR_OK;
|
||||
} else {
|
||||
return NSAPI_ERROR_NO_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
char *Nanostack::Interface::get_mac_address(char *buf, nsapi_size_t buflen)
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
link_layer_address_s addr;
|
||||
if (buflen >= 24 && arm_nwk_mac_address_read(interface_id, &addr) == 0) {
|
||||
snprintf(buf, buflen, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", addr.mac_long[0], addr.mac_long[1], addr.mac_long[2], addr.mac_long[3], addr.mac_long[4], addr.mac_long[5], addr.mac_long[6], addr.mac_long[7]);
|
||||
return buf;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::Interface::get_netmask(SocketAddress *address)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::Interface::get_gateway(SocketAddress *address)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_connection_status_t Nanostack::Interface::get_connection_status() const
|
||||
{
|
||||
return _connect_status;
|
||||
}
|
||||
|
||||
void Nanostack::Interface::attach(
|
||||
mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
{
|
||||
_connection_status_cb = status_cb;
|
||||
}
|
||||
|
||||
Nanostack::Interface::Interface(NanostackPhy &phy) : interface_phy(phy)
|
||||
{
|
||||
mesh_system_init();
|
||||
}
|
||||
|
||||
int InterfaceNanostack::connect()
|
||||
{
|
||||
nsapi_error_t error = do_initialize();
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
return _interface->bringup(false, NULL, NULL, NULL, IPV6_STACK, _blocking);
|
||||
}
|
||||
|
||||
int InterfaceNanostack::disconnect()
|
||||
{
|
||||
if (!_interface) {
|
||||
return NSAPI_ERROR_NO_CONNECTION;
|
||||
}
|
||||
return _interface->bringdown();
|
||||
}
|
||||
|
||||
char *Nanostack::MeshInterface::get_interface_name(char *buf)
|
||||
{
|
||||
if (interface_id < 0) {
|
||||
return NULL;
|
||||
}
|
||||
sprintf(buf, "MES%d", interface_id);
|
||||
return buf;
|
||||
};
|
||||
|
||||
nsapi_error_t MeshInterfaceNanostack::initialize(NanostackRfPhy *phy)
|
||||
{
|
||||
if (_phy && phy && _phy != phy) {
|
||||
error("Phy already set");
|
||||
return NSAPI_ERROR_IS_CONNECTED;
|
||||
}
|
||||
if (phy) {
|
||||
_phy = phy;
|
||||
}
|
||||
if (_phy) {
|
||||
return do_initialize();
|
||||
} else {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
void Nanostack::Interface::network_handler(mesh_connection_status_t status)
|
||||
{
|
||||
if (_blocking) {
|
||||
if (_connect_status == NSAPI_STATUS_CONNECTING
|
||||
&& (status == MESH_CONNECTED || status == MESH_CONNECTED_LOCAL
|
||||
|| status == MESH_CONNECTED_GLOBAL)) {
|
||||
connect_semaphore.release();
|
||||
} else if (status == MESH_DISCONNECTED) {
|
||||
disconnect_semaphore.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (status == MESH_CONNECTED) {
|
||||
uint8_t temp_ipv6_global[16];
|
||||
uint8_t temp_ipv6_local[16];
|
||||
if (arm_net_address_get(interface_id, ADDR_IPV6_LL, temp_ipv6_local) == 0) {
|
||||
_connect_status = NSAPI_STATUS_LOCAL_UP;
|
||||
}
|
||||
if (arm_net_address_get(interface_id, ADDR_IPV6_GP, temp_ipv6_global) == 0
|
||||
&& (memcmp(temp_ipv6_global, temp_ipv6_local, 16) != 0)) {
|
||||
_connect_status = NSAPI_STATUS_GLOBAL_UP;
|
||||
}
|
||||
} else if (status == MESH_CONNECTED_LOCAL) {
|
||||
_connect_status = NSAPI_STATUS_LOCAL_UP;
|
||||
} else if (status == MESH_CONNECTED_GLOBAL) {
|
||||
_connect_status = NSAPI_STATUS_GLOBAL_UP;
|
||||
} else if (status == MESH_BOOTSTRAP_STARTED || status == MESH_BOOTSTRAP_FAILED) {
|
||||
_connect_status = NSAPI_STATUS_CONNECTING;
|
||||
} else {
|
||||
_connect_status = NSAPI_STATUS_DISCONNECTED;
|
||||
}
|
||||
|
||||
if (_connection_status_cb && _previous_connection_status != _connect_status
|
||||
&& (_previous_connection_status != NSAPI_STATUS_GLOBAL_UP || status != MESH_BOOTSTRAP_STARTED)
|
||||
&& (_previous_connection_status != NSAPI_STATUS_CONNECTING || status != MESH_BOOTSTRAP_START_FAILED)) {
|
||||
_connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
|
||||
}
|
||||
_previous_connection_status = _connect_status;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::Interface::register_phy()
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
|
||||
if (_device_id < 0) {
|
||||
_device_id = interface_phy.phy_register();
|
||||
}
|
||||
if (_device_id < 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
Nanostack *InterfaceNanostack::get_stack()
|
||||
{
|
||||
return &Nanostack::get_instance();
|
||||
}
|
||||
|
||||
nsapi_error_t InterfaceNanostack::get_ip_address(SocketAddress *address)
|
||||
{
|
||||
if (_interface->get_ip_address(address) == NSAPI_ERROR_OK) {
|
||||
ip_addr = address->get_ip_address();
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_NO_ADDRESS;
|
||||
}
|
||||
|
||||
const char *InterfaceNanostack::get_mac_address()
|
||||
{
|
||||
if (_interface->get_mac_address(mac_addr_str, sizeof(mac_addr_str))) {
|
||||
return mac_addr_str;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsapi_connection_status_t InterfaceNanostack::get_connection_status() const
|
||||
{
|
||||
if (_interface) {
|
||||
return _interface->get_connection_status();
|
||||
} else {
|
||||
return NSAPI_STATUS_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
void InterfaceNanostack::attach(
|
||||
mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
{
|
||||
_connection_status_cb = status_cb;
|
||||
if (_interface) {
|
||||
_interface->attach(status_cb);
|
||||
}
|
||||
}
|
||||
|
||||
nsapi_error_t InterfaceNanostack::set_blocking(bool blocking)
|
||||
{
|
||||
_blocking = blocking;
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t InterfaceNanostack::set_file_system_root_path(const char *root_path)
|
||||
{
|
||||
int status = mesh_system_set_file_system_root_path(root_path);
|
||||
|
||||
if (status == 0) {
|
||||
return MESH_ERROR_NONE;
|
||||
} else if (status == -2) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
}
|
||||
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
#if !DEVICE_802_15_4_PHY
|
||||
MBED_WEAK MeshInterface *MeshInterface::get_target_default_instance()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2017 ARM Limited. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "NanostackEthernetInterface.h"
|
||||
#include "NanostackEthernetPhy.h"
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "arm_hal_phy.h"
|
||||
#include "EMAC.h"
|
||||
#include "enet_tasklet.h"
|
||||
#include "mbed_interface.h"
|
||||
|
||||
class EMACPhy : public NanostackEthernetPhy {
|
||||
public:
|
||||
EMACPhy(NanostackMemoryManager &mem, EMAC &m);
|
||||
int8_t phy_register() override;
|
||||
void get_mac_address(uint8_t *mac) override;
|
||||
void set_mac_address(uint8_t *mac) override;
|
||||
|
||||
int8_t address_write(phy_address_type_e, uint8_t *);
|
||||
int8_t tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow);
|
||||
|
||||
void emac_phy_rx(emac_mem_buf_t *mem);
|
||||
|
||||
private:
|
||||
NanostackMemoryManager &memory_manager;
|
||||
EMAC &emac;
|
||||
uint8_t mac_addr[6];
|
||||
int8_t device_id = -1;
|
||||
phy_device_driver_s phy;
|
||||
};
|
||||
|
||||
// GAH! no handles on the callback. Force a single interface
|
||||
static EMACPhy *single_phy;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static int8_t emac_phy_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
|
||||
{
|
||||
return single_phy->address_write(address_type, address_ptr);
|
||||
}
|
||||
|
||||
static int8_t emac_phy_interface_state_control(phy_interface_state_e, uint8_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int8_t emac_phy_tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow)
|
||||
{
|
||||
return single_phy->tx(data_ptr, data_len, tx_handle, data_flow);
|
||||
}
|
||||
|
||||
EMACPhy::EMACPhy(NanostackMemoryManager &mem, EMAC &m) : memory_manager(mem), emac(m)
|
||||
{
|
||||
/* Same default address logic as lwIP glue uses */
|
||||
#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
|
||||
mac_addr[0] = MBED_MAC_ADDR_0;
|
||||
mac_addr[1] = MBED_MAC_ADDR_1;
|
||||
mac_addr[2] = MBED_MAC_ADDR_2;
|
||||
mac_addr[3] = MBED_MAC_ADDR_3;
|
||||
mac_addr[4] = MBED_MAC_ADDR_4;
|
||||
mac_addr[5] = MBED_MAC_ADDR_5;
|
||||
#else
|
||||
mbed_mac_address((char *) mac_addr);
|
||||
#endif
|
||||
/* We have a default MAC address, so do don't force them to supply one */
|
||||
/* They may or may not update hwaddr with their address */
|
||||
emac.get_hwaddr(mac_addr);
|
||||
}
|
||||
|
||||
|
||||
void EMACPhy::emac_phy_rx(emac_mem_buf_t *mem)
|
||||
{
|
||||
const uint8_t *ptr = NULL;
|
||||
uint8_t *tmpbuf = NULL;
|
||||
uint32_t total_len;
|
||||
|
||||
if (memory_manager.get_next(mem) == NULL) {
|
||||
// Easy contiguous case
|
||||
ptr = static_cast<const uint8_t *>(memory_manager.get_ptr(mem));
|
||||
total_len = memory_manager.get_len(mem);
|
||||
} else {
|
||||
// Nanostack can't accept chunked data - make temporary contiguous copy
|
||||
total_len = memory_manager.get_total_len(mem);
|
||||
ptr = tmpbuf = static_cast<uint8_t *>(ns_dyn_mem_temporary_alloc(total_len));
|
||||
if (tmpbuf) {
|
||||
memory_manager.copy_from_buf(tmpbuf, total_len, mem);
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr && phy.phy_rx_cb) {
|
||||
phy.phy_rx_cb(ptr, total_len, 0xff, 0, device_id);
|
||||
}
|
||||
ns_dyn_mem_free(tmpbuf);
|
||||
memory_manager.free(mem);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int8_t EMACPhy::address_write(phy_address_type_e address_type, uint8_t *address_ptr)
|
||||
{
|
||||
if (address_type != PHY_MAC_48BIT) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(mac_addr, address_ptr, 6);
|
||||
emac.set_hwaddr(address_ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t EMACPhy::tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow)
|
||||
{
|
||||
emac_mem_buf_t *mem = memory_manager.alloc_pool(data_len, 0);
|
||||
if (!mem) {
|
||||
return -1;
|
||||
}
|
||||
memory_manager.copy_to_buf(mem, data_ptr, data_len);
|
||||
|
||||
// They take ownership - their responsibility to free
|
||||
emac.link_out(mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t EMACPhy::phy_register()
|
||||
{
|
||||
if (device_id < 0) {
|
||||
|
||||
phy.PHY_MAC = mac_addr;
|
||||
phy.address_write = emac_phy_address_write;
|
||||
phy.driver_description = const_cast<char *>("ETH");
|
||||
phy.link_type = PHY_LINK_ETHERNET_TYPE;
|
||||
phy.phy_MTU = 0;
|
||||
phy.phy_header_length = 0;
|
||||
phy.phy_tail_length = 0;
|
||||
phy.state_control = emac_phy_interface_state_control;
|
||||
phy.tx = emac_phy_tx;
|
||||
phy.phy_rx_cb = NULL;
|
||||
phy.phy_tx_done_cb = NULL;
|
||||
|
||||
emac.set_memory_manager(memory_manager);
|
||||
emac.set_link_input_cb(mbed::callback(this, &EMACPhy::emac_phy_rx));
|
||||
emac.set_link_state_cb(enet_tasklet_link_state_changed);
|
||||
|
||||
if (!emac.power_up()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
phy.phy_MTU = emac.get_mtu_size();
|
||||
/* Set the address - this could be either board default, what they
|
||||
* told us with EMAC::get_mac_address, or something manually specified
|
||||
* with EMACPhy::set_mac_address
|
||||
*/
|
||||
emac.set_hwaddr(mac_addr);
|
||||
|
||||
emac.set_all_multicast(true);
|
||||
|
||||
device_id = arm_net_phy_register(&phy);
|
||||
// driver_readiness_status_callback = driver_status_cb;
|
||||
|
||||
if (device_id < 0) {
|
||||
//tr_error("Ethernet Driver failed to register with Stack. RetCode=%i", eth_driver_enabled);
|
||||
//driver_readiness_status_callback(0, eth_interface_id);
|
||||
emac.power_down();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return device_id;
|
||||
}
|
||||
|
||||
void EMACPhy::get_mac_address(uint8_t *mac)
|
||||
{
|
||||
memcpy(mac, mac_addr, sizeof mac_addr);
|
||||
}
|
||||
|
||||
void EMACPhy::set_mac_address(uint8_t *mac)
|
||||
{
|
||||
memcpy(mac_addr, mac, sizeof mac_addr);
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::add_ethernet_interface(EMAC &emac, bool default_if, Nanostack::EthernetInterface **interface_out, const uint8_t *mac_addr)
|
||||
{
|
||||
if (single_phy) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
single_phy = new (std::nothrow) EMACPhy(this->memory_manager, emac);
|
||||
if (!single_phy) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (mac_addr) {
|
||||
single_phy->set_mac_address(const_cast<uint8_t *>(mac_addr));
|
||||
}
|
||||
|
||||
Nanostack::EthernetInterface *interface;
|
||||
|
||||
interface = new (std::nothrow) Nanostack::EthernetInterface(*single_phy);
|
||||
if (!interface) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
nsapi_error_t err = interface->initialize();
|
||||
if (err) {
|
||||
delete interface;
|
||||
return err;
|
||||
}
|
||||
|
||||
*interface_out = interface;
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out)
|
||||
{
|
||||
Nanostack::EthernetInterface *interface;
|
||||
nsapi_error_t err = add_ethernet_interface(emac, default_if, &interface);
|
||||
*interface_out = interface;
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "NanostackEthernetInterface.h"
|
||||
#include "mesh_system.h"
|
||||
#include "callback_handler.h"
|
||||
#include "enet_tasklet.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
nsapi_error_t Nanostack::EthernetInterface::initialize()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
if (register_phy() < 0) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t NanostackEthernetInterface::initialize(NanostackEthernetPhy *phy)
|
||||
{
|
||||
if (_interface) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
_interface = new (std::nothrow) Nanostack::EthernetInterface(*phy);
|
||||
if (!_interface) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
return get_interface()->initialize();
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::EthernetInterface::bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack, bool blocking)
|
||||
{
|
||||
if (stack == IPV4_STACK) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nanostack_lock();
|
||||
_blocking = blocking;
|
||||
if (interface_id < 0) {
|
||||
enet_tasklet_init();
|
||||
__mesh_handler_set_callback(this);
|
||||
interface_id = enet_tasklet_network_init(_device_id);
|
||||
}
|
||||
int8_t status = -1;
|
||||
if (interface_id >= 0) {
|
||||
status = enet_tasklet_connect(&__mesh_handler_c_callback, interface_id);
|
||||
}
|
||||
nanostack_unlock();
|
||||
|
||||
if (status == -1) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
} else if (status == -2) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
} else if (status == -3) {
|
||||
return NSAPI_ERROR_ALREADY;
|
||||
} else if (status != 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (blocking) {
|
||||
bool acquired = connect_semaphore.try_acquire_for(30s);
|
||||
|
||||
if (!acquired) {
|
||||
return NSAPI_ERROR_DHCP_FAILURE; // sort of...
|
||||
}
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t NanostackEthernetInterface::do_initialize()
|
||||
{
|
||||
if (!_interface) {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::EthernetInterface::bringdown()
|
||||
{
|
||||
nanostack_lock();
|
||||
int8_t status = enet_tasklet_disconnect(true);
|
||||
nanostack_unlock();
|
||||
|
||||
if (status == -1) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
} else if (status == -2) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
} else if (status == -3) {
|
||||
return NSAPI_ERROR_ALREADY;
|
||||
} else if (status != 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (_blocking) {
|
||||
bool acquired = disconnect_semaphore.try_acquire_for(30s);
|
||||
|
||||
if (!acquired) {
|
||||
return NSAPI_ERROR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
char *Nanostack::EthernetInterface::get_interface_name(char *buf)
|
||||
{
|
||||
if (interface_id < 0) {
|
||||
return NULL;
|
||||
}
|
||||
sprintf(buf, "ETH%d", interface_id);
|
||||
return buf;
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2016 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "nsdynmemLIB.h"
|
||||
#include <string.h>
|
||||
#include "mbed_assert.h"
|
||||
#include "NanostackMemoryManager.h"
|
||||
|
||||
struct ns_stack_mem_t {
|
||||
ns_stack_mem_t *next;
|
||||
void *payload;
|
||||
uint32_t len;
|
||||
uint8_t mem[];
|
||||
};
|
||||
|
||||
emac_mem_buf_t *NanostackMemoryManager::alloc_heap(uint32_t size, uint32_t align)
|
||||
{
|
||||
ns_stack_mem_t *buf = static_cast<ns_stack_mem_t *>(ns_dyn_mem_temporary_alloc(sizeof(ns_stack_mem_t) + size + align));
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf->next = NULL;
|
||||
buf->payload = buf->mem;
|
||||
buf->len = size;
|
||||
|
||||
if (align) {
|
||||
uint32_t remainder = reinterpret_cast<uint32_t>(buf->payload) % align;
|
||||
if (remainder) {
|
||||
uint32_t offset = align - remainder;
|
||||
if (offset >= align) {
|
||||
offset = align;
|
||||
}
|
||||
|
||||
buf->payload = static_cast<char *>(buf->payload) + offset;
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<emac_mem_buf_t *>(buf);
|
||||
}
|
||||
|
||||
emac_mem_buf_t *NanostackMemoryManager::alloc_pool(uint32_t size, uint32_t align)
|
||||
{
|
||||
return alloc_heap(size, align);
|
||||
}
|
||||
|
||||
uint32_t NanostackMemoryManager::get_pool_alloc_unit(uint32_t align) const
|
||||
{
|
||||
return 1536; // arbitrary nicely-aligned number big enough for Ethernet
|
||||
}
|
||||
|
||||
void NanostackMemoryManager::free(emac_mem_buf_t *mem)
|
||||
{
|
||||
ns_dyn_mem_free(mem);
|
||||
}
|
||||
|
||||
uint32_t NanostackMemoryManager::get_total_len(const emac_mem_buf_t *buf) const
|
||||
{
|
||||
const ns_stack_mem_t *mem = static_cast<const ns_stack_mem_t *>(buf);
|
||||
uint32_t total = 0;
|
||||
|
||||
while (mem) {
|
||||
total += mem->len;
|
||||
mem = mem->next;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
void NanostackMemoryManager::copy(emac_mem_buf_t *to, const emac_mem_buf_t *from)
|
||||
{
|
||||
ns_stack_mem_t *to_mem = static_cast<ns_stack_mem_t *>(to);
|
||||
const ns_stack_mem_t *from_mem = static_cast<const ns_stack_mem_t *>(from);
|
||||
MBED_ASSERT(get_total_len(to) >= get_total_len(from));
|
||||
|
||||
uint32_t to_offset = 0;
|
||||
uint32_t from_offset = 0;
|
||||
while (from_mem) {
|
||||
uint32_t to_avail = to_mem->len - to_offset;
|
||||
uint32_t from_avail = from_mem->len - from_offset;
|
||||
uint32_t chunk = to_avail < from_avail ? to_avail : from_avail;
|
||||
uint8_t *to_ptr = static_cast<uint8_t *>(to_mem->payload) + to_offset;
|
||||
const uint8_t *from_ptr = static_cast<const uint8_t *>(from_mem->payload) + from_offset;
|
||||
memcpy(to_ptr, from_ptr, chunk);
|
||||
to_offset += chunk;
|
||||
if (to_offset == to_mem->len) {
|
||||
to_mem = to_mem->next;
|
||||
to_offset = 0;
|
||||
}
|
||||
from_offset += chunk;
|
||||
if (from_offset == from_mem->len) {
|
||||
from_mem = from_mem->next;
|
||||
from_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NanostackMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf)
|
||||
{
|
||||
ns_stack_mem_t *to_mem = static_cast<ns_stack_mem_t *>(to_buf);
|
||||
ns_stack_mem_t *cat_mem = static_cast<ns_stack_mem_t *>(cat_buf);
|
||||
|
||||
while (to_mem->next) {
|
||||
to_mem = to_mem->next;
|
||||
}
|
||||
|
||||
to_mem->next = cat_mem;
|
||||
}
|
||||
|
||||
emac_mem_buf_t *NanostackMemoryManager::get_next(const emac_mem_buf_t *buf) const
|
||||
{
|
||||
return static_cast<const ns_stack_mem_t *>(buf)->next;
|
||||
}
|
||||
|
||||
void *NanostackMemoryManager::get_ptr(const emac_mem_buf_t *buf) const
|
||||
{
|
||||
return static_cast<const ns_stack_mem_t *>(buf)->payload;
|
||||
}
|
||||
|
||||
uint32_t NanostackMemoryManager::get_len(const emac_mem_buf_t *buf) const
|
||||
{
|
||||
return static_cast<const ns_stack_mem_t *>(buf)->len;
|
||||
}
|
||||
|
||||
void NanostackMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len)
|
||||
{
|
||||
ns_stack_mem_t *mem = static_cast<ns_stack_mem_t *>(buf);
|
||||
|
||||
mem->len = len;
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "NanostackPPPInterface.h"
|
||||
#include "NanostackPPPPhy.h"
|
||||
#include "PPP.h"
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "arm_hal_phy.h"
|
||||
#include "mbed_interface.h"
|
||||
#include "mesh_system.h"
|
||||
#include "callback_handler.h"
|
||||
#include "enet_tasklet.h"
|
||||
#include "ip6string.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class PPPPhy : public NanostackPPPPhy {
|
||||
public:
|
||||
PPPPhy(NanostackMemoryManager &mem, PPP &m);
|
||||
int8_t phy_register() override;
|
||||
|
||||
void phy_power_on();
|
||||
void phy_power_off();
|
||||
|
||||
void get_iid64(uint8_t *iid64) override;
|
||||
uint16_t get_mtu() override;
|
||||
|
||||
void set_link_state_change_cb(link_state_change_cb_t cb) override;
|
||||
|
||||
int8_t tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow);
|
||||
|
||||
void ppp_phy_rx(net_stack_mem_buf_t *mem);
|
||||
void link_state_cb(bool up);
|
||||
|
||||
private:
|
||||
NanostackMemoryManager &memory_manager;
|
||||
PPP &ppp;
|
||||
uint8_t iid64[8];
|
||||
link_state_change_cb_t link_state_change_cb = nullptr;
|
||||
bool active = false;
|
||||
bool powered_up = false;
|
||||
int8_t device_id = -1;
|
||||
phy_device_driver_s phy;
|
||||
};
|
||||
|
||||
nsapi_error_t Nanostack::PPPInterface::initialize()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
if (register_phy() < 0) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::PPPInterface::bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack, bool blocking)
|
||||
{
|
||||
if (stack == IPV4_STACK) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
_blocking = blocking;
|
||||
|
||||
if (link_state_up) {
|
||||
connect_enet_tasklet();
|
||||
}
|
||||
|
||||
if (blocking) {
|
||||
uint8_t retries = 10;
|
||||
while (_connect_status != NSAPI_STATUS_GLOBAL_UP) {
|
||||
bool acquired = connect_semaphore.try_acquire_for(3s);
|
||||
if (!acquired && retries-- == 0) {
|
||||
return NSAPI_ERROR_DHCP_FAILURE; // sort of...
|
||||
}
|
||||
// Not up until global up
|
||||
if (_connect_status == NSAPI_STATUS_LOCAL_UP) {
|
||||
_connect_status = NSAPI_STATUS_CONNECTING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::PPPInterface::connect_enet_tasklet()
|
||||
{
|
||||
if (enet_tasklet_connected) {
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
enet_tasklet_connected = true;
|
||||
|
||||
nanostack_lock();
|
||||
|
||||
if (interface_id < 0) {
|
||||
enet_tasklet_init();
|
||||
__mesh_handler_set_callback(this);
|
||||
interface_id = enet_tasklet_ppp_network_init(_device_id);
|
||||
}
|
||||
int8_t status = -1;
|
||||
if (interface_id >= 0) {
|
||||
status = enet_tasklet_connect(&__mesh_handler_c_callback, interface_id);
|
||||
}
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
if (status == -1) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
} else if (status == -2) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
} else if (status == -3) {
|
||||
return NSAPI_ERROR_ALREADY;
|
||||
} else if (status != 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::PPPInterface::bringdown()
|
||||
{
|
||||
nanostack_lock();
|
||||
int8_t status = enet_tasklet_disconnect(true);
|
||||
enet_tasklet_connected = false;
|
||||
nanostack_unlock();
|
||||
|
||||
if (status == -1) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
} else if (status == -2) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
} else if (status == -3) {
|
||||
return NSAPI_ERROR_ALREADY;
|
||||
} else if (status != 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (_blocking) {
|
||||
bool acquired = disconnect_semaphore.try_acquire_for(30s);
|
||||
|
||||
if (!acquired) {
|
||||
return NSAPI_ERROR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
void Nanostack::PPPInterface::link_state_changed(bool up)
|
||||
{
|
||||
link_state_up = up;
|
||||
|
||||
// If application callback is set
|
||||
if (link_state_cb) {
|
||||
link_state_cb(up, _device_id);
|
||||
} else {
|
||||
if (up) {
|
||||
connect_enet_tasklet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Nanostack::PPPInterface::set_link_state_changed_callback(link_state_cb_t new_link_state_cb)
|
||||
{
|
||||
link_state_cb = new_link_state_cb;
|
||||
}
|
||||
|
||||
char *Nanostack::PPPInterface::get_interface_name(char *buf)
|
||||
{
|
||||
if (interface_id < 0) {
|
||||
return NULL;
|
||||
}
|
||||
sprintf(buf, "PPP%d", interface_id);
|
||||
return buf;
|
||||
};
|
||||
|
||||
// GAH! no handles on the callback. Force a single interface
|
||||
static PPPPhy *single_phy;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static int8_t ppp_phy_interface_state_control(phy_interface_state_e, uint8_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int8_t ppp_phy_tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow)
|
||||
{
|
||||
return single_phy->tx(data_ptr, data_len, tx_handle, data_flow);
|
||||
}
|
||||
|
||||
PPPPhy::PPPPhy(NanostackMemoryManager &mem, PPP &m) : memory_manager(mem), ppp(m)
|
||||
{
|
||||
}
|
||||
|
||||
void PPPPhy::ppp_phy_rx(net_stack_mem_buf_t *mem)
|
||||
{
|
||||
if (!active) {
|
||||
memory_manager.free(mem);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *ptr = NULL;
|
||||
uint8_t *tmpbuf = NULL;
|
||||
uint32_t total_len;
|
||||
|
||||
if (memory_manager.get_next(mem) == NULL) {
|
||||
// Easy contiguous case
|
||||
ptr = static_cast<const uint8_t *>(memory_manager.get_ptr(mem));
|
||||
total_len = memory_manager.get_len(mem);
|
||||
} else {
|
||||
// Nanostack can't accept chunked data - make temporary contiguous copy
|
||||
total_len = memory_manager.get_total_len(mem);
|
||||
ptr = tmpbuf = static_cast<uint8_t *>(ns_dyn_mem_temporary_alloc(total_len));
|
||||
if (tmpbuf) {
|
||||
memory_manager.copy_from_buf(tmpbuf, total_len, mem);
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr && phy.phy_rx_cb) {
|
||||
phy.phy_rx_cb(ptr, total_len, 0xff, 0, device_id);
|
||||
}
|
||||
ns_dyn_mem_free(tmpbuf);
|
||||
memory_manager.free(mem);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int8_t PPPPhy::tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow)
|
||||
{
|
||||
if (!active) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_stack_mem_buf_t *mem = memory_manager.alloc_pool(data_len, 0);
|
||||
if (!mem) {
|
||||
return -1;
|
||||
}
|
||||
memory_manager.copy_to_buf(mem, data_ptr, data_len);
|
||||
|
||||
// They take ownership - their responsibility to free
|
||||
ppp.link_out(mem, IPV6_STACK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t PPPPhy::phy_register()
|
||||
{
|
||||
active = true;
|
||||
|
||||
if (device_id < 0) {
|
||||
phy.PHY_MAC = iid64;
|
||||
phy.address_write = NULL;
|
||||
phy.driver_description = const_cast<char *>("PPP");
|
||||
phy.link_type = PHY_LINK_PPP;
|
||||
phy.phy_MTU = 0;
|
||||
phy.phy_header_length = 0;
|
||||
phy.phy_tail_length = 0;
|
||||
phy.state_control = ppp_phy_interface_state_control;
|
||||
phy.tx = ppp_phy_tx;
|
||||
phy.phy_rx_cb = NULL;
|
||||
phy.phy_tx_done_cb = NULL;
|
||||
|
||||
ppp.set_memory_manager(memory_manager);
|
||||
ppp.set_link_input_cb(mbed::callback(this, &PPPPhy::ppp_phy_rx));
|
||||
if (link_state_change_cb) {
|
||||
ppp.set_link_state_cb(mbed::callback(this, &PPPPhy::link_state_cb));
|
||||
}
|
||||
|
||||
device_id = arm_net_phy_register(&phy);
|
||||
|
||||
if (device_id < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return device_id;
|
||||
}
|
||||
|
||||
void PPPPhy::phy_power_on()
|
||||
{
|
||||
if (!powered_up) {
|
||||
if (!ppp.power_up()) {
|
||||
return;
|
||||
}
|
||||
phy.phy_MTU = get_mtu();
|
||||
powered_up = true;
|
||||
active = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PPPPhy::phy_power_off()
|
||||
{
|
||||
if (powered_up) {
|
||||
ppp.power_down();
|
||||
powered_up = false;
|
||||
}
|
||||
active = false;
|
||||
}
|
||||
|
||||
void PPPPhy::set_link_state_change_cb(link_state_change_cb_t cb)
|
||||
{
|
||||
link_state_change_cb = cb;
|
||||
}
|
||||
|
||||
void PPPPhy::link_state_cb(bool up)
|
||||
{
|
||||
// Read negotiated parameters from PPP
|
||||
if (up) {
|
||||
get_iid64(iid64);
|
||||
}
|
||||
|
||||
// Call upper level callback if set
|
||||
if (link_state_change_cb) {
|
||||
link_state_change_cb(up);
|
||||
}
|
||||
}
|
||||
|
||||
void PPPPhy::get_iid64(uint8_t *iid64)
|
||||
{
|
||||
if (!iid64) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read link local IPv6 address
|
||||
const nsapi_addr_t *ipv6_ll_addr = ppp.get_ip_address(NSAPI_IPv6);
|
||||
if (ipv6_ll_addr) {
|
||||
memcpy(iid64, &ipv6_ll_addr->bytes[8], 8);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t PPPPhy::get_mtu()
|
||||
{
|
||||
return ppp.get_mtu_size();
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::add_ppp_interface(PPP &ppp, bool default_if, Nanostack::PPPInterface **interface_out)
|
||||
{
|
||||
if (!single_phy) {
|
||||
single_phy = new (std::nothrow) PPPPhy(this->memory_manager, ppp);
|
||||
if (!single_phy) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
static Nanostack::PPPInterface *interface = NULL;
|
||||
|
||||
if (interface == NULL) {
|
||||
interface = new (std::nothrow) Nanostack::PPPInterface(*single_phy);
|
||||
if (!interface) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
single_phy->set_link_state_change_cb(mbed::callback(interface, &Nanostack::PPPInterface::link_state_changed));
|
||||
}
|
||||
|
||||
interface->initialize();
|
||||
|
||||
single_phy->phy_power_on();
|
||||
|
||||
*interface_out = interface;
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::add_ppp_interface(PPP &ppp, bool default_if, OnboardNetworkStack::Interface **interface_out)
|
||||
{
|
||||
Nanostack::PPPInterface *interface;
|
||||
nsapi_error_t err = add_ppp_interface(ppp, default_if, &interface);
|
||||
*interface_out = interface;
|
||||
return err;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::remove_ppp_interface(OnboardNetworkStack::Interface **interface_out)
|
||||
{
|
||||
single_phy->phy_power_off();
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
283
connectivity/nanostack/mbed-mesh-api/source/ThreadInterface.cpp
Normal file
283
connectivity/nanostack/mbed-mesh-api/source/ThreadInterface.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2018 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ThreadInterface.h"
|
||||
#include "include/thread_tasklet.h"
|
||||
#include "callback_handler.h"
|
||||
#include "mesh_system.h"
|
||||
#include "randLIB.h"
|
||||
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "nsth"
|
||||
|
||||
class Nanostack::ThreadInterface : public Nanostack::MeshInterface {
|
||||
public:
|
||||
nsapi_error_t bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack = IPV6_STACK,
|
||||
bool blocking = true) override;
|
||||
nsapi_error_t bringdown() override;
|
||||
friend class Nanostack;
|
||||
friend class ::ThreadInterface;
|
||||
private:
|
||||
ThreadInterface(NanostackRfPhy &phy) : MeshInterface(phy), eui64_set(false) { }
|
||||
|
||||
/*
|
||||
* \brief Initialization of the interface.
|
||||
* \return MESH_ERROR_NONE on success.
|
||||
* \return MESH_ERROR_PARAM when input parameters are illegal (also in case when RF device is already associated to other interface)
|
||||
* \return MESH_ERROR_MEMORY in case of memory error
|
||||
* \return MESH_ERROR_UNKNOWN in other error cases
|
||||
*/
|
||||
mesh_error_t init();
|
||||
/**
|
||||
* \brief Connect interface to the mesh network
|
||||
* \return MESH_ERROR_NONE on success.
|
||||
* \return MESH_ERROR_PARAM in case of illegal parameters.
|
||||
* \return MESH_ERROR_MEMORY in case of memory error.
|
||||
* \return MESH_ERROR_STATE if interface is already connected to network.
|
||||
* \return MESH_ERROR_UNKNOWN in case of unspecified error.
|
||||
* */
|
||||
mesh_error_t mesh_connect();
|
||||
|
||||
/**
|
||||
* \brief Disconnect interface from the mesh network
|
||||
* \return MESH_ERROR_NONE on success.
|
||||
* \return MESH_ERROR_UNKNOWN in case of error.
|
||||
* */
|
||||
mesh_error_t mesh_disconnect();
|
||||
|
||||
/**
|
||||
* \brief Sets the eui64 for the device configuration.
|
||||
* By default this value is read from the radio driver.
|
||||
* The value must be set before calling the connect function.
|
||||
* */
|
||||
void device_eui64_set(const uint8_t *eui64);
|
||||
|
||||
/**
|
||||
* \brief Reads the eui64 from the device configuration.
|
||||
* */
|
||||
void device_eui64_get(uint8_t *eui64);
|
||||
|
||||
/**
|
||||
* \brief sets the PSKd for the device configuration.
|
||||
* The default value is overwritten, which is defined in the mbed_lib.json file in the mesh-api
|
||||
* The value must be set before calling the connect function.
|
||||
* \return MESH_ERROR_NONE on success.
|
||||
* \return MESH_ERROR_PARAM in case of illegal parameters.
|
||||
* \return MESH_ERROR_MEMORY in case of memory error.
|
||||
* */
|
||||
|
||||
mesh_error_t device_pskd_set(const char *pskd);
|
||||
|
||||
bool eui64_set;
|
||||
};
|
||||
|
||||
Nanostack::ThreadInterface *ThreadInterface::get_interface() const
|
||||
{
|
||||
return static_cast<Nanostack::ThreadInterface *>(_interface);
|
||||
}
|
||||
|
||||
nsapi_error_t ThreadInterface::do_initialize()
|
||||
{
|
||||
if (!_interface) {
|
||||
_interface = new (std::nothrow) Nanostack::ThreadInterface(*_phy);
|
||||
if (!_interface) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
_interface->attach(_connection_status_cb);
|
||||
}
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::ThreadInterface::bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack, bool blocking)
|
||||
{
|
||||
if (_connect_status == NSAPI_STATUS_GLOBAL_UP || _connect_status == NSAPI_STATUS_LOCAL_UP) {
|
||||
return NSAPI_ERROR_IS_CONNECTED;
|
||||
} else if (_connect_status == NSAPI_STATUS_CONNECTING) {
|
||||
return NSAPI_ERROR_ALREADY;
|
||||
}
|
||||
|
||||
if (stack == IPV4_STACK) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (register_phy() < 0) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
nanostack_lock();
|
||||
|
||||
_blocking = blocking;
|
||||
|
||||
// After the RF is up, we can seed the random from it.
|
||||
randLIB_seed_random();
|
||||
|
||||
mesh_error_t status = init();
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
status = mesh_connect();
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
// Release mutex before blocking
|
||||
nanostack_unlock();
|
||||
|
||||
// In Thread wait connection for ever:
|
||||
// -routers will create new network and get local connectivity
|
||||
// -end devices will get connectivity once attached to existing network
|
||||
// -devices without network settings gets connectivity once commissioned and attached to network
|
||||
_connect_status = NSAPI_STATUS_CONNECTING;
|
||||
if (_blocking) {
|
||||
connect_semaphore.acquire();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::ThreadInterface::bringdown()
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
mesh_error_t status = mesh_disconnect();
|
||||
|
||||
nanostack_unlock();
|
||||
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::ThreadInterface::init()
|
||||
{
|
||||
thread_tasklet_init();
|
||||
__mesh_handler_set_callback(this);
|
||||
device_eui64_get(NULL); // Ensure we've selected the EUI-64 - this does it
|
||||
interface_id = thread_tasklet_network_init(_device_id);
|
||||
|
||||
if (interface_id == -2) {
|
||||
return MESH_ERROR_PARAM;
|
||||
} else if (interface_id == -3) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
} else if (interface_id < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::ThreadInterface::mesh_connect()
|
||||
{
|
||||
int8_t status;
|
||||
tr_debug("connect()");
|
||||
|
||||
status = thread_tasklet_connect(&__mesh_handler_c_callback, interface_id);
|
||||
|
||||
if (status >= 0) {
|
||||
return MESH_ERROR_NONE;
|
||||
} else if (status == -1) {
|
||||
return MESH_ERROR_PARAM;
|
||||
} else if (status == -2) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
} else if (status == -3) {
|
||||
return MESH_ERROR_STATE;
|
||||
} else {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::ThreadInterface::mesh_disconnect()
|
||||
{
|
||||
int8_t status;
|
||||
|
||||
status = thread_tasklet_disconnect(true);
|
||||
|
||||
if (status >= 0) {
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
void ThreadInterface::device_eui64_set(const uint8_t *eui64)
|
||||
{
|
||||
get_interface()->device_eui64_set(eui64);
|
||||
}
|
||||
|
||||
void ThreadInterface::device_eui64_get(uint8_t *eui64)
|
||||
{
|
||||
memset(eui64, 0, 8);
|
||||
if (!get_interface()) {
|
||||
return;
|
||||
}
|
||||
get_interface()->device_eui64_get(eui64);
|
||||
}
|
||||
|
||||
void Nanostack::ThreadInterface::device_eui64_set(const uint8_t *eui64)
|
||||
{
|
||||
eui64_set = true;
|
||||
thread_tasklet_device_eui64_set(eui64);
|
||||
}
|
||||
|
||||
void Nanostack::ThreadInterface::device_eui64_get(uint8_t *eui64)
|
||||
{
|
||||
if (!eui64_set) {
|
||||
uint8_t eui64_buf[8];
|
||||
if (register_phy() < 0) {
|
||||
return;
|
||||
}
|
||||
get_phy().get_mac_address(eui64_buf);
|
||||
device_eui64_set(eui64_buf);
|
||||
}
|
||||
|
||||
if (eui64) {
|
||||
thread_tasklet_device_eui64_get(eui64);
|
||||
}
|
||||
}
|
||||
|
||||
mesh_error_t ThreadInterface::device_pskd_set(const char *pskd)
|
||||
{
|
||||
return get_interface()->device_pskd_set(pskd);
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::ThreadInterface::device_pskd_set(const char *pskd)
|
||||
{
|
||||
return (mesh_error_t)thread_tasklet_device_pskd_set(pskd);
|
||||
}
|
||||
|
||||
#define THREAD 0x2345
|
||||
#if MBED_CONF_NSAPI_DEFAULT_MESH_TYPE == THREAD && DEVICE_802_15_4_PHY
|
||||
|
||||
MBED_WEAK MeshInterface *MeshInterface::get_target_default_instance()
|
||||
{
|
||||
static bool inited;
|
||||
static ThreadInterface interface;
|
||||
singleton_lock();
|
||||
if (!inited) {
|
||||
nsapi_error_t result = interface.initialize(&NanostackRfPhy::get_default_instance());
|
||||
if (result != 0) {
|
||||
tr_error("Thread initialize failed: %d", result);
|
||||
singleton_unlock();
|
||||
return NULL;
|
||||
}
|
||||
inited = true;
|
||||
}
|
||||
singleton_unlock();
|
||||
return &interface;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2020 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "WisunInterface.h"
|
||||
#include "ns_trace.h"
|
||||
#include "WisunBorderRouter.h"
|
||||
#include "MeshInterfaceNanostack.h"
|
||||
|
||||
extern "C" {
|
||||
#include "ws_bbr_api.h"
|
||||
}
|
||||
|
||||
#define TRACE_GROUP "WSBR"
|
||||
|
||||
mesh_error_t WisunBorderRouter::start(NetworkInterface *mesh_if, NetworkInterface *backbone_if)
|
||||
{
|
||||
if (mesh_if == NULL || backbone_if == NULL) {
|
||||
return MESH_ERROR_PARAM;
|
||||
}
|
||||
|
||||
InterfaceNanostack *nano_mesh_if = reinterpret_cast<InterfaceNanostack *>(mesh_if);
|
||||
int8_t mesh_if_id = nano_mesh_if->get_interface_id();
|
||||
if (mesh_if_id < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
_mesh_if_id = mesh_if_id;
|
||||
|
||||
char backbone_if_name[7] = {0};
|
||||
if (backbone_if->get_interface_name(backbone_if_name) == NULL) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (strlen((char *) &backbone_if_name) < 4) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
int backbone_if_id = atoi(&backbone_if_name[3]);
|
||||
if (backbone_if_id < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
int ret = ws_bbr_start(mesh_if_id, backbone_if_id);
|
||||
if (ret < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::start(NetworkInterface *mesh_if, OnboardNetworkStack::Interface *backbone_if)
|
||||
{
|
||||
InterfaceNanostack *nano_mesh_if = reinterpret_cast<InterfaceNanostack *>(mesh_if);
|
||||
int8_t mesh_if_id = nano_mesh_if->get_interface_id();
|
||||
if (mesh_if_id < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
_mesh_if_id = mesh_if_id;
|
||||
|
||||
Nanostack::Interface *nano_backbone_if = static_cast<Nanostack::Interface *>(backbone_if);
|
||||
int8_t backbone_if_id = nano_backbone_if->get_interface_id();
|
||||
if (backbone_if_id < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
int ret = ws_bbr_start(mesh_if_id, backbone_if_id);
|
||||
if (ret < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
void WisunBorderRouter::stop()
|
||||
{
|
||||
if (_mesh_if_id < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ws_bbr_stop(_mesh_if_id);
|
||||
|
||||
_mesh_if_id = -1;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::set_rpl_parameters(uint8_t dio_interval_min, uint8_t dio_interval_doublings, uint8_t dio_redundancy_constant)
|
||||
{
|
||||
int status = ws_bbr_rpl_parameters_set(_mesh_if_id, dio_interval_min, dio_interval_doublings, dio_redundancy_constant);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::get_rpl_parameters(uint8_t *dio_interval_min, uint8_t *dio_interval_doublings, uint8_t *dio_redundancy_constant)
|
||||
{
|
||||
int status = ws_bbr_rpl_parameters_get(_mesh_if_id, dio_interval_min, dio_interval_doublings, dio_redundancy_constant);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::validate_rpl_parameters(uint8_t dio_interval_min, uint8_t dio_interval_doublings, uint8_t dio_redundancy_constant)
|
||||
{
|
||||
int status = ws_bbr_rpl_parameters_validate(_mesh_if_id, dio_interval_min, dio_interval_doublings, dio_redundancy_constant);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::set_pan_configuration(uint16_t pan_id)
|
||||
{
|
||||
int status = ws_bbr_pan_configuration_set(_mesh_if_id, pan_id);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::get_pan_configuration(uint16_t *pan_id)
|
||||
{
|
||||
int status = ws_bbr_pan_configuration_get(_mesh_if_id, pan_id);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::validate_pan_configuration(uint16_t pan_id)
|
||||
{
|
||||
int status = ws_bbr_pan_configuration_validate(_mesh_if_id, pan_id);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunBorderRouter::info_get(ws_br_info_t *info_ptr)
|
||||
{
|
||||
bbr_information_t bbr_info = {0};
|
||||
|
||||
if (info_ptr == NULL) {
|
||||
return MESH_ERROR_PARAM;
|
||||
}
|
||||
|
||||
int status = ws_bbr_info_get(_mesh_if_id, &bbr_info);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
info_ptr->device_count = bbr_info.devices_in_network;
|
||||
info_ptr->host_timestamp = bbr_info.timestamp;
|
||||
info_ptr->instance_id = bbr_info.instance_id;
|
||||
info_ptr->version = bbr_info.version;
|
||||
memcpy(info_ptr->rpl_dodag_id, bbr_info.dodag_id, 16);
|
||||
memcpy(info_ptr->ipv6_prefix, bbr_info.prefix, 8);
|
||||
memcpy(info_ptr->ipv6_iid, bbr_info.IID, 8);
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
int WisunBorderRouter::routing_table_get(ws_br_route_info_t *table_ptr, uint16_t table_len)
|
||||
{
|
||||
if (table_ptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ws_bbr_routing_table_get(_mesh_if_id, (bbr_route_info_t *)table_ptr, table_len);
|
||||
}
|
||||
622
connectivity/nanostack/mbed-mesh-api/source/WisunInterface.cpp
Normal file
622
connectivity/nanostack/mbed-mesh-api/source/WisunInterface.cpp
Normal file
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "WisunInterface.h"
|
||||
#include "NanostackRfPhy.h"
|
||||
#include "include/wisun_tasklet.h"
|
||||
#include "callback_handler.h"
|
||||
#include "NanostackLockGuard.h"
|
||||
#include "mesh_system.h"
|
||||
#include "randLIB.h"
|
||||
#include "fhss_api.h"
|
||||
#include "fhss_config.h"
|
||||
#include "ws_management_api.h"
|
||||
#include "net_rpl.h"
|
||||
#include "net_interface.h"
|
||||
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "WSIn"
|
||||
|
||||
class Nanostack::WisunInterface final : public Nanostack::MeshInterface {
|
||||
public:
|
||||
nsapi_error_t bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack = IPV6_STACK,
|
||||
bool blocking = true) override;
|
||||
nsapi_error_t bringdown() override;
|
||||
nsapi_error_t get_gateway(SocketAddress *address) override;
|
||||
|
||||
friend class Nanostack;
|
||||
friend class ::WisunInterface;
|
||||
private:
|
||||
WisunInterface(NanostackRfPhy &phy) : MeshInterface(phy) { }
|
||||
mesh_error_t init();
|
||||
mesh_error_t mesh_connect();
|
||||
mesh_error_t mesh_disconnect();
|
||||
};
|
||||
|
||||
Nanostack::WisunInterface *WisunInterface::get_interface() const
|
||||
{
|
||||
return static_cast<Nanostack::WisunInterface *>(_interface);
|
||||
}
|
||||
|
||||
nsapi_error_t WisunInterface::do_initialize()
|
||||
{
|
||||
if (!_interface) {
|
||||
_interface = new (std::nothrow) Nanostack::WisunInterface(*_phy);
|
||||
if (!_interface) {
|
||||
return NSAPI_ERROR_NO_MEMORY;
|
||||
}
|
||||
_interface->attach(_connection_status_cb);
|
||||
}
|
||||
|
||||
// Apply mbed configuration to Wi-SUN
|
||||
configure();
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t WisunInterface::configure()
|
||||
{
|
||||
int status;
|
||||
|
||||
if (_configured) {
|
||||
// Already configured
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
_configured = true;
|
||||
#ifdef MBED_CONF_MBED_MESH_API_WISUN_NETWORK_NAME
|
||||
char network_name[] = {MBED_CONF_MBED_MESH_API_WISUN_NETWORK_NAME};
|
||||
status = set_network_name((char *) &network_name);
|
||||
if (status < 0) {
|
||||
tr_error("Failed to set network name!");
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (MBED_CONF_MBED_MESH_API_WISUN_REGULATORY_DOMAIN != 255) || (MBED_CONF_MBED_MESH_API_WISUN_OPERATING_CLASS != 255) || (MBED_CONF_MBED_MESH_API_WISUN_OPERATING_MODE != 255)
|
||||
status = set_network_regulatory_domain(MBED_CONF_MBED_MESH_API_WISUN_REGULATORY_DOMAIN,
|
||||
MBED_CONF_MBED_MESH_API_WISUN_OPERATING_CLASS,
|
||||
MBED_CONF_MBED_MESH_API_WISUN_OPERATING_MODE);
|
||||
if (status < 0) {
|
||||
tr_error("Failed to set regulatory domain!");
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (MBED_CONF_MBED_MESH_API_WISUN_UC_CHANNEL_FUNCTION != 255)
|
||||
status = set_unicast_channel_function(static_cast<mesh_channel_function_t>(MBED_CONF_MBED_MESH_API_WISUN_UC_CHANNEL_FUNCTION),
|
||||
MBED_CONF_MBED_MESH_API_WISUN_UC_FIXED_CHANNEL,
|
||||
MBED_CONF_MBED_MESH_API_WISUN_UC_DWELL_INTERVAL);
|
||||
if (status < 0) {
|
||||
tr_error("Failed to set unicast channel function configuration");
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (MBED_CONF_MBED_MESH_API_WISUN_BC_CHANNEL_FUNCTION != 255) || (MBED_CONF_MBED_MESH_API_WISUN_BC_DWELL_INTERVAL != 0) || (MBED_CONF_MBED_MESH_API_WISUN_BC_INTERVAL != 0)
|
||||
status = set_broadcast_channel_function(static_cast<mesh_channel_function_t>(MBED_CONF_MBED_MESH_API_WISUN_BC_CHANNEL_FUNCTION),
|
||||
MBED_CONF_MBED_MESH_API_WISUN_BC_FIXED_CHANNEL,
|
||||
MBED_CONF_MBED_MESH_API_WISUN_BC_DWELL_INTERVAL,
|
||||
MBED_CONF_MBED_MESH_API_WISUN_BC_INTERVAL);
|
||||
if (status < 0) {
|
||||
tr_error("Failed to set broadcast channel function configuration");
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::WisunInterface::bringup(bool dhcp, const char *ip,
|
||||
const char *netmask, const char *gw,
|
||||
nsapi_ip_stack_t stack, bool blocking)
|
||||
{
|
||||
nanostack_lock();
|
||||
|
||||
if (register_phy() < 0) {
|
||||
nanostack_unlock();
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
_blocking = blocking;
|
||||
|
||||
// After the RF is up, we can seed the random from it.
|
||||
randLIB_seed_random();
|
||||
|
||||
mesh_error_t status = init();
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
status = mesh_connect();
|
||||
if (status != MESH_ERROR_NONE) {
|
||||
nanostack_unlock();
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
// Release mutex before blocking
|
||||
nanostack_unlock();
|
||||
|
||||
if (blocking) {
|
||||
// wait connection for ever
|
||||
connect_semaphore.acquire();
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::WisunInterface::bringdown()
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
|
||||
mesh_error_t status = mesh_disconnect();
|
||||
|
||||
return map_mesh_error(status);
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::WisunInterface::init()
|
||||
{
|
||||
wisun_tasklet_init();
|
||||
__mesh_handler_set_callback(this);
|
||||
interface_id = wisun_tasklet_network_init(_device_id);
|
||||
|
||||
if (interface_id == -2) {
|
||||
return MESH_ERROR_PARAM;
|
||||
} else if (interface_id == -3) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
} else if (interface_id < 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::WisunInterface::mesh_connect()
|
||||
{
|
||||
int8_t status = -9; // init to unknown error
|
||||
tr_debug("connect()");
|
||||
|
||||
status = wisun_tasklet_connect(&__mesh_handler_c_callback, interface_id);
|
||||
|
||||
if (status >= 0) {
|
||||
return MESH_ERROR_NONE;
|
||||
} else if (status == -1) {
|
||||
return MESH_ERROR_PARAM;
|
||||
} else if (status == -2) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
} else if (status == -3) {
|
||||
return MESH_ERROR_STATE;
|
||||
} else {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
mesh_error_t Nanostack::WisunInterface::mesh_disconnect()
|
||||
{
|
||||
int8_t status = -1;
|
||||
|
||||
status = wisun_tasklet_disconnect(true);
|
||||
|
||||
if (status >= 0) {
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
nsapi_error_t Nanostack::WisunInterface::get_gateway(SocketAddress *addr)
|
||||
{
|
||||
NanostackLockGuard lock;
|
||||
char buf[NSAPI_IPv6_SIZE];
|
||||
if (wisun_tasklet_get_router_ip_address(buf, NSAPI_IPv6_SIZE) == 0) {
|
||||
addr->set_ip_address(buf);
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
return NSAPI_ERROR_NO_ADDRESS;
|
||||
}
|
||||
|
||||
bool WisunInterface::getRouterIpAddress(char *address, int8_t len)
|
||||
{
|
||||
SocketAddress sock_addr;
|
||||
if (_interface->get_gateway(&sock_addr) == NSAPI_ERROR_OK) {
|
||||
strncpy(address, sock_addr.get_ip_address(), len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_network_name(char *network_name)
|
||||
{
|
||||
int status = ws_management_network_name_set(get_interface_id(), network_name);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::get_network_name(char *network_name)
|
||||
{
|
||||
int status = ws_management_network_name_get(get_interface_id(), network_name);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::validate_network_name(char *network_name)
|
||||
{
|
||||
int status = ws_management_network_name_validate(get_interface_id(), network_name);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_network_regulatory_domain(uint8_t regulatory_domain, uint8_t operating_class, uint8_t operating_mode)
|
||||
{
|
||||
int status = ws_management_regulatory_domain_set(get_interface_id(), regulatory_domain, operating_class, operating_mode);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::get_network_regulatory_domain(uint8_t *regulatory_domain, uint8_t *operating_class, uint8_t *operating_mode)
|
||||
{
|
||||
int status = ws_management_regulatory_domain_get(get_interface_id(), regulatory_domain, operating_class, operating_mode);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::validate_network_regulatory_domain(uint8_t regulatory_domain, uint8_t operating_class, uint8_t operating_mode)
|
||||
{
|
||||
int status = ws_management_regulatory_domain_validate(get_interface_id(), regulatory_domain, operating_class, operating_mode);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_network_size(uint8_t network_size)
|
||||
{
|
||||
if (network_size == 0xff) {
|
||||
// Size 0xff is internal API
|
||||
network_size = 0xfe;
|
||||
}
|
||||
|
||||
int status = ws_management_network_size_set(get_interface_id(), network_size);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::get_network_size(uint8_t *network_size)
|
||||
{
|
||||
int status = ws_management_network_size_get(get_interface_id(), network_size);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::validate_network_size(uint8_t network_size)
|
||||
{
|
||||
if (network_size == 0xff) {
|
||||
// Size 0xff is internal API
|
||||
network_size = 0xfe;
|
||||
}
|
||||
|
||||
int status = ws_management_network_size_validate(get_interface_id(), network_size);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_channel_mask(uint32_t channel_mask[8])
|
||||
{
|
||||
int status = ws_management_channel_mask_set(get_interface_id(), channel_mask);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::get_channel_mask(uint32_t *channel_mask)
|
||||
{
|
||||
int status = ws_management_channel_mask_get(get_interface_id(), channel_mask);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::validate_channel_mask(uint32_t channel_mask[8])
|
||||
{
|
||||
int status = ws_management_channel_mask_validate(get_interface_id(), channel_mask);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_unicast_channel_function(mesh_channel_function_t channel_function, uint16_t fixed_channel, uint8_t dwell_interval)
|
||||
{
|
||||
int status = ws_management_fhss_unicast_channel_function_configure(get_interface_id(), channel_function, fixed_channel, dwell_interval);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::get_unicast_channel_function(mesh_channel_function_t *channel_function, uint16_t *fixed_channel, uint8_t *dwell_interval)
|
||||
{
|
||||
uint8_t ch_function;
|
||||
int status = ws_management_fhss_unicast_channel_function_get(get_interface_id(), &ch_function, fixed_channel, dwell_interval);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
*channel_function = static_cast<mesh_channel_function_t>(ch_function);
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::validate_unicast_channel_function(mesh_channel_function_t channel_function, uint16_t fixed_channel, uint8_t dwell_interval)
|
||||
{
|
||||
int status = ws_management_fhss_unicast_channel_function_validate(get_interface_id(), channel_function, fixed_channel, dwell_interval);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_broadcast_channel_function(mesh_channel_function_t channel_function, uint16_t fixed_channel, uint8_t dwell_interval, uint32_t broadcast_interval)
|
||||
{
|
||||
int status = ws_management_fhss_broadcast_channel_function_configure(get_interface_id(), channel_function, fixed_channel, dwell_interval, broadcast_interval);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::get_broadcast_channel_function(mesh_channel_function_t *channel_function, uint16_t *fixed_channel, uint8_t *dwell_interval, uint32_t *broadcast_interval)
|
||||
{
|
||||
uint8_t ch_function;
|
||||
int status = ws_management_fhss_broadcast_channel_function_get(get_interface_id(), &ch_function, fixed_channel, dwell_interval, broadcast_interval);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
*channel_function = static_cast<mesh_channel_function_t>(ch_function);
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::validate_broadcast_channel_function(mesh_channel_function_t channel_function, uint16_t fixed_channel, uint8_t dwell_interval, uint32_t broadcast_interval)
|
||||
{
|
||||
int status = ws_management_fhss_broadcast_channel_function_validate(get_interface_id(), channel_function, fixed_channel, dwell_interval, broadcast_interval);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_timing_parameters(uint16_t disc_trickle_imin, uint16_t disc_trickle_imax, uint8_t disc_trickle_k, uint16_t pan_timeout)
|
||||
{
|
||||
int status = ws_management_timing_parameters_set(get_interface_id(), disc_trickle_imin, disc_trickle_imax, disc_trickle_k, pan_timeout);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::get_timing_parameters(uint16_t *disc_trickle_imin, uint16_t *disc_trickle_imax, uint8_t *disc_trickle_k, uint16_t *pan_timeout)
|
||||
{
|
||||
int status = ws_management_timing_parameters_get(get_interface_id(), disc_trickle_imin, disc_trickle_imax, disc_trickle_k, pan_timeout);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::validate_timing_parameters(uint16_t disc_trickle_imin, uint16_t disc_trickle_imax, uint8_t disc_trickle_k, uint16_t pan_timeout)
|
||||
{
|
||||
int status = ws_management_timing_parameters_validate(get_interface_id(), disc_trickle_imin, disc_trickle_imax, disc_trickle_k, pan_timeout);
|
||||
if (status != 0) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_own_certificate(uint8_t *cert, uint16_t cert_len, uint8_t *cert_key, uint16_t cert_key_len)
|
||||
{
|
||||
mesh_error_t ret_val = MESH_ERROR_NONE;
|
||||
int status = wisun_tasklet_set_own_certificate(cert, cert_len, cert_key, cert_key_len);
|
||||
if (status == -1) {
|
||||
ret_val = MESH_ERROR_MEMORY;
|
||||
} else if (status == -2) {
|
||||
ret_val = MESH_ERROR_STATE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::remove_own_certificates(void)
|
||||
{
|
||||
mesh_error_t ret_val = MESH_ERROR_NONE;
|
||||
int status = wisun_tasklet_remove_own_certificates();
|
||||
if (status == -1) {
|
||||
ret_val = MESH_ERROR_MEMORY;
|
||||
} else if (status == -2) {
|
||||
ret_val = MESH_ERROR_STATE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::set_trusted_certificate(uint8_t *cert, uint16_t cert_len)
|
||||
{
|
||||
mesh_error_t ret_val = MESH_ERROR_NONE;
|
||||
int status = wisun_tasklet_set_trusted_certificate(cert, cert_len);
|
||||
if (status == -1) {
|
||||
ret_val = MESH_ERROR_MEMORY;
|
||||
} else if (status == -2) {
|
||||
ret_val = MESH_ERROR_STATE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::remove_trusted_certificates(void)
|
||||
{
|
||||
mesh_error_t ret_val = MESH_ERROR_NONE;
|
||||
int status = wisun_tasklet_remove_trusted_certificates();
|
||||
if (status == -1) {
|
||||
ret_val = MESH_ERROR_MEMORY;
|
||||
} else if (status == -2) {
|
||||
ret_val = MESH_ERROR_STATE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::enable_statistics(void)
|
||||
{
|
||||
mesh_error_t ret_val = MESH_ERROR_NONE;
|
||||
int status = wisun_tasklet_statistics_start();
|
||||
if (status < 0) {
|
||||
ret_val = MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::read_nw_statistics(mesh_nw_statistics_t *statistics)
|
||||
{
|
||||
mesh_error_t ret_val = MESH_ERROR_NONE;
|
||||
int status = wisun_tasklet_statistics_nw_read(statistics);
|
||||
if (status < 0) {
|
||||
ret_val = MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::read_mac_statistics(mesh_mac_statistics_t *statistics)
|
||||
{
|
||||
mesh_error_t ret_val = MESH_ERROR_NONE;
|
||||
int status = wisun_tasklet_statistics_mac_read(statistics);
|
||||
if (status < 0) {
|
||||
ret_val = MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
mesh_error_t WisunInterface::info_get(ws_rpl_info_t *info_ptr)
|
||||
{
|
||||
if (info_ptr == NULL) {
|
||||
return MESH_ERROR_PARAM;
|
||||
}
|
||||
|
||||
rpl_dodag_info_t dodag_ptr = {0};
|
||||
uint8_t global_address[16] = {0};
|
||||
uint8_t rpl_instance_count;
|
||||
uint8_t instance_id_list[10];
|
||||
uint8_t instance_id = RPL_INSTANCE_LOCAL;
|
||||
uint8_t instance_id_new;
|
||||
uint8_t instance_index;
|
||||
rpl_instance_count = rpl_instance_list_read(&instance_id_list[0], sizeof(instance_id_list));
|
||||
|
||||
if (rpl_instance_count > 10) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Find lowest global instance ID (assumption: RPL instance with lowest instance ID has
|
||||
most generic routing rule and its rank should be indicated in beacon) */
|
||||
for (instance_index = 0; instance_index < rpl_instance_count; instance_index++) {
|
||||
instance_id_new = instance_id_list[instance_index];
|
||||
|
||||
if ((instance_id_new & RPL_INSTANCE_LOCAL) == RPL_INSTANCE_LOCAL) {
|
||||
break;
|
||||
} else {
|
||||
if (instance_id_new < instance_id) {
|
||||
instance_id = instance_id_new;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (instance_id == RPL_INSTANCE_LOCAL) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (!rpl_read_dodag_info(&dodag_ptr, instance_id)) {
|
||||
return MESH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (arm_net_address_get(get_interface_id(), ADDR_IPV6_GP, global_address) != 0) {
|
||||
// No global prefix available, Nothing to do.
|
||||
}
|
||||
|
||||
info_ptr->instance_id = dodag_ptr.instance_id;
|
||||
info_ptr->version = dodag_ptr.version_num;
|
||||
memcpy(info_ptr->rpl_dodag_id, dodag_ptr.dodag_id, 16);
|
||||
memcpy(info_ptr->ipv6_prefix, global_address, 8);
|
||||
memcpy(info_ptr->ipv6_iid, global_address + 8, 8);
|
||||
|
||||
return MESH_ERROR_NONE;
|
||||
}
|
||||
|
||||
#define WISUN 0x2345
|
||||
#if MBED_CONF_NSAPI_DEFAULT_MESH_TYPE == WISUN && DEVICE_802_15_4_PHY
|
||||
MBED_WEAK MeshInterface *MeshInterface::get_target_default_instance()
|
||||
{
|
||||
static bool inited;
|
||||
static WisunInterface interface;
|
||||
singleton_lock();
|
||||
if (!inited) {
|
||||
nsapi_error_t result = interface.initialize(&NanostackRfPhy::get_default_instance());
|
||||
if (result != 0) {
|
||||
tr_error("Wi-SUN initialize failed: %d", result);
|
||||
singleton_unlock();
|
||||
return NULL;
|
||||
}
|
||||
inited = true;
|
||||
}
|
||||
singleton_unlock();
|
||||
return &interface;
|
||||
}
|
||||
#endif
|
||||
393
connectivity/nanostack/mbed-mesh-api/source/ethernet_tasklet.c
Normal file
393
connectivity/nanostack/mbed-mesh-api/source/ethernet_tasklet.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h> //memset
|
||||
#include "eventOS_event_timer.h"
|
||||
#include "common_functions.h"
|
||||
#include "net_interface.h"
|
||||
#include "ip6string.h" //ip6tos
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "include/mesh_system.h"
|
||||
#include "ns_event_loop.h"
|
||||
#include "mesh_interface_types.h"
|
||||
#include "eventOS_event.h"
|
||||
#include "enet_tasklet.h"
|
||||
|
||||
// For tracing we need to define flag, have include and define group
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "IPV6"
|
||||
|
||||
#include "ethernet_mac_api.h"
|
||||
|
||||
#define INTERFACE_NAME "eth0"
|
||||
|
||||
// Tasklet timer events
|
||||
#define TIMER_EVENT_START_BOOTSTRAP 1
|
||||
|
||||
#define INVALID_INTERFACE_ID (-1)
|
||||
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
|
||||
/*
|
||||
* Mesh tasklet states.
|
||||
*/
|
||||
typedef enum {
|
||||
TASKLET_STATE_CREATED = 0,
|
||||
TASKLET_STATE_INITIALIZED,
|
||||
TASKLET_STATE_BOOTSTRAP_STARTED,
|
||||
TASKLET_STATE_BOOTSTRAP_FAILED,
|
||||
TASKLET_STATE_BOOTSTRAP_READY
|
||||
} tasklet_state_t;
|
||||
|
||||
/*
|
||||
* Mesh tasklet data structure.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*mesh_api_cb)(mesh_connection_status_t nwk_status);
|
||||
tasklet_state_t tasklet_state;
|
||||
mesh_connection_status_t connection_status;
|
||||
timeout_t *poll_network_status_timeout;
|
||||
int8_t node_main_tasklet_id;
|
||||
int8_t network_interface_id;
|
||||
int8_t tasklet;
|
||||
uint8_t ip[16];
|
||||
} tasklet_data_str_t;
|
||||
|
||||
/* Tasklet data */
|
||||
static tasklet_data_str_t *tasklet_data_ptr = NULL;
|
||||
static eth_mac_api_t *eth_mac_api = NULL;
|
||||
typedef void (*mesh_interface_cb)(mesh_connection_status_t mesh_status);
|
||||
|
||||
|
||||
/* private function prototypes */
|
||||
static void enet_tasklet_main(arm_event_s *event);
|
||||
static void enet_tasklet_network_state_changed(mesh_connection_status_t status);
|
||||
static void enet_tasklet_parse_network_event(arm_event_s *event);
|
||||
static void enet_tasklet_configure_and_connect_to_network(void);
|
||||
static void enet_tasklet_poll_network_status(void *param);
|
||||
static void enet_tasklet_generate_event(uint8_t link_status, mesh_connection_status_t mesh_status);
|
||||
/*
|
||||
* \brief A function which will be eventually called by NanoStack OS when ever the OS has an event to deliver.
|
||||
* @param event, describes the sender, receiver and event type.
|
||||
*
|
||||
* NOTE: Interrupts requested by HW are possible during this function!
|
||||
*/
|
||||
void enet_tasklet_main(arm_event_s *event)
|
||||
{
|
||||
arm_library_event_type_e event_type;
|
||||
event_type = (arm_library_event_type_e) event->event_type;
|
||||
|
||||
switch (event_type) {
|
||||
case ARM_LIB_NWK_INTERFACE_EVENT:
|
||||
/* This event is delivered every and each time when there is new
|
||||
* information of network connectivity.
|
||||
*/
|
||||
enet_tasklet_parse_network_event(event);
|
||||
break;
|
||||
|
||||
case ARM_LIB_TASKLET_INIT_EVENT:
|
||||
/* Event with type EV_INIT is an initializer event of NanoStack OS.
|
||||
* The event is delivered when the NanoStack OS is running fine.
|
||||
* This event should be delivered ONLY ONCE.
|
||||
*/
|
||||
tasklet_data_ptr->node_main_tasklet_id = event->receiver;
|
||||
mesh_system_send_connect_event(tasklet_data_ptr->tasklet);
|
||||
break;
|
||||
|
||||
case ARM_LIB_SYSTEM_TIMER_EVENT:
|
||||
eventOS_event_timer_cancel(event->event_id,
|
||||
tasklet_data_ptr->node_main_tasklet_id);
|
||||
|
||||
if (event->event_id == TIMER_EVENT_START_BOOTSTRAP) {
|
||||
tr_debug("Restart bootstrap");
|
||||
enet_tasklet_configure_and_connect_to_network();
|
||||
}
|
||||
break;
|
||||
|
||||
case APPLICATION_EVENT:
|
||||
if (event->event_id == APPL_EVENT_CONNECT) {
|
||||
enet_tasklet_configure_and_connect_to_network();
|
||||
} else if (event->event_id == APPL_BACKHAUL_LINK_UP
|
||||
&& tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_STARTED) {
|
||||
// Ethernet cable has been plugged in
|
||||
arm_nwk_interface_configure_ipv6_bootstrap_set(
|
||||
tasklet_data_ptr->network_interface_id, NET_IPV6_BOOTSTRAP_AUTONOMOUS, NULL);
|
||||
enet_tasklet_configure_and_connect_to_network();
|
||||
|
||||
if (tasklet_data_ptr->poll_network_status_timeout != NULL) {
|
||||
// Restart poll timer
|
||||
eventOS_timeout_cancel(tasklet_data_ptr->poll_network_status_timeout);
|
||||
}
|
||||
tasklet_data_ptr->poll_network_status_timeout =
|
||||
eventOS_timeout_every_ms(enet_tasklet_poll_network_status, 2000, NULL);
|
||||
} else if (event->event_id == APPL_BACKHAUL_LINK_DOWN) {
|
||||
// Ethernet cable has been removed
|
||||
arm_nwk_interface_down(tasklet_data_ptr->network_interface_id);
|
||||
eventOS_timeout_cancel(tasklet_data_ptr->poll_network_status_timeout);
|
||||
tasklet_data_ptr->poll_network_status_timeout = NULL;
|
||||
memset(tasklet_data_ptr->ip, 0x0, 16);
|
||||
enet_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
|
||||
} else if (event->event_id == APPL_BACKHAUL_INTERFACE_PHY_DOWN) {
|
||||
// disconnect called
|
||||
if (tasklet_data_ptr != NULL) {
|
||||
if (tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
if (tasklet_data_ptr->connection_status != MESH_BOOTSTRAP_STARTED) {
|
||||
arm_nwk_interface_down(tasklet_data_ptr->network_interface_id);
|
||||
}
|
||||
tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
|
||||
enet_tasklet_network_state_changed(MESH_DISCONNECTED);
|
||||
}
|
||||
tasklet_data_ptr->mesh_api_cb = NULL;
|
||||
eventOS_timeout_cancel(tasklet_data_ptr->poll_network_status_timeout);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
} // switch(event_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Network state event handler.
|
||||
* \param event show network start response or current network state.
|
||||
*
|
||||
* - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role
|
||||
* - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state
|
||||
* - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No ND Router at current Channel Stack is Already at Idle state
|
||||
* - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result
|
||||
* - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels
|
||||
* - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state
|
||||
*/
|
||||
void enet_tasklet_parse_network_event(arm_event_s *event)
|
||||
{
|
||||
arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data;
|
||||
tr_debug("app_parse_network_event() %d", status);
|
||||
switch (status) {
|
||||
case ARM_NWK_BOOTSTRAP_READY:
|
||||
/* Network is ready and node is connected to Access Point */
|
||||
if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
|
||||
tr_info("IPv6 bootstrap ready");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY;
|
||||
enet_tasklet_poll_network_status(NULL);
|
||||
}
|
||||
break;
|
||||
case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL:
|
||||
/* No ND Router at current Channel Stack is Already at Idle state */
|
||||
tr_info("Bootstrap fail");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
enet_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_NWK_CONNECTION_DOWN:
|
||||
/* Connection to Access point is lost wait for Scan Result */
|
||||
tr_info("Connection lost");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
enet_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
default:
|
||||
tr_warn("Unknown event %d", status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
|
||||
// Set 5s timer for new network scan
|
||||
eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
|
||||
ARM_LIB_SYSTEM_TIMER_EVENT,
|
||||
tasklet_data_ptr->node_main_tasklet_id,
|
||||
5000);
|
||||
}
|
||||
}
|
||||
|
||||
static void enet_tasklet_poll_network_status(void *param)
|
||||
{
|
||||
/* Check if we do have an IP */
|
||||
uint8_t temp_ipv6[16];
|
||||
if (arm_net_address_get(tasklet_data_ptr->network_interface_id, ADDR_IPV6_GP, temp_ipv6) == 0) {
|
||||
/* Check if this is link local address or not */
|
||||
if (memcmp(temp_ipv6, tasklet_data_ptr->ip, 16) == 0) {
|
||||
return;
|
||||
} else {
|
||||
memcpy(tasklet_data_ptr->ip, temp_ipv6, 16);
|
||||
uint8_t temp_ipv6_local[16];
|
||||
if (arm_net_address_get(tasklet_data_ptr->network_interface_id, ADDR_IPV6_LL, temp_ipv6_local) == 0
|
||||
&& (memcmp(temp_ipv6, temp_ipv6_local, 16) != 0)) {
|
||||
enet_tasklet_network_state_changed(MESH_CONNECTED_GLOBAL);
|
||||
} else {
|
||||
enet_tasklet_network_state_changed(MESH_CONNECTED_LOCAL);;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (tasklet_data_ptr->connection_status != MESH_DISCONNECTED &&
|
||||
tasklet_data_ptr->connection_status != MESH_BOOTSTRAP_STARTED) {
|
||||
enet_tasklet_network_state_changed(MESH_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Configure and establish network connection
|
||||
*
|
||||
*/
|
||||
void enet_tasklet_configure_and_connect_to_network(void)
|
||||
{
|
||||
int8_t status;
|
||||
|
||||
status = arm_nwk_interface_up(tasklet_data_ptr->network_interface_id);
|
||||
if (status >= 0) {
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
|
||||
tr_info("Start Bootstrap");
|
||||
enet_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
|
||||
} else {
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
tr_err("Bootstrap start failed, %d", status);
|
||||
enet_tasklet_network_state_changed(MESH_BOOTSTRAP_START_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform application about network state change
|
||||
*/
|
||||
void enet_tasklet_network_state_changed(mesh_connection_status_t status)
|
||||
{
|
||||
tasklet_data_ptr->connection_status = status;
|
||||
if (tasklet_data_ptr->mesh_api_cb) {
|
||||
(tasklet_data_ptr->mesh_api_cb)(status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
int8_t enet_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id)
|
||||
{
|
||||
int8_t re_connecting = true;
|
||||
int8_t tasklet_id = tasklet_data_ptr->tasklet;
|
||||
|
||||
if (tasklet_data_ptr->tasklet_state == TASKLET_STATE_CREATED) {
|
||||
re_connecting = false;
|
||||
}
|
||||
|
||||
memset(tasklet_data_ptr, 0, sizeof(tasklet_data_str_t));
|
||||
tasklet_data_ptr->mesh_api_cb = callback;
|
||||
tasklet_data_ptr->network_interface_id = nwk_interface_id;
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_INITIALIZED;
|
||||
tasklet_data_ptr->poll_network_status_timeout =
|
||||
eventOS_timeout_every_ms(enet_tasklet_poll_network_status, 2000, NULL);
|
||||
|
||||
if (re_connecting == false) {
|
||||
tasklet_data_ptr->tasklet = eventOS_event_handler_create(&enet_tasklet_main,
|
||||
ARM_LIB_TASKLET_INIT_EVENT);
|
||||
if (tasklet_data_ptr->tasklet < 0) {
|
||||
// -1 handler already used by other tasklet
|
||||
// -2 memory allocation failure
|
||||
return tasklet_data_ptr->tasklet;
|
||||
}
|
||||
} else {
|
||||
tasklet_data_ptr->tasklet = tasklet_id;
|
||||
mesh_system_send_connect_event(tasklet_data_ptr->tasklet);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t enet_tasklet_disconnect(bool send_cb)
|
||||
{
|
||||
enet_tasklet_generate_event(APPL_BACKHAUL_INTERFACE_PHY_DOWN, MESH_DISCONNECTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enet_tasklet_init(void)
|
||||
{
|
||||
if (tasklet_data_ptr == NULL) {
|
||||
tasklet_data_ptr = ns_dyn_mem_alloc(sizeof(tasklet_data_str_t));
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_CREATED;
|
||||
tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t enet_tasklet_network_init(int8_t device_id)
|
||||
{
|
||||
if (tasklet_data_ptr->network_interface_id != -1) {
|
||||
tr_debug("Interface already at active state\n");
|
||||
return tasklet_data_ptr->network_interface_id;
|
||||
}
|
||||
if (!eth_mac_api) {
|
||||
eth_mac_api = ethernet_mac_create(device_id);
|
||||
}
|
||||
|
||||
tasklet_data_ptr->network_interface_id = arm_nwk_interface_ethernet_init(eth_mac_api, "eth0");
|
||||
|
||||
tr_debug("interface ID: %d", tasklet_data_ptr->network_interface_id);
|
||||
arm_nwk_interface_configure_ipv6_bootstrap_set(
|
||||
tasklet_data_ptr->network_interface_id, NET_IPV6_BOOTSTRAP_AUTONOMOUS, NULL);
|
||||
return tasklet_data_ptr->network_interface_id;
|
||||
}
|
||||
|
||||
/* For now, to enable to compile without Nanostack interface changes, enables Nanostack PPP
|
||||
interface only if default stack is Nanostack and interface cellular. After Nanostack
|
||||
with updated interface call arm_nwk_interface_ppp_init() is integrated to mbed-os, this
|
||||
flagging can be removed.
|
||||
*/
|
||||
#define NANOSTACK 0x11991199
|
||||
#define CELLULAR 0x22992299
|
||||
#if MBED_CONF_NSAPI_DEFAULT_STACK == NANOSTACK && MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == CELLULAR
|
||||
#define ENABLE_NANOSTACK_PPP
|
||||
#endif
|
||||
#undef NANOSTACK
|
||||
#undef CELLULAR
|
||||
|
||||
int8_t enet_tasklet_ppp_network_init(int8_t device_id)
|
||||
{
|
||||
#ifdef ENABLE_NANOSTACK_PPP
|
||||
if (tasklet_data_ptr->network_interface_id != -1) {
|
||||
tr_debug("Interface already at active state\n");
|
||||
return tasklet_data_ptr->network_interface_id;
|
||||
}
|
||||
if (!eth_mac_api) {
|
||||
eth_mac_api = ethernet_mac_create(device_id);
|
||||
}
|
||||
|
||||
tasklet_data_ptr->network_interface_id = arm_nwk_interface_ppp_init(eth_mac_api, "ppp0");
|
||||
|
||||
tr_debug("interface ID: %d", tasklet_data_ptr->network_interface_id);
|
||||
arm_nwk_interface_configure_ipv6_bootstrap_set(
|
||||
tasklet_data_ptr->network_interface_id, NET_IPV6_BOOTSTRAP_AUTONOMOUS, NULL);
|
||||
return tasklet_data_ptr->network_interface_id;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void enet_tasklet_link_state_changed(bool up)
|
||||
{
|
||||
if (up) {
|
||||
enet_tasklet_generate_event(APPL_BACKHAUL_LINK_UP, MESH_BOOTSTRAP_STARTED);
|
||||
} else {
|
||||
enet_tasklet_generate_event(APPL_BACKHAUL_LINK_DOWN, MESH_BOOTSTRAP_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
static void enet_tasklet_generate_event(uint8_t link_status, mesh_connection_status_t mesh_status)
|
||||
{
|
||||
arm_event_s event = {
|
||||
.receiver = tasklet_data_ptr->tasklet,
|
||||
.sender = tasklet_data_ptr->tasklet,
|
||||
.event_type = APPLICATION_EVENT,
|
||||
.priority = ARM_LIB_LOW_PRIORITY_EVENT,
|
||||
.event_id = link_status,
|
||||
.event_data = mesh_status
|
||||
};
|
||||
eventOS_event_send(&event);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/* Copyright (c) 2017 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef NANOSTACK_MEMORY_MANAGER_H
|
||||
#define NANOSTACK_MEMORY_MANAGER_H
|
||||
|
||||
#include "EMACMemoryManager.h"
|
||||
|
||||
class NanostackMemoryManager final : public EMACMemoryManager {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Allocates memory buffer from the heap
|
||||
*
|
||||
* Memory buffer allocated from heap is always contiguous and can be arbitrary size.
|
||||
*
|
||||
* @param size Size of the memory to allocate in bytes
|
||||
* @param align Memory alignment requirement in bytes
|
||||
* @return Allocated memory buffer, or NULL in case of error
|
||||
*/
|
||||
emac_mem_buf_t *alloc_heap(uint32_t size, uint32_t align) override;
|
||||
|
||||
/**
|
||||
* Allocates memory buffer chain from a pool
|
||||
*
|
||||
* Memory allocated from pool is contiguous if size is equal or less than
|
||||
* (aligned) allocation unit, otherwise may be chained. Will typically come from
|
||||
* fixed-size packet pool memory.
|
||||
*
|
||||
* @param size Total size of the memory to allocate in bytes
|
||||
* @param align Memory alignment requirement for each buffer in bytes
|
||||
* @return Allocated memory buffer chain, or NULL in case of error
|
||||
*/
|
||||
emac_mem_buf_t *alloc_pool(uint32_t size, uint32_t align) override;
|
||||
|
||||
/**
|
||||
* Get memory buffer pool allocation unit
|
||||
*
|
||||
* Returns the maximum size of contiguous memory that can be allocated from a pool.
|
||||
*
|
||||
* @param align Memory alignment requirement in bytes
|
||||
* @return Contiguous memory size
|
||||
*/
|
||||
uint32_t get_pool_alloc_unit(uint32_t align) const override;
|
||||
|
||||
/**
|
||||
* Free memory buffer chain
|
||||
*
|
||||
* If memory buffer is chained must point to the start of the chain. Frees all buffers
|
||||
* from the chained list.
|
||||
*
|
||||
* @param buf Memory buffer chain to be freed.
|
||||
*/
|
||||
void free(emac_mem_buf_t *buf) override;
|
||||
|
||||
/**
|
||||
* Return total length of a memory buffer chain
|
||||
*
|
||||
* Returns a total length of this buffer and any following buffers in the chain.
|
||||
*
|
||||
* @param buf Memory buffer chain
|
||||
* @return Total length in bytes
|
||||
*/
|
||||
uint32_t get_total_len(const emac_mem_buf_t *buf) const override;
|
||||
|
||||
/**
|
||||
* Copy a memory buffer chain
|
||||
*
|
||||
* Copies data from one buffer chain to another. Copy operation does not adjust the lengths
|
||||
* of the copied-to memory buffer chain, so chain total lengths must be the same.
|
||||
*
|
||||
* @param to_buf Memory buffer chain to copy to
|
||||
* @param from_buf Memory buffer chain to copy from
|
||||
*/
|
||||
void copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf) override;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Concatenate two memory buffer chains
|
||||
*
|
||||
* Concatenates buffer chain to end of the other buffer chain. Concatenated-to buffer total length
|
||||
* is adjusted accordingly. cat_buf must point to the start of a the chain. After concatenation
|
||||
* to_buf's chain now owns those buffers, and they will be freed when the to_buf chain is freed.
|
||||
*
|
||||
* @param to_buf Memory buffer chain to concatenate to
|
||||
* @param cat_buf Memory buffer chain to concatenate
|
||||
*/
|
||||
void cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf) override;
|
||||
|
||||
/**
|
||||
* Returns the next buffer
|
||||
*
|
||||
* Returns the next buffer from the memory buffer chain.
|
||||
*
|
||||
* @param buf Memory buffer
|
||||
* @return The next memory buffer, or NULL if last
|
||||
*/
|
||||
emac_mem_buf_t *get_next(const emac_mem_buf_t *buf) const override;
|
||||
|
||||
/**
|
||||
* Return pointer to the payload of the buffer
|
||||
*
|
||||
* @param buf Memory buffer
|
||||
* @return Pointer to the payload
|
||||
*/
|
||||
void *get_ptr(const emac_mem_buf_t *buf) const override;
|
||||
|
||||
/**
|
||||
* Return payload size of the buffer
|
||||
*
|
||||
* @param buf Memory buffer
|
||||
* @return Size in bytes
|
||||
*/
|
||||
uint32_t get_len(const emac_mem_buf_t *buf) const override;
|
||||
|
||||
/**
|
||||
* Sets the payload size of the buffer
|
||||
*
|
||||
* The allocated payload size will not change. It is not permitted
|
||||
* to change the length of a buffer that is not the first (or only) in a chain.
|
||||
*
|
||||
* @param buf Memory buffer
|
||||
* @param len Payload size, must be less or equal allocated size
|
||||
*/
|
||||
void set_len(emac_mem_buf_t *buf, uint32_t len) override;
|
||||
};
|
||||
|
||||
#endif /* NANOSTACK_MEMORY_MANAGER_H */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_CALLBACK_HANDLER_H__
|
||||
#define __INCLUDE_CALLBACK_HANDLER_H__
|
||||
|
||||
#include "mesh_interface_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "MeshInterfaceNanostack.h"
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void __mesh_handler_c_callback(mesh_connection_status_t state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
void __mesh_handler_set_callback(Nanostack::Interface *handler);
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_CALLBACK_HANDLER_H__ */
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ENET_TASKLET_H
|
||||
#define ENET_TASKLET_H
|
||||
|
||||
#include "mesh_interface_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* \brief Initialize system.
|
||||
*/
|
||||
void enet_tasklet_init(void);
|
||||
|
||||
/*
|
||||
* \brief Create network interface.
|
||||
*
|
||||
* \param device_id Registered physical device.
|
||||
* \return interface ID used to communication with this interface.
|
||||
*/
|
||||
int8_t enet_tasklet_network_init(int8_t device_id);
|
||||
|
||||
/*
|
||||
* \brief Create PPP network interface.
|
||||
*
|
||||
* \param device_id Registered physical device.
|
||||
* \return interface ID used to communication with this interface.
|
||||
*/
|
||||
int8_t enet_tasklet_ppp_network_init(int8_t device_id);
|
||||
|
||||
/*
|
||||
* \brief Connect to Ethernet network.
|
||||
*
|
||||
* \param callback Call when network state changes.
|
||||
* \param nwk_interface_id To use for networking.
|
||||
*
|
||||
*/
|
||||
int8_t enet_tasklet_connect(void (*)(mesh_connection_status_t mesh_status), int8_t nwk_interface_id);
|
||||
|
||||
/*
|
||||
* \brief Disconnect network interface.
|
||||
*
|
||||
* \param send_cb Send possible network status change event if set to `true`.
|
||||
* \return >= 0 if disconnected successfully.
|
||||
* \return < 0 if error.
|
||||
*/
|
||||
int8_t enet_tasklet_disconnect(bool send_cb);
|
||||
|
||||
/*
|
||||
* \brief Callback to call when the link state changes.
|
||||
*
|
||||
* \param up Tells if link is up or down.
|
||||
*/
|
||||
void enet_tasklet_link_state_changed(bool up);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ENET_TASKLET_H
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2019 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_MESH_SYSTEM__
|
||||
#define __INCLUDE_MESH_SYSTEM__
|
||||
#include "ns_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Event type for connecting
|
||||
*/
|
||||
enum {
|
||||
APPL_EVENT_CONNECT = 0x01,
|
||||
APPL_BACKHAUL_INTERFACE_PHY_DOWN,
|
||||
APPL_BACKHAUL_LINK_DOWN,
|
||||
APPL_BACKHAUL_LINK_UP
|
||||
};
|
||||
|
||||
/*
|
||||
* \brief Send application connect event to receiver tasklet to
|
||||
* ensure that connection is made in right tasklet.
|
||||
*/
|
||||
void mesh_system_send_connect_event(uint8_t receiver);
|
||||
|
||||
int mesh_system_set_file_system_root_path(const char *root_path);
|
||||
|
||||
/*
|
||||
* \brief Initialize mesh system.
|
||||
* Memory pool, timers, traces and support are initialized.
|
||||
*/
|
||||
void mesh_system_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "nanostack-event-loop/eventOS_scheduler.h"
|
||||
|
||||
#define nanostack_lock() eventOS_scheduler_mutex_wait()
|
||||
#define nanostack_unlock() eventOS_scheduler_mutex_release()
|
||||
#define nanostack_assert_locked() //MBED_ASSERT(eventOS_scheduler_mutex_is_owner())
|
||||
|
||||
#endif /* __INCLUDE_MESH_SYSTEM__ */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_ND_TASKLET__
|
||||
#define __INCLUDE_ND_TASKLET__
|
||||
#include "ns_types.h"
|
||||
#include "eventOS_event.h"
|
||||
#include "mbed-mesh-api/mesh_interface_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type of the network status callback.
|
||||
*/
|
||||
typedef void (*mesh_interface_cb)(mesh_connection_status_t mesh_status);
|
||||
|
||||
/*
|
||||
* \brief Read border router IP address
|
||||
*
|
||||
* \param address where router IP address will be written
|
||||
* \param len length of provided address buffer
|
||||
*
|
||||
* \return 0 on success
|
||||
* \return -1 if address reading fails
|
||||
*/
|
||||
int8_t nd_tasklet_get_router_ip_address(char *address, int8_t len);
|
||||
|
||||
/*
|
||||
* \brief Connect to mesh network
|
||||
*
|
||||
* \param callback to be called when network state changes
|
||||
* \param nwk_interface_id to use for networking
|
||||
*
|
||||
* \return >= 0 on success
|
||||
* \return -1 if callback function is used in another tasklet
|
||||
* \return -2 if memory allocation fails
|
||||
* \return -3 if network is already connected
|
||||
*/
|
||||
int8_t nd_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id);
|
||||
|
||||
/*
|
||||
* \brief Initialize mesh system.
|
||||
* Memory pool, timers, traces and support are initialized.
|
||||
*/
|
||||
void nd_tasklet_init(void);
|
||||
|
||||
/*
|
||||
* \brief Create network interface.
|
||||
*
|
||||
* \param device_id registered physical device
|
||||
* \return interface ID that can be used to communication with this interface
|
||||
*/
|
||||
int8_t nd_tasklet_network_init(int8_t device_id);
|
||||
|
||||
/*
|
||||
* \brief Disconnect network interface.
|
||||
*
|
||||
* \param send_cb send possible network status change event if set to true.
|
||||
* \return >= 0 if disconnected successfully.
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int8_t nd_tasklet_disconnect(bool send_cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __INCLUDE_ND_TASKLET__ */
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_THREAD_TASKLET__
|
||||
#define __INCLUDE_THREAD_TASKLET__
|
||||
#include "ns_types.h"
|
||||
#include "eventOS_event.h"
|
||||
#include "mbed-mesh-api/mesh_interface_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type of the network status callback.
|
||||
*/
|
||||
typedef void (*mesh_interface_cb)(mesh_connection_status_t mesh_status);
|
||||
|
||||
/*
|
||||
* \brief Connect to mesh network
|
||||
*
|
||||
* \param callback to be called when network state changes
|
||||
* \param nwk_interface_id to use for networking
|
||||
*
|
||||
* \return >= 0 on success
|
||||
* \return -1 if callback function is used in another tasklet
|
||||
* \return -2 if memory allocation fails
|
||||
* \return -3 if network is already connected
|
||||
*/
|
||||
int8_t thread_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id);
|
||||
|
||||
/*
|
||||
* \brief Initialize mesh system.
|
||||
* Memory pool, timers, traces and support are initialized.
|
||||
*/
|
||||
void thread_tasklet_init(void);
|
||||
|
||||
/*
|
||||
* \brief Create network interface.
|
||||
*
|
||||
* \param device_id registered physical device
|
||||
* \return interface ID that can be used to communication with this interface
|
||||
*/
|
||||
int8_t thread_tasklet_network_init(int8_t device_id);
|
||||
|
||||
/*
|
||||
* \brief Sets eui64 for the device configuration
|
||||
* \param eui64 eui64 to be set
|
||||
*/
|
||||
void thread_tasklet_device_eui64_set(const uint8_t *eui64);
|
||||
|
||||
/*
|
||||
* \brief Gets eui64 from the device configuration
|
||||
* \param eui64 buffer for output eui64
|
||||
*/
|
||||
void thread_tasklet_device_eui64_get(uint8_t *eui64);
|
||||
|
||||
/*
|
||||
* \brief Sets PSKd for the device configuration
|
||||
* \param pskd private shared key to be set
|
||||
*/
|
||||
uint8_t thread_tasklet_device_pskd_set(const char *pskd);
|
||||
|
||||
/*
|
||||
* \brief Disconnect network interface.
|
||||
*
|
||||
* \param send_cb send possible network status change event if set to true.
|
||||
* \return >= 0 if disconnected successfully.
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int8_t thread_tasklet_disconnect(bool send_cb);
|
||||
|
||||
/*
|
||||
* \brief Set device data polling rate
|
||||
*
|
||||
* \param timeout timeout between data polls
|
||||
* \return 0 on success
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int8_t thread_tasklet_data_poll_rate_set(uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __INCLUDE_THREAD_TASKLET__ */
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 ARM Limited
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_WISUN_TASKLET__
|
||||
#define __INCLUDE_WISUN_TASKLET__
|
||||
#include "ns_types.h"
|
||||
#include "eventOS_event.h"
|
||||
#include "mbed-mesh-api/mesh_interface_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type of the network status callback.
|
||||
*/
|
||||
typedef void (*mesh_interface_cb)(mesh_connection_status_t mesh_status);
|
||||
|
||||
/*
|
||||
* \brief Read border router IP address
|
||||
*
|
||||
* \param address where router IP address will be written
|
||||
* \param len length of provided address buffer
|
||||
*
|
||||
* \return 0 on success
|
||||
* \return -1 if address reading fails
|
||||
*/
|
||||
int8_t wisun_tasklet_get_router_ip_address(char *address, int8_t len);
|
||||
|
||||
/*
|
||||
* \brief Connect to mesh network
|
||||
*
|
||||
* \param callback to be called when network state changes
|
||||
* \param nwk_interface_id to use for networking
|
||||
*
|
||||
* \return >= 0 on success
|
||||
* \return -1 if callback function is used in another tasklet
|
||||
* \return -2 if memory allocation fails
|
||||
* \return -3 if network is already connected
|
||||
*/
|
||||
int8_t wisun_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id);
|
||||
|
||||
/*
|
||||
* \brief Initialize mesh system.
|
||||
* Memory pool, timers, traces and support are initialized.
|
||||
*/
|
||||
void wisun_tasklet_init(void);
|
||||
|
||||
/*
|
||||
* \brief Create network interface.
|
||||
*
|
||||
* \param device_id registered physical device
|
||||
* \return interface ID that can be used to communication with this interface
|
||||
* \return -1 in case of MAC initialization fails
|
||||
* \return -2 in case of error in parameters
|
||||
* \return -3 in case of memory allocation error
|
||||
*/
|
||||
int8_t wisun_tasklet_network_init(int8_t device_id);
|
||||
|
||||
/*
|
||||
* \brief Disconnect network interface.
|
||||
*
|
||||
* \param send_cb send possible network status change event if set to true.
|
||||
* \return >= 0 if disconnected successfully.
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int8_t wisun_tasklet_disconnect(bool send_cb);
|
||||
|
||||
/*
|
||||
* \brief Set own certificate to Wi-SUN network
|
||||
*
|
||||
* \param cert to use for networking
|
||||
* \param cert_len
|
||||
* \param cert_key
|
||||
* \param cert_key_len
|
||||
* \return 0 if certificate stored successfully
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int wisun_tasklet_set_own_certificate(uint8_t *cert, uint16_t cert_len, uint8_t *cert_key, uint16_t cert_key_len);
|
||||
|
||||
/*
|
||||
* \brief Remove own certificate from Wi-SUN network
|
||||
*
|
||||
* \return 0 if certificates removed successfully
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int wisun_tasklet_remove_own_certificates(void);
|
||||
|
||||
/*
|
||||
* \brief Set trusted certificate to Wi-SUN network
|
||||
*
|
||||
* \param cert to use for networking
|
||||
* \param cert_len
|
||||
* \return 0 if certificate stored successfully
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int wisun_tasklet_set_trusted_certificate(uint8_t *cert, uint16_t cert_len);
|
||||
|
||||
/*
|
||||
* \brief Remove trusted certificate from Wi-SUN network
|
||||
*
|
||||
* \return 0 if certificates removed successfully
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int wisun_tasklet_remove_trusted_certificates(void);
|
||||
|
||||
/*
|
||||
* \brief Start Wi-SUN statistics
|
||||
*
|
||||
* \return 0 Statistics start successful
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int wisun_tasklet_statistics_start(void);
|
||||
|
||||
/*
|
||||
* \brief Reads Wi-SUN network statistics
|
||||
*
|
||||
* \return 0 Statistics read successful
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int wisun_tasklet_statistics_nw_read(mesh_nw_statistics_t *stats);
|
||||
|
||||
/*
|
||||
* \brief Reads Wi-SUN MAC statistics
|
||||
*
|
||||
* \return 0 Statistics read successful
|
||||
* \return < 0 in case of errors
|
||||
*/
|
||||
int wisun_tasklet_statistics_mac_read(mesh_mac_statistics_t *stats);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __INCLUDE_WISUN_TASKLET__ */
|
||||
85
connectivity/nanostack/mbed-mesh-api/source/mesh_system.c
Normal file
85
connectivity/nanostack/mbed-mesh-api/source/mesh_system.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2019 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "eventOS_scheduler.h"
|
||||
#include "eventOS_event.h"
|
||||
#include "net_interface.h"
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "randLIB.h"
|
||||
#include "platform/arm_hal_timer.h"
|
||||
#include "ns_hal_init.h"
|
||||
#include "include/mesh_system.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "mbed_error.h"
|
||||
#include "ns_file_system.h"
|
||||
// For tracing we need to define flag, have include and define group
|
||||
#define HAVE_DEBUG 1
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "m6-mesh-system"
|
||||
|
||||
/* Heap for NanoStack */
|
||||
#if !MBED_CONF_MBED_MESH_API_USE_MALLOC_FOR_HEAP
|
||||
static uint8_t app_stack_heap[MBED_CONF_MBED_MESH_API_HEAP_SIZE + 1];
|
||||
#else
|
||||
static uint8_t *app_stack_heap;
|
||||
#endif
|
||||
static bool mesh_initialized = false;
|
||||
#ifdef MBED_CONF_MBED_MESH_API_HEAP_STAT_INFO_DEFINITION
|
||||
MBED_CONF_MBED_MESH_API_HEAP_STAT_INFO_DEFINITION;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Heap error handler, called when heap problem is detected.
|
||||
* Function is for-ever loop.
|
||||
*/
|
||||
static void mesh_system_heap_error_handler(heap_fail_t event)
|
||||
{
|
||||
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_OUT_OF_MEMORY), "Heap error, mesh_system_heap_error_handler()", event);
|
||||
}
|
||||
|
||||
void mesh_system_init(void)
|
||||
{
|
||||
if (mesh_initialized == false) {
|
||||
#if MBED_CONF_MBED_MESH_API_USE_MALLOC_FOR_HEAP
|
||||
app_stack_heap = malloc(MBED_CONF_MBED_MESH_API_HEAP_SIZE + 1);
|
||||
MBED_ASSERT(app_stack_heap);
|
||||
#endif
|
||||
ns_hal_init(app_stack_heap, MBED_CONF_MBED_MESH_API_HEAP_SIZE,
|
||||
mesh_system_heap_error_handler, MBED_CONF_MBED_MESH_API_HEAP_STAT_INFO);
|
||||
eventOS_scheduler_mutex_wait();
|
||||
net_init_core();
|
||||
eventOS_scheduler_mutex_release();
|
||||
mesh_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void mesh_system_send_connect_event(uint8_t receiver)
|
||||
{
|
||||
arm_event_s event = {
|
||||
.sender = receiver,
|
||||
.event_id = APPL_EVENT_CONNECT,
|
||||
.receiver = receiver,
|
||||
.event_type = APPLICATION_EVENT,
|
||||
.priority = ARM_LIB_LOW_PRIORITY_EVENT,
|
||||
};
|
||||
eventOS_event_send(&event);
|
||||
}
|
||||
|
||||
int mesh_system_set_file_system_root_path(const char *root_path)
|
||||
{
|
||||
return ns_file_system_set_root_path(root_path);
|
||||
}
|
||||
437
connectivity/nanostack/mbed-mesh-api/source/nd_tasklet.c
Normal file
437
connectivity/nanostack/mbed-mesh-api/source/nd_tasklet.c
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h> //memset
|
||||
#include "eventOS_event_timer.h"
|
||||
#include "common_functions.h"
|
||||
#include "net_interface.h"
|
||||
#include "ip6string.h" //ip6tos
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "include/nd_tasklet.h"
|
||||
#include "include/mesh_system.h"
|
||||
#include "ns_event_loop.h"
|
||||
#include "multicast_api.h"
|
||||
|
||||
// For tracing we need to define flag, have include and define group
|
||||
#define HAVE_DEBUG 1
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "m6LND"
|
||||
|
||||
#include "mac_api.h"
|
||||
#include "sw_mac.h"
|
||||
|
||||
#define INTERFACE_NAME "6L-ND"
|
||||
|
||||
// Tasklet timer events
|
||||
#define TIMER_EVENT_START_BOOTSTRAP 1
|
||||
|
||||
#define INVALID_INTERFACE_ID (-1)
|
||||
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
|
||||
/*
|
||||
* Mesh tasklet states.
|
||||
*/
|
||||
typedef enum {
|
||||
TASKLET_STATE_CREATED = 0,
|
||||
TASKLET_STATE_INITIALIZED,
|
||||
TASKLET_STATE_BOOTSTRAP_STARTED,
|
||||
TASKLET_STATE_BOOTSTRAP_FAILED,
|
||||
TASKLET_STATE_BOOTSTRAP_READY
|
||||
} tasklet_state_t;
|
||||
|
||||
/*
|
||||
* Mesh tasklet data structure.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*mesh_api_cb)(mesh_connection_status_t nwk_status);
|
||||
channel_list_s channel_list;
|
||||
tasklet_state_t tasklet_state;
|
||||
net_6lowpan_mode_e mode;
|
||||
net_6lowpan_link_layer_sec_mode_e sec_mode;
|
||||
net_link_layer_psk_security_info_s psk_sec_info;
|
||||
int8_t network_interface_id;
|
||||
int8_t tasklet;
|
||||
} tasklet_data_str_t;
|
||||
|
||||
/* Tasklet data */
|
||||
static tasklet_data_str_t *tasklet_data_ptr = NULL;
|
||||
static mac_api_t *mac_api = NULL;
|
||||
|
||||
/* private function prototypes */
|
||||
void nd_tasklet_main(arm_event_s *event);
|
||||
void nd_tasklet_network_state_changed(mesh_connection_status_t status);
|
||||
void nd_tasklet_parse_network_event(arm_event_s *event);
|
||||
void nd_tasklet_configure_and_connect_to_network(void);
|
||||
#define TRACE_ND_TASKLET
|
||||
#ifndef TRACE_ND_TASKLET
|
||||
#define nd_tasklet_trace_bootstrap_info() ((void) 0)
|
||||
#else
|
||||
void nd_tasklet_trace_bootstrap_info(void);
|
||||
#endif
|
||||
|
||||
static void initialize_channel_list(void)
|
||||
{
|
||||
uint32_t channel = MBED_CONF_MBED_MESH_API_6LOWPAN_ND_CHANNEL;
|
||||
|
||||
const int_fast8_t word_index = channel / 32;
|
||||
const int_fast8_t bit_index = channel % 32;
|
||||
|
||||
memset(&tasklet_data_ptr->channel_list, 0, sizeof(tasklet_data_ptr->channel_list));
|
||||
|
||||
tasklet_data_ptr->channel_list.channel_page = (channel_page_e)MBED_CONF_MBED_MESH_API_6LOWPAN_ND_CHANNEL_PAGE;
|
||||
tasklet_data_ptr->channel_list.channel_mask[0] = MBED_CONF_MBED_MESH_API_6LOWPAN_ND_CHANNEL_MASK;
|
||||
|
||||
if (channel > 0) {
|
||||
memset(&tasklet_data_ptr->channel_list.channel_mask, 0, sizeof(tasklet_data_ptr->channel_list.channel_mask));
|
||||
tasklet_data_ptr->channel_list.channel_mask[word_index] |= ((uint32_t) 1 << bit_index);
|
||||
}
|
||||
|
||||
arm_nwk_set_channel_list(tasklet_data_ptr->network_interface_id, &tasklet_data_ptr->channel_list);
|
||||
|
||||
tr_debug("Channel: %" PRIu32, channel);
|
||||
tr_debug("Channel page: %d", tasklet_data_ptr->channel_list.channel_page);
|
||||
tr_debug("Channel mask: 0x%.8" PRIx32, tasklet_data_ptr->channel_list.channel_mask[word_index]);
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief A function which will be eventually called by NanoStack OS when ever the OS has an event to deliver.
|
||||
* @param event, describes the sender, receiver and event type.
|
||||
*
|
||||
* NOTE: Interrupts requested by HW are possible during this function!
|
||||
*/
|
||||
void nd_tasklet_main(arm_event_s *event)
|
||||
{
|
||||
arm_library_event_type_e event_type;
|
||||
event_type = (arm_library_event_type_e) event->event_type;
|
||||
|
||||
switch (event_type) {
|
||||
case ARM_LIB_NWK_INTERFACE_EVENT:
|
||||
/* This event is delivered every and each time when there is new
|
||||
* information of network connectivity.
|
||||
*/
|
||||
nd_tasklet_parse_network_event(event);
|
||||
break;
|
||||
|
||||
case ARM_LIB_TASKLET_INIT_EVENT:
|
||||
/* Event with type EV_INIT is an initializer event of NanoStack OS.
|
||||
* The event is delivered when the NanoStack OS is running fine.
|
||||
* This event should be delivered ONLY ONCE.
|
||||
*/
|
||||
mesh_system_send_connect_event(tasklet_data_ptr->tasklet);
|
||||
break;
|
||||
|
||||
case ARM_LIB_SYSTEM_TIMER_EVENT:
|
||||
eventOS_event_timer_cancel(event->event_id,
|
||||
tasklet_data_ptr->tasklet);
|
||||
|
||||
if (event->event_id == TIMER_EVENT_START_BOOTSTRAP) {
|
||||
tr_debug("Restart bootstrap");
|
||||
nd_tasklet_configure_and_connect_to_network();
|
||||
}
|
||||
break;
|
||||
|
||||
case APPLICATION_EVENT:
|
||||
if (event->event_id == APPL_EVENT_CONNECT) {
|
||||
nd_tasklet_configure_and_connect_to_network();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
} // switch(event_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Network state event handler.
|
||||
* \param event show network start response or current network state.
|
||||
*
|
||||
* - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role
|
||||
* - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state
|
||||
* - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No ND Router at current Channel Stack is Already at Idle state
|
||||
* - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result
|
||||
* - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels
|
||||
* - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state
|
||||
*/
|
||||
void nd_tasklet_parse_network_event(arm_event_s *event)
|
||||
{
|
||||
arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data;
|
||||
tr_debug("app_parse_network_event() %d", status);
|
||||
switch (status) {
|
||||
case ARM_NWK_BOOTSTRAP_READY:
|
||||
/* Network is ready and node is connected to Access Point */
|
||||
if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
|
||||
tr_info("6LoWPAN ND bootstrap ready");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY;
|
||||
nd_tasklet_trace_bootstrap_info();
|
||||
nd_tasklet_network_state_changed(MESH_CONNECTED);
|
||||
}
|
||||
break;
|
||||
case ARM_NWK_NWK_SCAN_FAIL:
|
||||
/* Link Layer Active Scan Fail, Stack is Already at Idle state */
|
||||
tr_debug("Link Layer Scan Fail: No Beacons");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
nd_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL:
|
||||
/* No ND Router at current Channel Stack is Already at Idle state */
|
||||
tr_debug("ND Scan/ GP REG fail");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
nd_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_NWK_CONNECTION_DOWN:
|
||||
/* Connection to Access point is lost wait for Scan Result */
|
||||
tr_debug("ND/RPL scan new network");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
nd_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_NWK_PARENT_POLL_FAIL:
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
nd_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_AUHTENTICATION_FAIL:
|
||||
tr_debug("Network authentication fail");
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
nd_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
default:
|
||||
tr_warn("Unknown event %d", status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY &&
|
||||
tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
// Set 5s timer for new network scan
|
||||
eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
|
||||
ARM_LIB_SYSTEM_TIMER_EVENT,
|
||||
tasklet_data_ptr->tasklet,
|
||||
5000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Configure and establish network connection
|
||||
*
|
||||
*/
|
||||
void nd_tasklet_configure_and_connect_to_network(void)
|
||||
{
|
||||
int8_t status;
|
||||
char *sec_mode;
|
||||
|
||||
// configure bootstrap
|
||||
arm_nwk_interface_configure_6lowpan_bootstrap_set(
|
||||
tasklet_data_ptr->network_interface_id, tasklet_data_ptr->mode,
|
||||
NET_6LOWPAN_ND_WITH_MLE);
|
||||
|
||||
sec_mode = STR(MBED_CONF_MBED_MESH_API_6LOWPAN_ND_SECURITY_MODE);
|
||||
|
||||
if (strcmp(sec_mode, "PSK") == 0) {
|
||||
tr_debug("Using PSK security mode.");
|
||||
tasklet_data_ptr->sec_mode = NET_SEC_MODE_PSK_LINK_SECURITY;
|
||||
tasklet_data_ptr->psk_sec_info.key_id = MBED_CONF_MBED_MESH_API_6LOWPAN_ND_PSK_KEY_ID;
|
||||
memcpy(tasklet_data_ptr->psk_sec_info.security_key, (const uint8_t[16])MBED_CONF_MBED_MESH_API_6LOWPAN_ND_PSK_KEY, 16);
|
||||
} else {
|
||||
tr_debug("Link-layer security NOT enabled.");
|
||||
tasklet_data_ptr->sec_mode = NET_SEC_MODE_NO_LINK_SECURITY;
|
||||
}
|
||||
|
||||
// configure link layer security
|
||||
arm_nwk_link_layer_security_mode(
|
||||
tasklet_data_ptr->network_interface_id,
|
||||
tasklet_data_ptr->sec_mode,
|
||||
MBED_CONF_MBED_MESH_API_6LOWPAN_ND_SEC_LEVEL,
|
||||
&tasklet_data_ptr->psk_sec_info);
|
||||
|
||||
// configure scan parameters
|
||||
arm_nwk_6lowpan_link_scan_parameter_set(tasklet_data_ptr->network_interface_id, 5);
|
||||
|
||||
// configure scan channels
|
||||
initialize_channel_list();
|
||||
|
||||
// Configure scan options (NULL disables filter)
|
||||
arm_nwk_6lowpan_link_nwk_id_filter_for_nwk_scan(
|
||||
tasklet_data_ptr->network_interface_id, NULL);
|
||||
|
||||
arm_nwk_6lowpan_link_panid_filter_for_nwk_scan(
|
||||
tasklet_data_ptr->network_interface_id,
|
||||
MBED_CONF_MBED_MESH_API_6LOWPAN_ND_PANID_FILTER);
|
||||
|
||||
// Enable MPL by default
|
||||
const uint8_t all_mpl_forwarders[16] = {0xff, 0x03, [15] = 0xfc};
|
||||
multicast_mpl_domain_subscribe(tasklet_data_ptr->network_interface_id,
|
||||
all_mpl_forwarders,
|
||||
MULTICAST_MPL_SEED_ID_DEFAULT,
|
||||
NULL);
|
||||
|
||||
status = arm_nwk_interface_up(tasklet_data_ptr->network_interface_id);
|
||||
if (status >= 0) {
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
|
||||
tr_info("Start 6LoWPAN ND Bootstrap");
|
||||
nd_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
|
||||
} else {
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
tr_err("Bootstrap start failed, %d", status);
|
||||
nd_tasklet_network_state_changed(MESH_BOOTSTRAP_START_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform application about network state change
|
||||
*/
|
||||
void nd_tasklet_network_state_changed(mesh_connection_status_t status)
|
||||
{
|
||||
if (tasklet_data_ptr->mesh_api_cb) {
|
||||
(tasklet_data_ptr->mesh_api_cb)(status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trace bootstrap information.
|
||||
*/
|
||||
#ifdef TRACE_ND_TASKLET
|
||||
void nd_tasklet_trace_bootstrap_info()
|
||||
{
|
||||
network_layer_address_s app_nd_address_info;
|
||||
link_layer_address_s app_link_address_info;
|
||||
uint8_t temp_ipv6[16];
|
||||
if (arm_nwk_nd_address_read(tasklet_data_ptr->network_interface_id,
|
||||
&app_nd_address_info) != 0) {
|
||||
tr_error("ND Address read fail");
|
||||
} else {
|
||||
tr_debug("ND Access Point: %s", trace_ipv6(app_nd_address_info.border_router));
|
||||
tr_debug("ND Prefix 64: %s", trace_array(app_nd_address_info.prefix, 8));
|
||||
|
||||
if (arm_net_address_get(tasklet_data_ptr->network_interface_id,
|
||||
ADDR_IPV6_GP, temp_ipv6) == 0) {
|
||||
tr_debug("GP IPv6: %s", trace_ipv6(temp_ipv6));
|
||||
}
|
||||
}
|
||||
|
||||
if (arm_nwk_mac_address_read(tasklet_data_ptr->network_interface_id,
|
||||
&app_link_address_info) != 0) {
|
||||
tr_error("MAC Address read fail\n");
|
||||
} else {
|
||||
uint8_t temp[2];
|
||||
common_write_16_bit(app_link_address_info.mac_short, temp);
|
||||
tr_debug("MAC 16-bit: %s", trace_array(temp, 2));
|
||||
common_write_16_bit(app_link_address_info.PANId, temp);
|
||||
tr_debug("PAN ID: %s", trace_array(temp, 2));
|
||||
tr_debug("MAC 64-bit: %s", trace_array(app_link_address_info.mac_long, 8));
|
||||
tr_debug("IID (Based on MAC 64-bit address): %s", trace_array(app_link_address_info.iid_eui64, 8));
|
||||
}
|
||||
|
||||
tr_debug("Channel: %d", arm_net_get_current_channel(tasklet_data_ptr->network_interface_id));
|
||||
}
|
||||
#endif /* #define TRACE_ND_TASKLET */
|
||||
|
||||
/* Public functions */
|
||||
int8_t nd_tasklet_get_router_ip_address(char *address, int8_t len)
|
||||
{
|
||||
network_layer_address_s nd_address;
|
||||
|
||||
if ((len >= 40) && (0 == arm_nwk_nd_address_read(
|
||||
tasklet_data_ptr->network_interface_id, &nd_address))) {
|
||||
ip6tos(nd_address.border_router, address);
|
||||
//tr_debug("Router IP address: %s", address);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t nd_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id)
|
||||
{
|
||||
int8_t re_connecting = true;
|
||||
int8_t tasklet_id = tasklet_data_ptr->tasklet;
|
||||
|
||||
if (tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
return -3; // already connected to network
|
||||
}
|
||||
|
||||
if (tasklet_data_ptr->tasklet_state == TASKLET_STATE_CREATED) {
|
||||
re_connecting = false;
|
||||
}
|
||||
|
||||
memset(tasklet_data_ptr, 0, sizeof(tasklet_data_str_t));
|
||||
tasklet_data_ptr->mesh_api_cb = callback;
|
||||
tasklet_data_ptr->network_interface_id = nwk_interface_id;
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_INITIALIZED;
|
||||
|
||||
tasklet_data_ptr->mode = MBED_CONF_MBED_MESH_API_6LOWPAN_ND_DEVICE_TYPE;
|
||||
tasklet_data_ptr->sec_mode = NET_SEC_MODE_NO_LINK_SECURITY;
|
||||
//tasklet_data_ptr->psk_sec_info.key_id = 0;
|
||||
|
||||
if (re_connecting == false) {
|
||||
tasklet_data_ptr->tasklet = eventOS_event_handler_create(&nd_tasklet_main,
|
||||
ARM_LIB_TASKLET_INIT_EVENT);
|
||||
if (tasklet_data_ptr->tasklet < 0) {
|
||||
// -1 handler already used by other tasklet
|
||||
// -2 memory allocation failure
|
||||
return tasklet_data_ptr->tasklet;
|
||||
}
|
||||
} else {
|
||||
tasklet_data_ptr->tasklet = tasklet_id;
|
||||
eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
|
||||
ARM_LIB_SYSTEM_TIMER_EVENT,
|
||||
tasklet_data_ptr->tasklet,
|
||||
500);
|
||||
}
|
||||
|
||||
return tasklet_data_ptr->tasklet;
|
||||
}
|
||||
|
||||
int8_t nd_tasklet_disconnect(bool send_cb)
|
||||
{
|
||||
int8_t status = -1;
|
||||
if (tasklet_data_ptr != NULL) {
|
||||
if (tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
status = arm_nwk_interface_down(tasklet_data_ptr->network_interface_id);
|
||||
tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
|
||||
if (send_cb == true) {
|
||||
nd_tasklet_network_state_changed(MESH_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
tasklet_data_ptr->mesh_api_cb = NULL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void nd_tasklet_init(void)
|
||||
{
|
||||
if (tasklet_data_ptr == NULL) {
|
||||
// memory allocation will not fail as memory was just initialized
|
||||
tasklet_data_ptr = ns_dyn_mem_alloc(sizeof(tasklet_data_str_t));
|
||||
tasklet_data_ptr->tasklet_state = TASKLET_STATE_CREATED;
|
||||
tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t nd_tasklet_network_init(int8_t device_id)
|
||||
{
|
||||
// TODO, read interface name from configuration
|
||||
mac_description_storage_size_t storage_sizes;
|
||||
storage_sizes.device_decription_table_size = MBED_CONF_MBED_MESH_API_MAC_NEIGH_TABLE_SIZE;
|
||||
storage_sizes.key_description_table_size = 3;
|
||||
storage_sizes.key_lookup_size = 1;
|
||||
storage_sizes.key_usage_size = 3;
|
||||
if (!mac_api) {
|
||||
mac_api = ns_sw_mac_create(device_id, &storage_sizes);
|
||||
}
|
||||
return arm_nwk_interface_lowpan_init(mac_api, INTERFACE_NAME);
|
||||
}
|
||||
|
||||
514
connectivity/nanostack/mbed-mesh-api/source/thread_tasklet.c
Normal file
514
connectivity/nanostack/mbed-mesh-api/source/thread_tasklet.c
Normal file
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h> //memset
|
||||
#include "eventOS_event_timer.h"
|
||||
#include "common_functions.h"
|
||||
#include "net_interface.h"
|
||||
#include "ip6string.h" //ip6tos
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "thread_management_if.h"
|
||||
#include "net_polling_api.h"
|
||||
#include "include/thread_tasklet.h"
|
||||
#include "include/mesh_system.h"
|
||||
#include <mbed_assert.h>
|
||||
#include "ns_event_loop.h"
|
||||
|
||||
// For tracing we need to define flag, have include and define group
|
||||
#define HAVE_DEBUG 1
|
||||
#include "ns_trace.h"
|
||||
#define TRACE_GROUP "m6Thread"
|
||||
|
||||
#include "mac_api.h"
|
||||
#include "sw_mac.h"
|
||||
|
||||
#define DETAILED_TRACES
|
||||
#ifdef DETAILED_TRACES
|
||||
#define TRACE_DETAIL tr_debug
|
||||
#else
|
||||
#define TRACE_DETAIL(...)
|
||||
#endif
|
||||
|
||||
#define INTERFACE_NAME "6L-THREAD"
|
||||
|
||||
// Tasklet timer events
|
||||
#define TIMER_EVENT_START_BOOTSTRAP 1
|
||||
|
||||
#define INVALID_INTERFACE_ID (-1)
|
||||
|
||||
/*
|
||||
* Thread tasklet states.
|
||||
*/
|
||||
typedef enum {
|
||||
TASKLET_STATE_CREATED = 0,
|
||||
TASKLET_STATE_INITIALIZED,
|
||||
TASKLET_STATE_BOOTSTRAP_STARTED,
|
||||
TASKLET_STATE_BOOTSTRAP_FAILED,
|
||||
TASKLET_STATE_BOOTSTRAP_READY
|
||||
} tasklet_state_t;
|
||||
|
||||
/*
|
||||
* Mesh tasklet data structure.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*mesh_api_cb)(mesh_connection_status_t nwk_status);
|
||||
channel_list_s channel_list;
|
||||
tasklet_state_t tasklet_state;
|
||||
mesh_connection_status_t connection_status;
|
||||
timeout_t *poll_network_status_timeout;
|
||||
int8_t tasklet;
|
||||
|
||||
net_6lowpan_mode_e operating_mode;
|
||||
int8_t nwk_if_id;
|
||||
link_configuration_s link_config;
|
||||
|
||||
/** Default network ID*/
|
||||
uint8_t networkid[16];
|
||||
uint8_t extented_panid[8];
|
||||
uint8_t ip[16];
|
||||
} thread_tasklet_data_str_t;
|
||||
|
||||
|
||||
/* Tasklet data */
|
||||
static thread_tasklet_data_str_t *thread_tasklet_data_ptr = NULL;
|
||||
static mac_api_t *mac_api = NULL;
|
||||
static device_configuration_s device_configuration;
|
||||
|
||||
/* private function prototypes */
|
||||
void thread_tasklet_main(arm_event_s *event);
|
||||
void thread_tasklet_network_state_changed(mesh_connection_status_t status);
|
||||
void thread_tasklet_parse_network_event(arm_event_s *event);
|
||||
void thread_tasklet_configure_and_connect_to_network(void);
|
||||
void thread_tasklet_poll_network_status(void *param);
|
||||
#define TRACE_THREAD_TASKLET
|
||||
#ifndef TRACE_THREAD_TASKLET
|
||||
#define thread_tasklet_trace_bootstrap_info() ((void) 0)
|
||||
#else
|
||||
void thread_tasklet_trace_bootstrap_info(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* \brief A function which will be eventually called by NanoStack OS when ever the OS has an event to deliver.
|
||||
* @param event, describes the sender, receiver and event type.
|
||||
*
|
||||
* NOTE: Interrupts requested by HW are possible during this function!
|
||||
*/
|
||||
void thread_tasklet_main(arm_event_s *event)
|
||||
{
|
||||
arm_library_event_type_e event_type;
|
||||
event_type = (arm_library_event_type_e) event->event_type;
|
||||
|
||||
switch (event_type) {
|
||||
case ARM_LIB_NWK_INTERFACE_EVENT:
|
||||
/* This event is delivered every and each time when there is new
|
||||
* information of network connectivity.
|
||||
*/
|
||||
thread_tasklet_parse_network_event(event);
|
||||
break;
|
||||
|
||||
case ARM_LIB_TASKLET_INIT_EVENT:
|
||||
/* Event with type EV_INIT is an initializer event of NanoStack OS.
|
||||
* The event is delivered when the NanoStack OS is running fine.
|
||||
* This event should be delivered ONLY ONCE.
|
||||
*/
|
||||
mesh_system_send_connect_event(thread_tasklet_data_ptr->tasklet);
|
||||
break;
|
||||
|
||||
case ARM_LIB_SYSTEM_TIMER_EVENT:
|
||||
eventOS_event_timer_cancel(event->event_id,
|
||||
thread_tasklet_data_ptr->tasklet);
|
||||
|
||||
if (event->event_id == TIMER_EVENT_START_BOOTSTRAP) {
|
||||
int8_t status;
|
||||
tr_debug("Restart bootstrap");
|
||||
status = arm_nwk_interface_up(thread_tasklet_data_ptr->nwk_if_id);
|
||||
|
||||
if (status >= 0) {
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
|
||||
tr_info("Start Thread bootstrap (%s mode)", thread_tasklet_data_ptr->operating_mode == NET_6LOWPAN_SLEEPY_HOST ? "SED" : "Router");
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
|
||||
} else {
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
tr_err("Bootstrap start failed, %d", status);
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_START_FAILED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case APPLICATION_EVENT:
|
||||
if (event->event_id == APPL_EVENT_CONNECT) {
|
||||
thread_tasklet_configure_and_connect_to_network();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
} // switch(event_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Network state event handler.
|
||||
* \param event show network start response or current network state.
|
||||
*
|
||||
* - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role
|
||||
* - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state
|
||||
* - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No ND Router at current Channel Stack is Already at Idle state
|
||||
* - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result
|
||||
* - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels
|
||||
* - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state
|
||||
*/
|
||||
void thread_tasklet_parse_network_event(arm_event_s *event)
|
||||
{
|
||||
arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data;
|
||||
tr_debug("app_parse_network_event() %d", status);
|
||||
switch (status) {
|
||||
case ARM_NWK_BOOTSTRAP_READY:
|
||||
/* Network is ready and node is connected to Access Point */
|
||||
if (thread_tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
|
||||
tr_info("Thread bootstrap ready");
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY;
|
||||
thread_tasklet_trace_bootstrap_info();
|
||||
/* We are connected, for Local or Global IP */
|
||||
thread_tasklet_poll_network_status(NULL);
|
||||
}
|
||||
break;
|
||||
case ARM_NWK_NWK_SCAN_FAIL:
|
||||
/* Link Layer Active Scan Fail, Stack is Already at Idle state */
|
||||
tr_debug("Link Layer Scan Fail: No Beacons");
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL:
|
||||
/* No ND Router at current Channel Stack is Already at Idle state */
|
||||
tr_debug("ND Scan/ GP REG fail");
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_NWK_CONNECTION_DOWN:
|
||||
/* Connection to Access point is lost wait for Scan Result */
|
||||
tr_debug("ND/RPL scan new network");
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_NWK_PARENT_POLL_FAIL:
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_AUHTENTICATION_FAIL:
|
||||
tr_debug("Network authentication fail");
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
default:
|
||||
tr_warn("Unknown event %d", status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (thread_tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY &&
|
||||
thread_tasklet_data_ptr->nwk_if_id != INVALID_INTERFACE_ID) {
|
||||
// Set 5s timer for a new network scan
|
||||
eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
|
||||
ARM_LIB_SYSTEM_TIMER_EVENT,
|
||||
thread_tasklet_data_ptr->tasklet,
|
||||
5000);
|
||||
}
|
||||
}
|
||||
|
||||
void thread_tasklet_poll_network_status(void *param)
|
||||
{
|
||||
/* Check if we do have an IP */
|
||||
uint8_t temp_ipv6[16];
|
||||
if (arm_net_address_get(thread_tasklet_data_ptr->nwk_if_id, ADDR_IPV6_GP, temp_ipv6) == 0) {
|
||||
/* Check if this is the same IP than previously */
|
||||
if (memcmp(temp_ipv6, thread_tasklet_data_ptr->ip, 16) == 0) {
|
||||
return;
|
||||
} else {
|
||||
memcpy(thread_tasklet_data_ptr->ip, temp_ipv6, 16);
|
||||
link_configuration_s *link_cfg = thread_management_configuration_get(thread_tasklet_data_ptr->nwk_if_id);
|
||||
if (memcmp(thread_tasklet_data_ptr->ip, link_cfg->mesh_local_ula_prefix, 8) == 0) {
|
||||
thread_tasklet_network_state_changed(MESH_CONNECTED_LOCAL);
|
||||
} else {
|
||||
thread_tasklet_network_state_changed(MESH_CONNECTED_GLOBAL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thread_tasklet_data_ptr->connection_status = MESH_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
void read_link_configuration()
|
||||
{
|
||||
|
||||
thread_tasklet_data_ptr->link_config.panId = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_PANID;
|
||||
TRACE_DETAIL("PANID %x", thread_tasklet_data_ptr->link_config.panId);
|
||||
|
||||
thread_tasklet_data_ptr->link_config.rfChannel = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL;
|
||||
TRACE_DETAIL("channel: %d", thread_tasklet_data_ptr->link_config.rfChannel);
|
||||
|
||||
// Mesh prefix
|
||||
const uint8_t mesh_local_prefix[] = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_ML_PREFIX;
|
||||
MBED_ASSERT(sizeof(mesh_local_prefix) == 8);
|
||||
|
||||
memcpy(thread_tasklet_data_ptr->link_config.mesh_local_ula_prefix, mesh_local_prefix, 8);
|
||||
TRACE_DETAIL("Mesh prefix: %s", trace_array(mesh_local_prefix, 8));
|
||||
|
||||
// Master Key
|
||||
const uint8_t master_key[] = MBED_CONF_MBED_MESH_API_THREAD_MASTER_KEY;
|
||||
MBED_ASSERT(sizeof(master_key) == 16);
|
||||
memcpy(thread_tasklet_data_ptr->link_config.master_key, master_key, 16);
|
||||
|
||||
// PSKc
|
||||
const uint8_t PSKc[] = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_PSKC;
|
||||
MBED_ASSERT(sizeof(PSKc) == 16);
|
||||
memcpy(thread_tasklet_data_ptr->link_config.PSKc, PSKc, 16);
|
||||
|
||||
thread_tasklet_data_ptr->link_config.key_rotation = 3600;
|
||||
thread_tasklet_data_ptr->link_config.key_sequence = 0;
|
||||
|
||||
thread_tasklet_data_ptr->link_config.securityPolicy = MBED_CONF_MBED_MESH_API_THREAD_SECURITY_POLICY;
|
||||
|
||||
// network name
|
||||
MBED_ASSERT(strlen(MBED_CONF_MBED_MESH_API_THREAD_CONFIG_NETWORK_NAME) > 0 && strlen(MBED_CONF_MBED_MESH_API_THREAD_CONFIG_NETWORK_NAME) < 17);
|
||||
memcpy(thread_tasklet_data_ptr->link_config.name, MBED_CONF_MBED_MESH_API_THREAD_CONFIG_NETWORK_NAME, strlen(MBED_CONF_MBED_MESH_API_THREAD_CONFIG_NETWORK_NAME));
|
||||
|
||||
thread_tasklet_data_ptr->link_config.timestamp = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_COMMISSIONING_DATASET_TIMESTAMP;
|
||||
|
||||
// extended pan-id
|
||||
const uint8_t extented_panid[] = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_EXTENDED_PANID;
|
||||
MBED_ASSERT(sizeof(extented_panid) == 8);
|
||||
memcpy(thread_tasklet_data_ptr->link_config.extented_pan_id, extented_panid, sizeof(extented_panid));
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Configure mesh network
|
||||
*
|
||||
*/
|
||||
void thread_tasklet_configure_and_connect_to_network(void)
|
||||
{
|
||||
int8_t status;
|
||||
link_configuration_s *temp_link_config = NULL;
|
||||
|
||||
|
||||
if (MBED_CONF_MBED_MESH_API_THREAD_DEVICE_TYPE == MESH_DEVICE_TYPE_THREAD_MINIMAL_END_DEVICE) {
|
||||
thread_tasklet_data_ptr->operating_mode = NET_6LOWPAN_HOST;
|
||||
} else if (MBED_CONF_MBED_MESH_API_THREAD_DEVICE_TYPE == MESH_DEVICE_TYPE_THREAD_SLEEPY_END_DEVICE) {
|
||||
thread_tasklet_data_ptr->operating_mode = NET_6LOWPAN_SLEEPY_HOST;
|
||||
} else {
|
||||
thread_tasklet_data_ptr->operating_mode = NET_6LOWPAN_ROUTER;
|
||||
}
|
||||
|
||||
arm_nwk_interface_configure_6lowpan_bootstrap_set(
|
||||
thread_tasklet_data_ptr->nwk_if_id,
|
||||
thread_tasklet_data_ptr->operating_mode,
|
||||
NET_6LOWPAN_THREAD);
|
||||
|
||||
thread_tasklet_data_ptr->channel_list.channel_page = (channel_page_e)MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL_PAGE;
|
||||
thread_tasklet_data_ptr->channel_list.channel_mask[0] = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL_MASK;
|
||||
|
||||
TRACE_DETAIL("channel page: %d", thread_tasklet_data_ptr->channel_list.channel_page);
|
||||
TRACE_DETAIL("channel mask: 0x%.8" PRIx32, thread_tasklet_data_ptr->channel_list.channel_mask[0]);
|
||||
|
||||
// PSKd
|
||||
const char PSKd[] = MBED_CONF_MBED_MESH_API_THREAD_PSKD;
|
||||
if (device_configuration.PSKd_len == 0) {
|
||||
int ret = thread_tasklet_device_pskd_set(PSKd);
|
||||
MBED_ASSERT(!ret);
|
||||
}
|
||||
|
||||
if (true == MBED_CONF_MBED_MESH_API_THREAD_USE_STATIC_LINK_CONFIG) {
|
||||
read_link_configuration();
|
||||
temp_link_config = &thread_tasklet_data_ptr->link_config;
|
||||
}
|
||||
|
||||
thread_management_node_init(thread_tasklet_data_ptr->nwk_if_id,
|
||||
&thread_tasklet_data_ptr->channel_list,
|
||||
&device_configuration,
|
||||
temp_link_config);
|
||||
|
||||
status = arm_nwk_interface_up(thread_tasklet_data_ptr->nwk_if_id);
|
||||
|
||||
if (status >= 0) {
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
|
||||
tr_info("Start Thread bootstrap (%s mode)", thread_tasklet_data_ptr->operating_mode == NET_6LOWPAN_SLEEPY_HOST ? "SED" : "Router");
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
|
||||
} else {
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
tr_err("Bootstrap start failed, %d", status);
|
||||
thread_tasklet_network_state_changed(MESH_BOOTSTRAP_START_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform application about network state change
|
||||
*/
|
||||
void thread_tasklet_network_state_changed(mesh_connection_status_t status)
|
||||
{
|
||||
thread_tasklet_data_ptr->connection_status = status;
|
||||
if (thread_tasklet_data_ptr->mesh_api_cb) {
|
||||
(thread_tasklet_data_ptr->mesh_api_cb)(status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Trace bootstrap information.
|
||||
*/
|
||||
#ifdef TRACE_THREAD_TASKLET
|
||||
void thread_tasklet_trace_bootstrap_info()
|
||||
{
|
||||
link_layer_address_s app_link_address_info;
|
||||
uint8_t temp_ipv6[16];
|
||||
if (arm_net_address_get(thread_tasklet_data_ptr->nwk_if_id,
|
||||
ADDR_IPV6_GP, temp_ipv6) == 0) {
|
||||
tr_debug("GP IPv6: %s", trace_ipv6(temp_ipv6));
|
||||
}
|
||||
|
||||
if (arm_nwk_mac_address_read(thread_tasklet_data_ptr->nwk_if_id,
|
||||
&app_link_address_info) != 0) {
|
||||
tr_error("MAC Address read fail\n");
|
||||
} else {
|
||||
uint8_t temp[2];
|
||||
common_write_16_bit(app_link_address_info.mac_short, temp);
|
||||
tr_debug("MAC 16-bit: %s", trace_array(temp, 2));
|
||||
common_write_16_bit(app_link_address_info.PANId, temp);
|
||||
tr_debug("PAN ID: %s", trace_array(temp, 2));
|
||||
tr_debug("MAC 64-bit: %s", trace_array(app_link_address_info.mac_long, 8));
|
||||
tr_debug("IID (Based on MAC 64-bit address): %s", trace_array(app_link_address_info.iid_eui64, 8));
|
||||
}
|
||||
}
|
||||
#endif /* #define TRACE_THREAD_TASKLET */
|
||||
|
||||
int8_t thread_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id)
|
||||
{
|
||||
int8_t re_connecting = true;
|
||||
int8_t tasklet = thread_tasklet_data_ptr->tasklet;
|
||||
|
||||
if (thread_tasklet_data_ptr->nwk_if_id != INVALID_INTERFACE_ID) {
|
||||
return -3; // already connected to network
|
||||
}
|
||||
|
||||
if (thread_tasklet_data_ptr->tasklet_state == TASKLET_STATE_CREATED) {
|
||||
re_connecting = false;
|
||||
}
|
||||
|
||||
memset(thread_tasklet_data_ptr, 0, sizeof(thread_tasklet_data_str_t));
|
||||
thread_tasklet_data_ptr->mesh_api_cb = callback;
|
||||
thread_tasklet_data_ptr->nwk_if_id = nwk_interface_id;
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_INITIALIZED;
|
||||
thread_tasklet_data_ptr->poll_network_status_timeout =
|
||||
eventOS_timeout_every_ms(thread_tasklet_poll_network_status, 2000, NULL);
|
||||
|
||||
if (re_connecting == false) {
|
||||
thread_tasklet_data_ptr->tasklet = eventOS_event_handler_create(&thread_tasklet_main,
|
||||
ARM_LIB_TASKLET_INIT_EVENT);
|
||||
if (thread_tasklet_data_ptr->tasklet < 0) {
|
||||
// -1 handler already used by other tasklet
|
||||
// -2 memory allocation failure
|
||||
return thread_tasklet_data_ptr->tasklet;
|
||||
}
|
||||
} else {
|
||||
thread_tasklet_data_ptr->tasklet = tasklet;
|
||||
mesh_system_send_connect_event(thread_tasklet_data_ptr->tasklet);
|
||||
}
|
||||
|
||||
return thread_tasklet_data_ptr->tasklet;
|
||||
}
|
||||
|
||||
int8_t thread_tasklet_disconnect(bool send_cb)
|
||||
{
|
||||
int8_t status = -1;
|
||||
// check that module is initialized
|
||||
if (thread_tasklet_data_ptr != NULL) {
|
||||
if (thread_tasklet_data_ptr->nwk_if_id != INVALID_INTERFACE_ID) {
|
||||
status = arm_nwk_interface_down(thread_tasklet_data_ptr->nwk_if_id);
|
||||
thread_tasklet_data_ptr->nwk_if_id = INVALID_INTERFACE_ID;
|
||||
if (send_cb == true) {
|
||||
thread_tasklet_network_state_changed(MESH_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear callback, it will be set again in next connect
|
||||
thread_tasklet_data_ptr->mesh_api_cb = NULL;
|
||||
// Cancel the callback timeout
|
||||
eventOS_timeout_cancel(thread_tasklet_data_ptr->poll_network_status_timeout);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void thread_tasklet_init(void)
|
||||
{
|
||||
if (thread_tasklet_data_ptr == NULL) {
|
||||
thread_tasklet_data_ptr = ns_dyn_mem_alloc(sizeof(thread_tasklet_data_str_t));
|
||||
memset(thread_tasklet_data_ptr, 0, sizeof(thread_tasklet_data_str_t));
|
||||
thread_tasklet_data_ptr->tasklet_state = TASKLET_STATE_CREATED;
|
||||
thread_tasklet_data_ptr->nwk_if_id = INVALID_INTERFACE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t thread_tasklet_network_init(int8_t device_id)
|
||||
{
|
||||
// TODO, read interface name from configuration
|
||||
mac_description_storage_size_t storage_sizes;
|
||||
storage_sizes.device_decription_table_size = MBED_CONF_MBED_MESH_API_MAC_NEIGH_TABLE_SIZE;
|
||||
storage_sizes.key_description_table_size = 6;
|
||||
storage_sizes.key_lookup_size = 1;
|
||||
storage_sizes.key_usage_size = 3;
|
||||
if (!mac_api) {
|
||||
mac_api = ns_sw_mac_create(device_id, &storage_sizes);
|
||||
}
|
||||
return arm_nwk_interface_lowpan_init(mac_api, INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void thread_tasklet_device_eui64_set(const uint8_t *eui64)
|
||||
{
|
||||
memcpy(device_configuration.eui64, eui64, 8);
|
||||
}
|
||||
|
||||
void thread_tasklet_device_eui64_get(uint8_t *eui64)
|
||||
{
|
||||
memcpy(eui64, device_configuration.eui64, 8);
|
||||
}
|
||||
|
||||
uint8_t thread_tasklet_device_pskd_set(const char *pskd)
|
||||
{
|
||||
int len = strlen(pskd);
|
||||
if (len < 6 || len > 32) {
|
||||
return MESH_ERROR_PARAM;
|
||||
}
|
||||
char *dyn_buf = ns_dyn_mem_alloc(strlen(pskd) + 1);
|
||||
if (!dyn_buf) {
|
||||
return MESH_ERROR_MEMORY;
|
||||
}
|
||||
strcpy(dyn_buf, pskd);
|
||||
ns_dyn_mem_free(device_configuration.PSKd_ptr);
|
||||
device_configuration.PSKd_ptr = (uint8_t *)dyn_buf;
|
||||
device_configuration.PSKd_len = strlen(pskd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int8_t thread_tasklet_data_poll_rate_set(uint32_t timeout)
|
||||
{
|
||||
int8_t status = -1;
|
||||
if (thread_tasklet_data_ptr) {
|
||||
if (timeout != 0) {
|
||||
status = arm_nwk_host_mode_set(thread_tasklet_data_ptr->nwk_if_id, NET_HOST_SLOW_POLL_MODE, timeout);
|
||||
} else {
|
||||
status = arm_nwk_host_mode_set(thread_tasklet_data_ptr->nwk_if_id, NET_HOST_RX_ON_IDLE, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
644
connectivity/nanostack/mbed-mesh-api/source/wisun_tasklet.c
Normal file
644
connectivity/nanostack/mbed-mesh-api/source/wisun_tasklet.c
Normal file
@@ -0,0 +1,644 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 ARM Limited. All rights reserved.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h> //memset
|
||||
#include "eventOS_event_timer.h"
|
||||
#include "common_functions.h"
|
||||
#include "ip6string.h" //ip6tos
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "include/wisun_tasklet.h"
|
||||
#include "include/mesh_system.h"
|
||||
#include "ns_event_loop.h"
|
||||
#include "fhss_api.h"
|
||||
#include "fhss_config.h"
|
||||
#include "multicast_api.h"
|
||||
#include "mac_api.h"
|
||||
#include "sw_mac.h"
|
||||
#include "ns_list.h"
|
||||
#include "net_interface.h"
|
||||
#include "nwk_stats_api.h"
|
||||
#include "ws_management_api.h" //ws_management_node_init
|
||||
#ifdef MBED_CONF_MBED_MESH_API_CERTIFICATE_HEADER
|
||||
#if !defined(MBED_CONF_MBED_MESH_API_ROOT_CERTIFICATE) || !defined(MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE) || \
|
||||
!defined(MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_KEY)
|
||||
#error Invalid Wi-SUN certificate configuration
|
||||
#endif
|
||||
#include MBED_CONF_MBED_MESH_API_CERTIFICATE_HEADER
|
||||
#endif
|
||||
|
||||
|
||||
// For tracing we need to define flag, have include and define group
|
||||
//#define HAVE_DEBUG
|
||||
#define TRACE_GROUP "WSND"
|
||||
#include "ns_trace.h"
|
||||
|
||||
// Tasklet timer events
|
||||
#define TIMER_EVENT_START_BOOTSTRAP 1
|
||||
#define INVALID_INTERFACE_ID (-1)
|
||||
#define INTERFACE_NAME "WiSunInterface"
|
||||
/*
|
||||
* Mesh tasklet states.
|
||||
*/
|
||||
typedef enum {
|
||||
TASKLET_STATE_CREATED = 0,
|
||||
TASKLET_STATE_INITIALIZED,
|
||||
TASKLET_STATE_BOOTSTRAP_STARTED,
|
||||
TASKLET_STATE_BOOTSTRAP_FAILED,
|
||||
TASKLET_STATE_BOOTSTRAP_READY
|
||||
} tasklet_state_t;
|
||||
|
||||
/*
|
||||
* Mesh tasklet data structure.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*mesh_api_cb)(mesh_connection_status_t nwk_status);
|
||||
tasklet_state_t tasklet_state;
|
||||
int8_t tasklet;
|
||||
net_6lowpan_mode_e operating_mode;
|
||||
net_6lowpan_mode_extension_e operating_mode_extension;
|
||||
int8_t network_interface_id;
|
||||
} wisun_tasklet_data_str_t;
|
||||
|
||||
typedef struct {
|
||||
arm_certificate_entry_s arm_cert_entry;
|
||||
ns_list_link_t link; /*!< List link entry */
|
||||
} wisun_certificate_entry_t;
|
||||
|
||||
typedef NS_LIST_HEAD(wisun_certificate_entry_t, link) cert_list_t;
|
||||
typedef struct {
|
||||
cert_list_t own_certificates_list;
|
||||
cert_list_t trusted_certificates_list;
|
||||
bool remove_own_certificates: 1;
|
||||
bool remove_trusted_certificates: 1;
|
||||
} wisun_certificates_t;
|
||||
|
||||
/* Tasklet data */
|
||||
static wisun_tasklet_data_str_t *wisun_tasklet_data_ptr = NULL;
|
||||
static wisun_certificates_t *wisun_certificates_ptr = NULL;
|
||||
static mac_api_t *mac_api = NULL;
|
||||
|
||||
typedef struct {
|
||||
nwk_stats_t nwk_stats;
|
||||
mac_statistics_t mac_statistics;
|
||||
ws_statistics_t ws_statistics;
|
||||
} wisun_statistics_t;
|
||||
|
||||
static bool statistics_started = false;
|
||||
static wisun_statistics_t *statistics = NULL;
|
||||
|
||||
extern fhss_timer_t fhss_functions;
|
||||
|
||||
/* private function prototypes */
|
||||
static void wisun_tasklet_main(arm_event_s *event);
|
||||
static void wisun_tasklet_network_state_changed(mesh_connection_status_t status);
|
||||
static void wisun_tasklet_parse_network_event(arm_event_s *event);
|
||||
static void wisun_tasklet_configure_and_connect_to_network(void);
|
||||
static void wisun_tasklet_clear_stored_certificates(void) ;
|
||||
static int wisun_tasklet_store_certificate_data(const uint8_t *cert, uint16_t cert_len, const uint8_t *cert_key, uint16_t cert_key_len, bool remove_own, bool remove_trusted, bool trusted_cert);
|
||||
static int wisun_tasklet_add_stored_certificates(void) ;
|
||||
static void wisun_tasklet_statistics_do_start(void);
|
||||
|
||||
/*
|
||||
* \brief A function which will be eventually called by NanoStack OS when ever the OS has an event to deliver.
|
||||
* @param event, describes the sender, receiver and event type.
|
||||
*
|
||||
* NOTE: Interrupts requested by HW are possible during this function!
|
||||
*/
|
||||
static void wisun_tasklet_main(arm_event_s *event)
|
||||
{
|
||||
arm_library_event_type_e event_type;
|
||||
event_type = (arm_library_event_type_e) event->event_type;
|
||||
|
||||
switch (event_type) {
|
||||
case ARM_LIB_NWK_INTERFACE_EVENT:
|
||||
/* This event is delivered every and each time when there is new
|
||||
* information of network connectivity.
|
||||
*/
|
||||
wisun_tasklet_parse_network_event(event);
|
||||
break;
|
||||
|
||||
case ARM_LIB_TASKLET_INIT_EVENT:
|
||||
/* Event with type EV_INIT is an initializer event of NanoStack OS.
|
||||
* The event is delivered when the NanoStack OS is running fine.
|
||||
* This event should be delivered ONLY ONCE.
|
||||
*/
|
||||
mesh_system_send_connect_event(wisun_tasklet_data_ptr->tasklet);
|
||||
break;
|
||||
|
||||
case ARM_LIB_SYSTEM_TIMER_EVENT:
|
||||
eventOS_event_timer_cancel(event->event_id, wisun_tasklet_data_ptr->tasklet);
|
||||
|
||||
if (event->event_id == TIMER_EVENT_START_BOOTSTRAP) {
|
||||
tr_debug("Restart bootstrap");
|
||||
wisun_tasklet_configure_and_connect_to_network();
|
||||
}
|
||||
break;
|
||||
|
||||
case APPLICATION_EVENT:
|
||||
if (event->event_id == APPL_EVENT_CONNECT) {
|
||||
wisun_tasklet_configure_and_connect_to_network();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
} // switch(event_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Network state event handler.
|
||||
* \param event show network start response or current network state.
|
||||
*
|
||||
* - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role
|
||||
* - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state
|
||||
* - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No WS Router at current Channel Stack is Already at Idle state
|
||||
* - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result
|
||||
* - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels
|
||||
* - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state
|
||||
*/
|
||||
static void wisun_tasklet_parse_network_event(arm_event_s *event)
|
||||
{
|
||||
arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data;
|
||||
tr_debug("app_parse_network_event() %d", status);
|
||||
switch (status) {
|
||||
case ARM_NWK_BOOTSTRAP_READY:
|
||||
/* Network is ready and node is connected to Access Point */
|
||||
if (wisun_tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
|
||||
tr_info("Wi-SUN bootstrap ready");
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY;
|
||||
wisun_tasklet_network_state_changed(MESH_CONNECTED);
|
||||
}
|
||||
break;
|
||||
case ARM_NWK_NWK_SCAN_FAIL:
|
||||
/* Link Layer Active Scan Fail, Stack is Already at Idle state */
|
||||
tr_debug("Link Layer Scan Fail: No Beacons");
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL:
|
||||
/* No WS Router at current Channel Stack is Already at Idle state */
|
||||
tr_debug("WS Scan/ GP REG fail");
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_NWK_CONNECTION_DOWN:
|
||||
/* Connection to Access point is lost wait for Scan Result */
|
||||
tr_debug("WS/RPL scan new network");
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
|
||||
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
|
||||
break;
|
||||
case ARM_NWK_NWK_PARENT_POLL_FAIL:
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
case ARM_NWK_AUHTENTICATION_FAIL:
|
||||
tr_debug("Network authentication fail");
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
|
||||
break;
|
||||
default:
|
||||
tr_warn("Unknown event %d", status);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((wisun_tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY &&
|
||||
wisun_tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_STARTED) &&
|
||||
wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
// Set 5s timer for new network scan
|
||||
eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
|
||||
ARM_LIB_SYSTEM_TIMER_EVENT,
|
||||
wisun_tasklet_data_ptr->tasklet,
|
||||
5000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Configure and establish network connection
|
||||
*
|
||||
*/
|
||||
static void wisun_tasklet_configure_and_connect_to_network(void)
|
||||
{
|
||||
int status;
|
||||
fhss_timer_t *fhss_timer_ptr = &fhss_functions;
|
||||
|
||||
if (MBED_CONF_MBED_MESH_API_WISUN_DEVICE_TYPE == MESH_DEVICE_TYPE_WISUN_BORDER_ROUTER) {
|
||||
wisun_tasklet_data_ptr->operating_mode = NET_6LOWPAN_BORDER_ROUTER;
|
||||
} else {
|
||||
wisun_tasklet_data_ptr->operating_mode = NET_6LOWPAN_ROUTER;
|
||||
}
|
||||
|
||||
wisun_tasklet_data_ptr->operating_mode_extension = NET_6LOWPAN_WS;
|
||||
|
||||
arm_nwk_interface_configure_6lowpan_bootstrap_set(
|
||||
wisun_tasklet_data_ptr->network_interface_id,
|
||||
wisun_tasklet_data_ptr->operating_mode,
|
||||
wisun_tasklet_data_ptr->operating_mode_extension);
|
||||
|
||||
if (wisun_tasklet_add_stored_certificates() != 0) {
|
||||
tr_error("Can't set Wi-SUN certificates");
|
||||
return;
|
||||
}
|
||||
|
||||
char network_name[33];
|
||||
status = ws_management_network_name_get(wisun_tasklet_data_ptr->network_interface_id, (char *) &network_name);
|
||||
if (status < 0) {
|
||||
tr_error("Failed to read network name");
|
||||
return;
|
||||
}
|
||||
uint8_t regulatory_domain;
|
||||
uint8_t operating_class;
|
||||
uint8_t operating_mode;
|
||||
status = ws_management_regulatory_domain_get(wisun_tasklet_data_ptr->network_interface_id,
|
||||
®ulatory_domain,
|
||||
&operating_class,
|
||||
&operating_mode);
|
||||
if (status < 0) {
|
||||
tr_error("Failed to read regulatory domain");
|
||||
return;
|
||||
}
|
||||
status = ws_management_node_init(wisun_tasklet_data_ptr->network_interface_id,
|
||||
regulatory_domain,
|
||||
(char *) network_name,
|
||||
fhss_timer_ptr);
|
||||
if (status < 0) {
|
||||
tr_error("Failed to initialize WS");
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(MBED_CONF_MBED_MESH_API_CERTIFICATE_HEADER)
|
||||
arm_certificate_entry_s trusted_cert = {
|
||||
.cert = MBED_CONF_MBED_MESH_API_ROOT_CERTIFICATE,
|
||||
.key = NULL,
|
||||
.cert_len = 0,
|
||||
.key_len = 0
|
||||
};
|
||||
#ifdef MBED_CONF_MBED_MESH_API_ROOT_CERTIFICATE_LEN
|
||||
trusted_cert.cert_len = MBED_CONF_MBED_MESH_API_ROOT_CERTIFICATE_LEN;
|
||||
#else
|
||||
trusted_cert.cert_len = strlen((const char *) MBED_CONF_MBED_MESH_API_ROOT_CERTIFICATE) + 1;
|
||||
#endif
|
||||
arm_network_trusted_certificate_add((const arm_certificate_entry_s *)&trusted_cert);
|
||||
|
||||
arm_certificate_entry_s own_cert = {
|
||||
.cert = MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE,
|
||||
.key = MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_KEY,
|
||||
.cert_len = 0,
|
||||
.key_len = 0
|
||||
};
|
||||
#ifdef MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_LEN
|
||||
own_cert.cert_len = MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_LEN;
|
||||
#else
|
||||
own_cert.cert_len = strlen((const char *) MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE) + 1;
|
||||
#endif
|
||||
#ifdef MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_KEY_LEN
|
||||
own_cert.key_len = MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_KEY_LEN;
|
||||
#else
|
||||
own_cert.key_len = strlen((const char *) MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_KEY) + 1;
|
||||
#endif
|
||||
arm_network_own_certificate_add((const arm_certificate_entry_s *)&own_cert);
|
||||
#endif
|
||||
|
||||
if (statistics_started) {
|
||||
wisun_tasklet_statistics_do_start();
|
||||
}
|
||||
|
||||
status = arm_nwk_interface_up(wisun_tasklet_data_ptr->network_interface_id);
|
||||
if (status >= 0) {
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
|
||||
tr_info("Start Wi-SUN Bootstrap");
|
||||
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
|
||||
} else {
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
|
||||
tr_err("Bootstrap start failed, %d", status);
|
||||
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_START_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform application about network state change
|
||||
*/
|
||||
static void wisun_tasklet_network_state_changed(mesh_connection_status_t status)
|
||||
{
|
||||
if (wisun_tasklet_data_ptr->mesh_api_cb) {
|
||||
(wisun_tasklet_data_ptr->mesh_api_cb)(status);
|
||||
}
|
||||
}
|
||||
|
||||
static int wisun_tasklet_store_certificate_data(const uint8_t *cert, uint16_t cert_len, const uint8_t *cert_key, uint16_t cert_key_len, bool remove_own, bool remove_trusted, bool trusted_cert)
|
||||
{
|
||||
if (wisun_certificates_ptr == NULL) {
|
||||
wisun_certificates_ptr = (wisun_certificates_t *)ns_dyn_mem_alloc(sizeof(wisun_certificates_t));
|
||||
if (!wisun_certificates_ptr) {
|
||||
return -1;
|
||||
}
|
||||
ns_list_init(&wisun_certificates_ptr->own_certificates_list);
|
||||
ns_list_init(&wisun_certificates_ptr->trusted_certificates_list);
|
||||
wisun_certificates_ptr->remove_own_certificates = false;
|
||||
wisun_certificates_ptr->remove_trusted_certificates = false;
|
||||
}
|
||||
|
||||
if (remove_own) {
|
||||
wisun_certificates_ptr->remove_own_certificates = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (remove_trusted) {
|
||||
wisun_certificates_ptr->remove_trusted_certificates = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wisun_certificate_entry_t *ws_cert_entry_store = (wisun_certificate_entry_t *)ns_dyn_mem_alloc(sizeof(wisun_certificate_entry_t));
|
||||
if (!ws_cert_entry_store) {
|
||||
wisun_tasklet_clear_stored_certificates();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ws_cert_entry_store->arm_cert_entry.cert = cert;
|
||||
ws_cert_entry_store->arm_cert_entry.cert_len = cert_len;
|
||||
|
||||
if (cert_key) {
|
||||
ws_cert_entry_store->arm_cert_entry.key = cert_key;
|
||||
ws_cert_entry_store->arm_cert_entry.key_len = cert_key_len;
|
||||
} else {
|
||||
ws_cert_entry_store->arm_cert_entry.key = NULL;
|
||||
ws_cert_entry_store->arm_cert_entry.key_len = 0;
|
||||
}
|
||||
|
||||
if (trusted_cert) {
|
||||
ns_list_add_to_end(&wisun_certificates_ptr->trusted_certificates_list, ws_cert_entry_store);
|
||||
} else {
|
||||
ns_list_add_to_end(&wisun_certificates_ptr->own_certificates_list, ws_cert_entry_store);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wisun_tasklet_clear_stored_certificates(void)
|
||||
{
|
||||
if (!wisun_certificates_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ns_list_foreach_safe(wisun_certificate_entry_t, trusted_cert_entry, &wisun_certificates_ptr->trusted_certificates_list) {
|
||||
ns_list_remove(&wisun_certificates_ptr->trusted_certificates_list, trusted_cert_entry);
|
||||
ns_dyn_mem_free(trusted_cert_entry);
|
||||
}
|
||||
|
||||
ns_list_foreach_safe(wisun_certificate_entry_t, own_cert_entry, &wisun_certificates_ptr->own_certificates_list) {
|
||||
ns_list_remove(&wisun_certificates_ptr->own_certificates_list, own_cert_entry);
|
||||
ns_dyn_mem_free(own_cert_entry);
|
||||
}
|
||||
|
||||
ns_dyn_mem_free(wisun_certificates_ptr);
|
||||
wisun_certificates_ptr = NULL;
|
||||
}
|
||||
|
||||
static int wisun_tasklet_add_stored_certificates(void)
|
||||
{
|
||||
int8_t status = 0;
|
||||
|
||||
if (wisun_certificates_ptr == NULL) {
|
||||
// certificates not updated
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wisun_certificates_ptr->remove_own_certificates) {
|
||||
status = arm_network_own_certificates_remove();
|
||||
if (status != 0) {
|
||||
goto CERTIFICATE_SET_END;
|
||||
}
|
||||
}
|
||||
|
||||
if (wisun_certificates_ptr->remove_trusted_certificates) {
|
||||
status = arm_network_trusted_certificates_remove();
|
||||
if (status != 0) {
|
||||
goto CERTIFICATE_SET_END;
|
||||
}
|
||||
}
|
||||
|
||||
ns_list_foreach(wisun_certificate_entry_t, cert_entry, &wisun_certificates_ptr->trusted_certificates_list) {
|
||||
status = arm_network_trusted_certificate_add(&cert_entry->arm_cert_entry);
|
||||
if (status != 0) {
|
||||
goto CERTIFICATE_SET_END;
|
||||
}
|
||||
}
|
||||
|
||||
ns_list_foreach(wisun_certificate_entry_t, cert_entry, &wisun_certificates_ptr->own_certificates_list) {
|
||||
status = arm_network_own_certificate_add(&cert_entry->arm_cert_entry);
|
||||
if (status != 0) {
|
||||
goto CERTIFICATE_SET_END;
|
||||
}
|
||||
}
|
||||
|
||||
CERTIFICATE_SET_END:
|
||||
wisun_tasklet_clear_stored_certificates();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
int8_t wisun_tasklet_get_router_ip_address(char *address, int8_t len)
|
||||
{
|
||||
network_layer_address_s nd_address;
|
||||
|
||||
if ((len >= 40) && (0 == arm_nwk_nd_address_read(wisun_tasklet_data_ptr->network_interface_id, &nd_address))) {
|
||||
ip6tos(nd_address.border_router, address);
|
||||
tr_debug("Router IP address: %s", address);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t wisun_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id)
|
||||
{
|
||||
bool re_connecting = true;
|
||||
int8_t tasklet_id = wisun_tasklet_data_ptr->tasklet;
|
||||
|
||||
if (wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
return -3; // already connected to network
|
||||
}
|
||||
|
||||
if (wisun_tasklet_data_ptr->tasklet_state == TASKLET_STATE_CREATED) {
|
||||
re_connecting = false;
|
||||
}
|
||||
|
||||
memset(wisun_tasklet_data_ptr, 0, sizeof(wisun_tasklet_data_str_t));
|
||||
wisun_tasklet_data_ptr->mesh_api_cb = callback;
|
||||
wisun_tasklet_data_ptr->network_interface_id = nwk_interface_id;
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_INITIALIZED;
|
||||
|
||||
if (re_connecting == false) {
|
||||
wisun_tasklet_data_ptr->tasklet = eventOS_event_handler_create(&wisun_tasklet_main,
|
||||
ARM_LIB_TASKLET_INIT_EVENT);
|
||||
if (wisun_tasklet_data_ptr->tasklet < 0) {
|
||||
// -1 handler already used by other tasklet
|
||||
// -2 memory allocation failure
|
||||
return wisun_tasklet_data_ptr->tasklet;
|
||||
}
|
||||
} else {
|
||||
wisun_tasklet_data_ptr->tasklet = tasklet_id;
|
||||
mesh_system_send_connect_event(wisun_tasklet_data_ptr->tasklet);
|
||||
}
|
||||
|
||||
return wisun_tasklet_data_ptr->tasklet;
|
||||
}
|
||||
|
||||
int8_t wisun_tasklet_disconnect(bool send_cb)
|
||||
{
|
||||
int8_t status = -1;
|
||||
if (wisun_tasklet_data_ptr != NULL) {
|
||||
if (wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
status = arm_nwk_interface_down(wisun_tasklet_data_ptr->network_interface_id);
|
||||
wisun_tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
|
||||
if (send_cb == true) {
|
||||
wisun_tasklet_network_state_changed(MESH_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
wisun_tasklet_data_ptr->mesh_api_cb = NULL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void wisun_tasklet_init(void)
|
||||
{
|
||||
if (wisun_tasklet_data_ptr == NULL) {
|
||||
wisun_tasklet_data_ptr = (wisun_tasklet_data_str_t *)ns_dyn_mem_alloc(sizeof(wisun_tasklet_data_str_t));
|
||||
// allocation not validated, in case of failure execution stops here
|
||||
memset(wisun_tasklet_data_ptr, 0, sizeof(wisun_tasklet_data_str_t));
|
||||
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_CREATED;
|
||||
wisun_tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t wisun_tasklet_network_init(int8_t device_id)
|
||||
{
|
||||
// TODO, read interface name from configuration
|
||||
mac_description_storage_size_t storage_sizes;
|
||||
storage_sizes.device_decription_table_size = MBED_CONF_MBED_MESH_API_MAC_NEIGH_TABLE_SIZE;
|
||||
storage_sizes.key_description_table_size = 4;
|
||||
storage_sizes.key_lookup_size = 1;
|
||||
storage_sizes.key_usage_size = 3;
|
||||
if (!mac_api) {
|
||||
mac_api = ns_sw_mac_create(device_id, &storage_sizes);
|
||||
}
|
||||
|
||||
return arm_nwk_interface_lowpan_init(mac_api, INTERFACE_NAME);
|
||||
}
|
||||
|
||||
int wisun_tasklet_set_own_certificate(uint8_t *cert, uint16_t cert_len, uint8_t *cert_key, uint16_t cert_key_len)
|
||||
{
|
||||
if (wisun_tasklet_data_ptr && wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
// interface already active write certificates to stack.
|
||||
arm_certificate_entry_s arm_cert_entry;
|
||||
arm_cert_entry.cert = cert;
|
||||
arm_cert_entry.cert_len = cert_len;
|
||||
arm_cert_entry.key = cert_key;
|
||||
arm_cert_entry.key_len = cert_key_len;
|
||||
return arm_network_own_certificate_add(&arm_cert_entry);
|
||||
}
|
||||
// Stack is inactive store the certificates and activate when connect() called
|
||||
return wisun_tasklet_store_certificate_data(cert, cert_len, cert_key, cert_key_len, false, false, false);
|
||||
}
|
||||
|
||||
int wisun_tasklet_remove_own_certificates(void)
|
||||
{
|
||||
return wisun_tasklet_store_certificate_data(NULL, 0, NULL, 0, true, false, false);
|
||||
}
|
||||
|
||||
int wisun_tasklet_remove_trusted_certificates(void)
|
||||
{
|
||||
return wisun_tasklet_store_certificate_data(NULL, 0, NULL, 0, false, true, false);
|
||||
}
|
||||
|
||||
int wisun_tasklet_set_trusted_certificate(uint8_t *cert, uint16_t cert_len)
|
||||
{
|
||||
if (wisun_tasklet_data_ptr && wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
|
||||
// interface already active write certificates to stack.
|
||||
arm_certificate_entry_s arm_cert_entry;
|
||||
arm_cert_entry.cert = cert;
|
||||
arm_cert_entry.cert_len = cert_len;
|
||||
arm_cert_entry.key = NULL;
|
||||
arm_cert_entry.key_len = 0;
|
||||
return arm_network_trusted_certificate_add(&arm_cert_entry);
|
||||
}
|
||||
// Stack is inactive store the certificates and activate when connect() called
|
||||
return wisun_tasklet_store_certificate_data(cert, cert_len, NULL, 0, false, false, true);
|
||||
}
|
||||
|
||||
int wisun_tasklet_statistics_start(void)
|
||||
{
|
||||
statistics_started = true;
|
||||
|
||||
if (statistics == NULL) {
|
||||
statistics = ns_dyn_mem_alloc(sizeof(wisun_statistics_t));
|
||||
}
|
||||
if (statistics == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(statistics, 0, sizeof(wisun_statistics_t));
|
||||
|
||||
wisun_tasklet_statistics_do_start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wisun_tasklet_statistics_do_start(void)
|
||||
{
|
||||
if (!wisun_tasklet_data_ptr || wisun_tasklet_data_ptr->network_interface_id < 0 || !mac_api) {
|
||||
return;
|
||||
}
|
||||
|
||||
protocol_stats_start(&statistics->nwk_stats);
|
||||
ns_sw_mac_statistics_start(mac_api, &statistics->mac_statistics);
|
||||
ws_statistics_start(wisun_tasklet_data_ptr->network_interface_id, &statistics->ws_statistics);
|
||||
}
|
||||
|
||||
int wisun_tasklet_statistics_nw_read(mesh_nw_statistics_t *stats)
|
||||
{
|
||||
if (!statistics || !stats) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stats->rpl_total_memory = statistics->nwk_stats.rpl_total_memory;
|
||||
stats->etx_1st_parent = statistics->nwk_stats.etx_1st_parent;
|
||||
stats->etx_2nd_parent = statistics->nwk_stats.etx_2nd_parent;
|
||||
stats->asynch_tx_count = statistics->ws_statistics.asynch_tx_count;
|
||||
stats->asynch_rx_count = statistics->ws_statistics.asynch_rx_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wisun_tasklet_statistics_mac_read(mesh_mac_statistics_t *stats)
|
||||
{
|
||||
if (!statistics || !stats) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stats->mac_rx_count = statistics->mac_statistics.mac_rx_count;
|
||||
stats->mac_tx_count = statistics->mac_statistics.mac_tx_count;
|
||||
stats->mac_bc_rx_count = statistics->mac_statistics.mac_bc_rx_count;
|
||||
stats->mac_bc_tx_count = statistics->mac_statistics.mac_bc_tx_count;
|
||||
stats->mac_tx_bytes = statistics->mac_statistics.mac_tx_bytes;
|
||||
stats->mac_rx_bytes = statistics->mac_statistics.mac_rx_bytes;
|
||||
stats->mac_tx_failed_count = statistics->mac_statistics.mac_tx_failed_count;
|
||||
stats->mac_retry_count = statistics->mac_statistics.mac_retry_count;
|
||||
stats->mac_cca_attempts_count = statistics->mac_statistics.mac_cca_attempts_count;
|
||||
stats->mac_failed_cca_count = statistics->mac_statistics.mac_failed_cca_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user