diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/LoWPANNDInterface.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/LoWPANNDInterface.h index 537f04aee0..ff2810feca 100644 --- a/features/nanostack/mbed-mesh-api/mbed-mesh-api/LoWPANNDInterface.h +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/LoWPANNDInterface.h @@ -30,22 +30,16 @@ public: * * Must initialize to initialize the mesh on a phy. */ - LoWPANNDInterface() : MeshInterfaceNanostack() { } + LoWPANNDInterface() { } - /** Create an initialized MeshInterface + /** Create an initialized LoWPANNDInterface * */ LoWPANNDInterface(NanostackRfPhy *phy) : MeshInterfaceNanostack(phy) { } - nsapi_error_t initialize(NanostackRfPhy *phy); virtual int connect(); virtual int disconnect(); - virtual bool getOwnIpAddress(char *address, int8_t len); bool getRouterIpAddress(char *address, int8_t len); -private: - mesh_error_t init(); - mesh_error_t mesh_connect(); - mesh_error_t mesh_disconnect(); }; #endif diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h index 15c6bc207a..7a8e5123b6 100644 --- a/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/MeshInterfaceNanostack.h @@ -20,36 +20,53 @@ #include "MeshInterface.h" #include "NanostackRfPhy.h" +#include "Nanostack.h" #include "mesh_interface_types.h" -/** Nanostack's network interface class. - * - * Common class that is shared between mesh interface classes - */ -class MeshInterfaceNanostack : public MeshInterface { +class Nanostack::Interface : public OnboardNetworkStack::Interface, private mbed::NonCopyable { public: + virtual char *get_ip_address(char *buf, nsapi_size_t buflen); + virtual char *get_mac_address(char *buf, nsapi_size_t buflen); + virtual char *get_netmask(char *buf, nsapi_size_t buflen); + virtual char *get_gateway(char *buf, nsapi_size_t buflen); + virtual void attach(mbed::Callback status_cb); + virtual nsapi_connection_status_t get_connection_status() const; - /** Attach phy and initialize the mesh - * - * Initializes a mesh interface on the given phy. Not needed if - * the phy is passed to the mesh's constructor. - * - * @return 0 on success, negative on failure - */ - nsapi_error_t initialize(NanostackPhy *phy); + void get_mac_address(uint8_t *buf) const { interface_phy.get_mac_address(buf); } - /** Start the interface - * - * @return 0 on success, negative on failure - */ - virtual nsapi_error_t connect() = 0; + /** + * \brief Callback from C-layer + * \param status state of the network + * */ + void network_handler(mesh_connection_status_t status); - /** Stop the interface - * - * @return 0 on success, negative on failure - */ - virtual nsapi_error_t disconnect() = 0; + int8_t get_interface_id() const { return interface_id; } + int8_t get_driver_id() const { return _device_id; } +private: + NanostackPhy &interface_phy; +protected: + Interface(NanostackPhy &phy); + virtual nsapi_error_t register_phy(); + NanostackPhy &get_phy() const { return interface_phy; } + int8_t interface_id; + int8_t _device_id; + Semaphore connect_semaphore; + + Callback _connection_status_cb; + nsapi_connection_status_t _connect_status; + bool _blocking; +}; + +class Nanostack::MeshInterface : public Nanostack::Interface { +protected: + MeshInterface(NanostackRfPhy &phy) : Interface(phy) { } + NanostackRfPhy &get_phy() const { return static_cast(Interface::get_phy()); } +}; + + +class InterfaceNanostack : public virtual NetworkInterface { +public: /** Get the internally stored IP address /return IP address of the interface or null if not yet connected */ @@ -60,18 +77,11 @@ public: */ virtual const char *get_mac_address(); - /** Get the interface ID - /return Interface identifier - */ - int8_t get_interface_id() const { return _network_interface_id; } - - /** - * \brief Callback from C-layer - * \param status state of the network - * */ - void mesh_network_handler(mesh_connection_status_t status); - /** Register callback for status reporting + * + * The specified status callback function will be called on status changes + * on the network. The parameters on the callback are the event type and + * event-type dependent reason parameter. * * @param status_cb The callback for status changes */ @@ -90,34 +100,41 @@ public: */ virtual nsapi_error_t set_blocking(bool blocking); + /** Get the interface ID + /return Interface identifier + */ + int8_t get_interface_id() const { return _interface->get_interface_id(); } + protected: - MeshInterfaceNanostack(); - MeshInterfaceNanostack(NanostackPhy *phy); - nsapi_error_t register_phy(); - virtual NetworkStack * get_stack(void); + InterfaceNanostack(); + virtual Nanostack *get_stack(void); + Nanostack::Interface *get_interface() const { return _interface; } - /** - * \brief Read own global IP address - * - * \param address is where the IP address will be copied - * \param len is the length of the address buffer, must be at least 40 bytes - * \return true if address is read successfully, false otherwise - */ - virtual bool getOwnIpAddress(char *address, int8_t len) = 0; + Nanostack::Interface *_interface; - NanostackPhy *phy; - /** Network interface ID */ - int8_t _network_interface_id; - /** Registered device ID */ - int8_t _device_id; - uint8_t _eui64[8]; char ip_addr_str[40]; char mac_addr_str[24]; - Semaphore connect_semaphore; - - Callback _connection_status_cb; - nsapi_connection_status_t _connect_status; + mbed::Callback _connection_status_cb; bool _blocking; }; +class MeshInterfaceNanostack : public InterfaceNanostack, public MeshInterface, private mbed::NonCopyable { +public: + + /** Attach phy and initialize the mesh + * + * Initializes a mesh interface on the given phy. Not needed if + * the phy is passed to the mesh's constructor. + * + * @return 0 on success, negative on failure + */ + nsapi_error_t initialize(NanostackRfPhy *phy); + +protected: + MeshInterfaceNanostack() : _phy(NULL) { } + MeshInterfaceNanostack(NanostackRfPhy *phy) : _phy(phy) { } + Nanostack::MeshInterface *get_interface() const { return static_cast(_interface); } + NanostackRfPhy *_phy; +}; + #endif /* MESHINTERFACENANOSTACK_H */ diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEMACInterface.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEMACInterface.h new file mode 100644 index 0000000000..90ecd9a3b8 --- /dev/null +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEMACInterface.h @@ -0,0 +1,29 @@ +/* + * 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 NANOSTACKEMACINTERFACE_H +#define NANOSTACKEMACINTERFACE_H + +#include "MeshInterfaceNanostack.h" +#include "NanostackEthernetPhy.h" + +class NanostackEMACInterface : public Nanostack::Interface { +public: + + NanostackEMACInterface(EMAC &emac); +}; + +#endif // NANOSTACKEMACINTERFACE_H diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h index 1d38281c7b..34ea88b991 100644 --- a/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackEthernetInterface.h @@ -17,24 +17,53 @@ #ifndef NANOSTACKETHERNETINTERFACE_H #define NANOSTACKETHERNETINTERFACE_H +#include "EthInterface.h" #include "MeshInterfaceNanostack.h" #include "NanostackEthernetPhy.h" +class Nanostack::EthernetInterface : public Nanostack::Interface { +public: + virtual nsapi_error_t bringup(bool dhcp, const char *ip, + const char *netmask, const char *gw, + nsapi_ip_stack_t stack = DEFAULT_STACK, + bool blocking = true); + virtual nsapi_error_t bringdown(); + +private: + friend Nanostack; + friend class NanostackEthernetInterface; + EthernetInterface(NanostackEthernetPhy &phy) : Interface(phy) {} + nsapi_error_t initialize(); +protected: + NanostackEthernetPhy &get_phy() const { return static_cast(Interface::get_phy()); } +}; + /** Ethernet interface for Nanostack. * * Configure Nanostack to use Ethernet connectivity. */ -class NanostackEthernetInterface : public MeshInterfaceNanostack { +class NanostackEthernetInterface : public InterfaceNanostack, public EthInterface, private mbed::NonCopyable { public: - - NanostackEthernetInterface() : MeshInterfaceNanostack() { } - NanostackEthernetInterface(NanostackEthernetPhy *phy) : MeshInterfaceNanostack(phy) { } + NanostackEthernetInterface() { } + //NanostackEthernetInterface(NanostackEthernetPhy *phy); nsapi_error_t initialize(NanostackEthernetPhy *phy); - virtual int connect(); - virtual int disconnect(); - virtual bool getOwnIpAddress(char *address, int8_t len); - bool getRouterIpAddress(char *address, int8_t len); + + /** Start the interface + * + * @return 0 on success, negative on failure + */ + virtual nsapi_error_t connect(); + + /** Stop the interface + * + * @return 0 on success, negative on failure + */ + virtual nsapi_error_t disconnect(); + +protected: + Nanostack::EthernetInterface *get_interface() const { return static_cast(_interface); } + }; #endif // NANOSTACKETHERNETINTERFACE_H diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackRfInterface.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackRfInterface.h new file mode 100644 index 0000000000..76706dad14 --- /dev/null +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/NanostackRfInterface.h @@ -0,0 +1,29 @@ +/* + * 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 NANOSTACKRFINTERFACE_H +#define NANOSTACKRFINTERFACE_H + +#include "MeshInterfaceNanostack.h" +#include "NanostackRfPhy.h" + +class NanostackRfInterface : public Nanostack::Interface { +public: + + NanostackRfInterface(NanostackRfPhy &phy); +}; + +#endif // NANOSTACKRFINTERFACE_H diff --git a/features/nanostack/mbed-mesh-api/mbed-mesh-api/ThreadInterface.h b/features/nanostack/mbed-mesh-api/mbed-mesh-api/ThreadInterface.h index 4e133243a3..6033d68b54 100644 --- a/features/nanostack/mbed-mesh-api/mbed-mesh-api/ThreadInterface.h +++ b/features/nanostack/mbed-mesh-api/mbed-mesh-api/ThreadInterface.h @@ -26,18 +26,16 @@ class ThreadInterface : public MeshInterfaceNanostack { public: - /** Create an uninitialized LoWPANNDInterface + /** Create an uninitialized ThreadInterface * * Must initialize to initialize the mesh on a phy. */ - ThreadInterface() : MeshInterfaceNanostack() { } + ThreadInterface() : user_set_eui64(false) { } - /** Create an initialized MeshInterface + /** Create an initialized ThreadInterface * */ - ThreadInterface(NanostackRfPhy *phy) : MeshInterfaceNanostack(phy) { } - - nsapi_error_t initialize(NanostackRfPhy *phy); + ThreadInterface(NanostackRfPhy *phy) : MeshInterfaceNanostack(phy), user_set_eui64(false) { } /** * \brief Sets the eui64 for the device configuration. @@ -59,40 +57,11 @@ public: virtual int connect(); virtual int disconnect(); +protected: + Nanostack::ThreadInterface *get_interface() const; + private: - /* - * \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 Read own global IP address - * - * \param address is where the IP address will be copied - * \param len is the length of the address buffer, must be at least 40 bytes - * \return true if address is read successfully, false otherwise - */ - virtual bool getOwnIpAddress(char *address, int8_t len); + bool user_set_eui64; }; #endif // THREADINTERFACE_H diff --git a/features/nanostack/mbed-mesh-api/source/CallbackHandler.cpp b/features/nanostack/mbed-mesh-api/source/CallbackHandler.cpp index 1d80d12533..6c5c278bd6 100644 --- a/features/nanostack/mbed-mesh-api/source/CallbackHandler.cpp +++ b/features/nanostack/mbed-mesh-api/source/CallbackHandler.cpp @@ -14,20 +14,21 @@ * limitations under the License. */ +#include "MeshInterfaceNanostack.h" + #include "include/callback_handler.h" - -static MeshInterfaceNanostack *_handler = NULL; +static Nanostack::Interface *_handler = NULL; void __mesh_handler_c_callback(mesh_connection_status_t state) { if (_handler) { - _handler->mesh_network_handler(state); + _handler->network_handler(state); } } -void __mesh_handler_set_callback(MeshInterfaceNanostack *handler) +void __mesh_handler_set_callback(Nanostack::Interface *handler) { _handler = handler; } diff --git a/features/nanostack/mbed-mesh-api/source/LoWPANNDInterface.cpp b/features/nanostack/mbed-mesh-api/source/LoWPANNDInterface.cpp index e592d96826..51a3e14d15 100644 --- a/features/nanostack/mbed-mesh-api/source/LoWPANNDInterface.cpp +++ b/features/nanostack/mbed-mesh-api/source/LoWPANNDInterface.cpp @@ -1,18 +1,49 @@ #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" -nsapi_error_t LoWPANNDInterface::initialize(NanostackRfPhy *phy) +class Nanostack::LoWPANNDInterface : public Nanostack::MeshInterface { - return MeshInterfaceNanostack::initialize(phy); -} +public: + virtual 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); + virtual nsapi_error_t bringdown(); + virtual char *get_gateway(char *buf, nsapi_size_t buflen); + + friend Nanostack; + friend class ::LoWPANNDInterface; +private: + LoWPANNDInterface(NanostackRfPhy &phy) : MeshInterface(phy) { } + mesh_error_t init(); + mesh_error_t mesh_connect(); + mesh_error_t mesh_disconnect(); +}; int LoWPANNDInterface::connect() +{ + if (!_interface) { + _interface = new (nothrow) Nanostack::LoWPANNDInterface(*_phy); + if (!_interface) { + return NSAPI_ERROR_NO_MEMORY; + } + _interface->attach(_connection_status_cb); + } + + return _interface->bringup(false, NULL, NULL, NULL, IPV6_STACK, _blocking); + +} + +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(); @@ -21,6 +52,8 @@ int LoWPANNDInterface::connect() return NSAPI_ERROR_DEVICE_ERROR; } + _blocking = blocking; + // After the RF is up, we can seed the random from it. randLIB_seed_random(); @@ -39,11 +72,13 @@ int LoWPANNDInterface::connect() // Release mutex before blocking nanostack_unlock(); - // wait connection for ever - int32_t count = connect_semaphore.wait(osWaitForever); + if (blocking) { + // wait connection for ever + int32_t count = connect_semaphore.wait(osWaitForever); - if (count <= 0) { - return NSAPI_ERROR_DHCP_FAILURE; // sort of... + if (count <= 0) { + return NSAPI_ERROR_DHCP_FAILURE; // sort of... + } } return 0; @@ -51,37 +86,40 @@ int LoWPANNDInterface::connect() int LoWPANNDInterface::disconnect() { - nanostack_lock(); + return _interface->bringdown(); +} + +nsapi_error_t Nanostack::LoWPANNDInterface::bringdown() +{ + NanostackLockGuard lock; mesh_error_t status = mesh_disconnect(); - nanostack_unlock(); - return map_mesh_error(status); } -mesh_error_t LoWPANNDInterface::init() +mesh_error_t Nanostack::LoWPANNDInterface::init() { nd_tasklet_init(); __mesh_handler_set_callback(this); - _network_interface_id = nd_tasklet_network_init(_device_id); + interface_id = nd_tasklet_network_init(_device_id); - if (_network_interface_id == -2) { + if (interface_id == -2) { return MESH_ERROR_PARAM; - } else if (_network_interface_id == -3) { + } else if (interface_id == -3) { return MESH_ERROR_MEMORY; - } else if (_network_interface_id < 0) { + } else if (interface_id < 0) { return MESH_ERROR_UNKNOWN; } return MESH_ERROR_NONE; } -mesh_error_t LoWPANNDInterface::mesh_connect() +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, _network_interface_id); + status = nd_tasklet_connect(&__mesh_handler_c_callback, interface_id); if (status >= 0) { return MESH_ERROR_NONE; @@ -96,7 +134,7 @@ mesh_error_t LoWPANNDInterface::mesh_connect() } } -mesh_error_t LoWPANNDInterface::mesh_disconnect() +mesh_error_t Nanostack::LoWPANNDInterface::mesh_disconnect() { int8_t status = -1; @@ -109,20 +147,16 @@ mesh_error_t LoWPANNDInterface::mesh_disconnect() return MESH_ERROR_UNKNOWN; } -bool LoWPANNDInterface::getOwnIpAddress(char *address, int8_t len) +char *Nanostack::LoWPANNDInterface::get_gateway(char *buf, nsapi_size_t buflen) { - tr_debug("getOwnIpAddress()"); - if (nd_tasklet_get_ip_address(address, len) == 0) { - return true; + NanostackLockGuard lock; + if (nd_tasklet_get_router_ip_address(buf, buflen) == 0) { + return buf; } - return false; + return NULL; } bool LoWPANNDInterface::getRouterIpAddress(char *address, int8_t len) { - tr_debug("getRouterIpAddress()"); - if (nd_tasklet_get_router_ip_address(address, len) == 0) { - return true; - } - return false; + return _interface->get_gateway(address, len); } diff --git a/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp b/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp index 355dc8f1ad..f79df884f6 100644 --- a/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp +++ b/features/nanostack/mbed-mesh-api/source/MeshInterfaceNanostack.cpp @@ -15,56 +15,99 @@ */ #include "MeshInterfaceNanostack.h" -#include "NanostackInterface.h" +#include "Nanostack.h" +#include "NanostackLockGuard.h" #include "mesh_system.h" -#include "net_interface.h" +#include "nanostack/net_interface.h" #include "thread_management_if.h" +#include "ip6string.h" - -MeshInterfaceNanostack::MeshInterfaceNanostack() - : phy(NULL), _network_interface_id(-1), _device_id(-1), _eui64(), - ip_addr_str(), mac_addr_str(), connect_semaphore(0), - _connection_status_cb(NULL), _connect_status(NSAPI_STATUS_DISCONNECTED), - _blocking(true) +char *Nanostack::Interface::get_ip_address(char *buf, nsapi_size_t buflen) { - // Nothing to do + NanostackLockGuard lock; + uint8_t binary_ipv6[16]; + + if (buflen >= 40 && arm_net_address_get(interface_id, ADDR_IPV6_GP, binary_ipv6) == 0) { + ip6tos(binary_ipv6, buf); + return buf; + } else { + return NULL; + } } -MeshInterfaceNanostack::MeshInterfaceNanostack(NanostackPhy *phy) - : phy(phy), _network_interface_id(-1), _device_id(-1), connect_semaphore(0) +char *Nanostack::Interface::get_mac_address(char *buf, nsapi_size_t buflen) { - // Nothing to do + 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 MeshInterfaceNanostack::initialize(NanostackPhy *phy) +char *Nanostack::Interface::get_netmask(char *, nsapi_size_t) +{ + return NULL; +} + +char *Nanostack::Interface::get_gateway(char *, nsapi_size_t) +{ + return NULL; +} + +nsapi_connection_status_t Nanostack::Interface::get_connection_status() const +{ + return _connect_status; +} + +void Nanostack::Interface::attach( + mbed::Callback status_cb) +{ + _connection_status_cb = status_cb; +} + +Nanostack::Interface::Interface(NanostackPhy &phy) : interface_phy(phy), interface_id(-1), _device_id(-1), + _connect_status(NSAPI_STATUS_DISCONNECTED), _blocking(true) { mesh_system_init(); - if (this->phy != NULL) { - error("Phy already set"); - } - this->phy = phy; - return 0; } -void MeshInterfaceNanostack::mesh_network_handler(mesh_connection_status_t status) -{ - nanostack_lock(); +InterfaceNanostack::InterfaceNanostack() + : _interface(NULL), + ip_addr_str(), mac_addr_str(), _blocking(true) +{ + // Nothing to do +} + +nsapi_error_t MeshInterfaceNanostack::initialize(NanostackRfPhy *phy) +{ + if (_phy) { + error("Phy already set"); + return NSAPI_ERROR_IS_CONNECTED; + } + _phy = phy; + return NSAPI_ERROR_OK; +} + + +void Nanostack::Interface::network_handler(mesh_connection_status_t status) +{ if ((status == MESH_CONNECTED || status == MESH_CONNECTED_LOCAL || status == MESH_CONNECTED_GLOBAL) && _blocking) { connect_semaphore.release(); } - nanostack_unlock(); - if (status == MESH_CONNECTED) { uint8_t temp_ipv6_global[16]; uint8_t temp_ipv6_local[16]; - if (arm_net_address_get(_network_interface_id, ADDR_IPV6_LL, temp_ipv6_local) == 0) { + 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(_network_interface_id, ADDR_IPV6_GP, temp_ipv6_global) == 0 + 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; } @@ -83,65 +126,58 @@ void MeshInterfaceNanostack::mesh_network_handler(mesh_connection_status_t statu } } -nsapi_error_t MeshInterfaceNanostack::register_phy() +nsapi_error_t Nanostack::Interface::register_phy() { - nanostack_lock(); + NanostackLockGuard lock; - _device_id = phy->phy_register(); + _device_id = interface_phy.phy_register(); if (_device_id < 0) { - nanostack_unlock(); - return -1; - } - // Read mac address after registering the device. - const uint8_t empty_eui64[8] = {0,0,0,0,0,0,0,0}; - // if not set by application then read from rf driver - if(!memcmp(_eui64, empty_eui64,8)) { - phy->get_mac_address(_eui64); + return NSAPI_ERROR_DEVICE_ERROR; } - sprintf(mac_addr_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", _eui64[0], _eui64[1], _eui64[2], _eui64[3], _eui64[4], _eui64[5], _eui64[6], _eui64[7]); - - nanostack_unlock(); - - return 0; + return NSAPI_ERROR_OK; } -NetworkStack * MeshInterfaceNanostack::get_stack() +Nanostack *InterfaceNanostack::get_stack() { - return NanostackInterface::get_stack(); + return &Nanostack::get_instance(); } -const char *MeshInterfaceNanostack::get_ip_address() +const char *InterfaceNanostack::get_ip_address() { - nanostack_lock(); - - const char *ret = NULL; - if (getOwnIpAddress(ip_addr_str, sizeof ip_addr_str)) { - ret = ip_addr_str; + if (_interface->get_ip_address(ip_addr_str, sizeof(ip_addr_str))) { + return ip_addr_str; } - - nanostack_unlock(); - - return ret; + return NULL; } -const char *MeshInterfaceNanostack::get_mac_address() +const char *InterfaceNanostack::get_mac_address() { - return mac_addr_str; + if (_interface->get_mac_address(mac_addr_str, sizeof(mac_addr_str))) { + return mac_addr_str; + } + return NULL; } -nsapi_connection_status_t MeshInterfaceNanostack::get_connection_status() const +nsapi_connection_status_t InterfaceNanostack::get_connection_status() const { - return _connect_status; + if (_interface) { + return _interface->get_connection_status(); + } else { + return NSAPI_STATUS_DISCONNECTED; + } } -void MeshInterfaceNanostack::attach( - Callback status_cb) +void InterfaceNanostack::attach( + mbed::Callback status_cb) { _connection_status_cb = status_cb; + if (_interface) { + _interface->attach(status_cb); + } } -nsapi_error_t MeshInterfaceNanostack::set_blocking(bool blocking) +nsapi_error_t InterfaceNanostack::set_blocking(bool blocking) { _blocking = blocking; return NSAPI_ERROR_OK; diff --git a/features/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp b/features/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp new file mode 100644 index 0000000000..9e17bdc812 --- /dev/null +++ b/features/nanostack/mbed-mesh-api/source/NanostackEMACInterface.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2017 ARM Limited. All rights reserved. + */ + +#include "Nanostack.h" +#include "NanostackEthernetInterface.h" +#include "NanostackEthernetPhy.h" +#include "EMAC.h" +#include "nsdynmemLIB.h" +#include "arm_hal_phy.h" + +class EMACPhy : public NanostackEthernetPhy +{ +public: + EMACPhy(NanostackMemoryManager &mem, EMAC &m); + virtual int8_t phy_register(); + virtual void get_mac_address(uint8_t *mac); + virtual void set_mac_address(uint8_t *mac); + + 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; + 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), device_id(-1) +{ + /* 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(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(ns_dyn_mem_temporary_alloc(total_len)); + if (tmpbuf) { + memory_manager.copy_from_buf(tmpbuf, total_len, mem); + } + } + + if (ptr) { + 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) { + + emac.set_memory_manager(memory_manager); + emac.set_link_input_cb(callback(this, &EMACPhy::emac_phy_rx)); + + 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); + + phy.PHY_MAC = mac_addr; + phy.address_write = emac_phy_address_write; + phy.driver_description = const_cast("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; + 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 (nothrow) EMACPhy(this->memory_manager, emac); + if (!single_phy) { + return NSAPI_ERROR_NO_MEMORY; + } + + if (mac_addr) { + single_phy->set_mac_address(const_cast(mac_addr)); + } + + Nanostack::EthernetInterface *interface; + + interface = new (nothrow) Nanostack::EthernetInterface(*single_phy); + if (!interface) { + return NSAPI_ERROR_NO_MEMORY; + } + + nsapi_error_t err = interface->initialize(); + if (err) { + 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; +} diff --git a/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp b/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp index 1a8e8d798a..29b987733e 100644 --- a/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp +++ b/features/nanostack/mbed-mesh-api/source/NanostackEthernetInterface.cpp @@ -18,12 +18,8 @@ #include "callback_handler.h" #include "enet_tasklet.h" -nsapi_error_t NanostackEthernetInterface::initialize(NanostackEthernetPhy *phy) +nsapi_error_t Nanostack::EthernetInterface::initialize() { - nsapi_error_t err = MeshInterfaceNanostack::initialize(phy); - if (err != NSAPI_ERROR_OK) - return err; - nanostack_lock(); if (register_phy() < 0) { @@ -31,54 +27,85 @@ nsapi_error_t NanostackEthernetInterface::initialize(NanostackEthernetPhy *phy) return NSAPI_ERROR_DEVICE_ERROR; } - enet_tasklet_init(); - __mesh_handler_set_callback(this); - _network_interface_id = enet_tasklet_network_init(_device_id); - nanostack_unlock(); - if (_network_interface_id < 0) - return MESH_ERROR_UNKNOWN; - else - return MESH_ERROR_NONE; + return NSAPI_ERROR_OK; } -int NanostackEthernetInterface::connect() +nsapi_error_t NanostackEthernetInterface::initialize(NanostackEthernetPhy *phy) { + if (_interface) { + return NSAPI_ERROR_PARAMETER; + } + + _interface = new (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(); - int8_t status = enet_tasklet_connect(&__mesh_handler_c_callback, _network_interface_id); + _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 MESH_ERROR_PARAM; + return NSAPI_ERROR_DEVICE_ERROR; } else if (status == -2) { - return MESH_ERROR_MEMORY; + return NSAPI_ERROR_NO_MEMORY; } else if (status == -3) { - return MESH_ERROR_STATE; + return NSAPI_ERROR_ALREADY; } else if (status != 0) { - return MESH_ERROR_UNKNOWN; + return NSAPI_ERROR_DEVICE_ERROR; } - int32_t count = connect_semaphore.wait(30000); + if (blocking) { + int32_t count = connect_semaphore.wait(30000); - if (count <= 0) { - return NSAPI_ERROR_DHCP_FAILURE; // sort of... + if (count <= 0) { + return NSAPI_ERROR_DHCP_FAILURE; // sort of... + } } return 0; } -int NanostackEthernetInterface::disconnect() +int NanostackEthernetInterface::connect() +{ + if (!_interface) { + return NSAPI_ERROR_PARAMETER; + } + return _interface->bringup(false, NULL, NULL, NULL, IPV6_STACK, _blocking); +} + +nsapi_error_t Nanostack::EthernetInterface::bringdown() { enet_tasklet_disconnect(); return 0; } -bool NanostackEthernetInterface::getOwnIpAddress(char *address, int8_t len) -{ - return enet_tasklet_get_ip_address(address, len)?false:true; -} -bool NanostackEthernetInterface::getRouterIpAddress(char *address, int8_t len) +int NanostackEthernetInterface::disconnect() { - return false; + if (!_interface) { + return NSAPI_ERROR_NO_CONNECTION; + } + return _interface->bringdown(); } diff --git a/features/nanostack/mbed-mesh-api/source/NanostackMemoryManager.cpp b/features/nanostack/mbed-mesh-api/source/NanostackMemoryManager.cpp new file mode 100644 index 0000000000..002a698111 --- /dev/null +++ b/features/nanostack/mbed-mesh-api/source/NanostackMemoryManager.cpp @@ -0,0 +1,143 @@ +/* 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 +#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_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(buf->payload) % align; + if (remainder) { + uint32_t offset = align - remainder; + if (offset >= align) { + offset = align; + } + + buf->payload = static_cast(buf->payload) + offset; + } + } + + return static_cast(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(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(to); + const ns_stack_mem_t *from_mem = static_cast(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(to_mem->payload) + to_offset; + const uint8_t *from_ptr = static_cast(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(to_buf); + ns_stack_mem_t *cat_mem = static_cast(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(buf)->next; +} + +void *NanostackMemoryManager::get_ptr(const emac_mem_buf_t *buf) const +{ + return static_cast(buf)->payload; +} + +uint32_t NanostackMemoryManager::get_len(const emac_mem_buf_t *buf) const +{ + return static_cast(buf)->len; +} + +void NanostackMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len) +{ + ns_stack_mem_t *mem = static_cast(buf); + + mem->len = len; +} diff --git a/features/nanostack/mbed-mesh-api/source/ThreadInterface.cpp b/features/nanostack/mbed-mesh-api/source/ThreadInterface.cpp index d27ffe6e49..594dc18728 100644 --- a/features/nanostack/mbed-mesh-api/source/ThreadInterface.cpp +++ b/features/nanostack/mbed-mesh-api/source/ThreadInterface.cpp @@ -7,12 +7,86 @@ #include "ns_trace.h" #define TRACE_GROUP "nsth" -nsapi_error_t ThreadInterface::initialize(NanostackRfPhy *phy) +class Nanostack::ThreadInterface : public Nanostack::MeshInterface { - return MeshInterfaceNanostack::initialize(phy); +public: + virtual 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); + virtual nsapi_error_t bringdown(); + friend Nanostack; + friend class ::ThreadInterface; +private: + ThreadInterface(NanostackRfPhy &phy) : MeshInterface(phy), user_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 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 user_eui64_set; +}; + +Nanostack::ThreadInterface *ThreadInterface::get_interface() const +{ + return static_cast(_interface); } int ThreadInterface::connect() +{ + if (!_interface) { + _interface = new (nothrow) Nanostack::ThreadInterface(*_phy); + if (!_interface) { + return NSAPI_ERROR_NO_MEMORY; + } + _interface->attach(_connection_status_cb); + } + + return _interface->bringup(false, NULL, NULL, NULL, IPV6_STACK, _blocking); +} + +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; @@ -20,12 +94,17 @@ int ThreadInterface::connect() return NSAPI_ERROR_ALREADY; } - nanostack_lock(); + if (stack == IPV4_STACK) { + return NSAPI_ERROR_UNSUPPORTED; + } if (register_phy() < 0) { - nanostack_unlock(); return NSAPI_ERROR_DEVICE_ERROR; } + nanostack_lock(); + + _blocking = blocking; + // After the RF is up, we can seed the random from it. randLIB_seed_random(); @@ -63,6 +142,11 @@ int ThreadInterface::connect() } int ThreadInterface::disconnect() +{ + return _interface->bringdown(); +} + +nsapi_error_t Nanostack::ThreadInterface::bringdown() { nanostack_lock(); @@ -73,38 +157,33 @@ int ThreadInterface::disconnect() return map_mesh_error(status); } -mesh_error_t ThreadInterface::init() +mesh_error_t Nanostack::ThreadInterface::init() { thread_tasklet_init(); __mesh_handler_set_callback(this); - thread_tasklet_device_eui64_set(_eui64); - _network_interface_id = thread_tasklet_network_init(_device_id); + if (!user_eui64_set) { + uint8_t eui64[8]; + get_phy().get_mac_address(eui64); + thread_tasklet_device_eui64_set(eui64); + } + interface_id = thread_tasklet_network_init(_device_id); - if (_network_interface_id == -2) { + if (interface_id == -2) { return MESH_ERROR_PARAM; - } else if (_network_interface_id == -3) { + } else if (interface_id == -3) { return MESH_ERROR_MEMORY; - } else if (_network_interface_id < 0) { + } else if (interface_id < 0) { return MESH_ERROR_UNKNOWN; } return MESH_ERROR_NONE; } -bool ThreadInterface::getOwnIpAddress(char *address, int8_t len) -{ - tr_debug("getOwnIpAddress()"); - if (thread_tasklet_get_ip_address(address, len) == 0) { - return true; - } - return false; -} - -mesh_error_t ThreadInterface::mesh_connect() +mesh_error_t Nanostack::ThreadInterface::mesh_connect() { int8_t status; tr_debug("connect()"); - status = thread_tasklet_connect(&__mesh_handler_c_callback, _network_interface_id); + status = thread_tasklet_connect(&__mesh_handler_c_callback, interface_id); if (status >= 0) { return MESH_ERROR_NONE; @@ -119,17 +198,7 @@ mesh_error_t ThreadInterface::mesh_connect() } } -void ThreadInterface::device_eui64_set(const uint8_t *eui64) -{ - memcpy(_eui64, eui64, 8); -} - -mesh_error_t ThreadInterface::device_pskd_set(const char *pskd) -{ - return (mesh_error_t)thread_tasklet_device_pskd_set(pskd); -} - -mesh_error_t ThreadInterface::mesh_disconnect() +mesh_error_t Nanostack::ThreadInterface::mesh_disconnect() { int8_t status; @@ -141,3 +210,24 @@ mesh_error_t ThreadInterface::mesh_disconnect() return MESH_ERROR_UNKNOWN; } + +void ThreadInterface::device_eui64_set(const uint8_t *eui64) +{ + get_interface()->device_eui64_set(eui64); +} + +void Nanostack::ThreadInterface::device_eui64_set(const uint8_t *eui64) +{ + user_eui64_set = true; + thread_tasklet_device_eui64_set(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); +} diff --git a/features/nanostack/mbed-mesh-api/source/ethernet_tasklet.c b/features/nanostack/mbed-mesh-api/source/ethernet_tasklet.c index 0385924f97..88073a698a 100644 --- a/features/nanostack/mbed-mesh-api/source/ethernet_tasklet.c +++ b/features/nanostack/mbed-mesh-api/source/ethernet_tasklet.c @@ -224,20 +224,6 @@ void enet_tasklet_network_state_changed(mesh_connection_status_t status) } /* Public functions */ -int8_t enet_tasklet_get_ip_address(char *address, int8_t len) -{ - uint8_t binary_ipv6[16]; - - if ((len >= 40) && (0 == arm_net_address_get( - tasklet_data_ptr->network_interface_id, ADDR_IPV6_GP, binary_ipv6))) { - ip6tos(binary_ipv6, address); - //tr_debug("IP address: %s", address); - return 0; - } else { - return -1; - } -} - int8_t enet_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id) { int8_t re_connecting = true; diff --git a/features/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h b/features/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h new file mode 100644 index 0000000000..267bc1f8dc --- /dev/null +++ b/features/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h @@ -0,0 +1,143 @@ +/* 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 : 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 + */ + virtual emac_mem_buf_t *alloc_heap(uint32_t size, uint32_t align); + + /** + * 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 + */ + virtual emac_mem_buf_t *alloc_pool(uint32_t size, uint32_t align); + + /** + * 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 + */ + virtual uint32_t get_pool_alloc_unit(uint32_t align) const; + + /** + * 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. + */ + virtual void free(emac_mem_buf_t *buf); + + /** + * 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 + */ + virtual uint32_t get_total_len(const emac_mem_buf_t *buf) const; + + virtual void set_align_preference(uint32_t align) { } + + /** + * 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 + */ + virtual void copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf); + + + + /** + * 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 + */ + virtual void cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf); + + /** + * 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 + */ + virtual emac_mem_buf_t *get_next(const emac_mem_buf_t *buf) const; + + /** + * Return pointer to the payload of the buffer + * + * @param buf Memory buffer + * @return Pointer to the payload + */ + virtual void *get_ptr(const emac_mem_buf_t *buf) const; + + /** + * Return payload size of the buffer + * + * @param buf Memory buffer + * @return Size in bytes + */ + virtual uint32_t get_len(const emac_mem_buf_t *buf) const; + + /** + * 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 + */ + virtual void set_len(emac_mem_buf_t *buf, uint32_t len); +}; + +#endif /* NANOSTACK_MEMORY_MANAGER_H */ diff --git a/features/nanostack/mbed-mesh-api/source/include/callback_handler.h b/features/nanostack/mbed-mesh-api/source/include/callback_handler.h index 2096e69331..24ba727585 100644 --- a/features/nanostack/mbed-mesh-api/source/include/callback_handler.h +++ b/features/nanostack/mbed-mesh-api/source/include/callback_handler.h @@ -21,6 +21,7 @@ #include "mesh_interface_types.h" #ifdef __cplusplus +#include "MeshInterfaceNanostack.h" extern "C" { #endif @@ -31,8 +32,7 @@ void __mesh_handler_c_callback(mesh_connection_status_t state); #endif #ifdef __cplusplus -#include "NanostackInterface.h" -void __mesh_handler_set_callback(MeshInterfaceNanostack *handler); +void __mesh_handler_set_callback(Nanostack::Interface *handler); #endif #endif /* __INCLUDE_CALLBACK_HANDLER_H__ */ diff --git a/features/nanostack/mbed-mesh-api/source/include/enet_tasklet.h b/features/nanostack/mbed-mesh-api/source/include/enet_tasklet.h index 0876c7dd2d..f8a8edf3b1 100644 --- a/features/nanostack/mbed-mesh-api/source/include/enet_tasklet.h +++ b/features/nanostack/mbed-mesh-api/source/include/enet_tasklet.h @@ -26,7 +26,6 @@ void enet_tasklet_init(void); uint8_t enet_tasklet_network_init(int8_t); int8_t enet_tasklet_connect(void (*)(mesh_connection_status_t mesh_status), int8_t nwk_interface_id); void enet_tasklet_disconnect(); -int8_t enet_tasklet_get_ip_address(char *address, int8_t len); #ifdef __cplusplus } diff --git a/features/nanostack/mbed-mesh-api/source/include/nd_tasklet.h b/features/nanostack/mbed-mesh-api/source/include/nd_tasklet.h index 28e67ea699..254ac4ebab 100644 --- a/features/nanostack/mbed-mesh-api/source/include/nd_tasklet.h +++ b/features/nanostack/mbed-mesh-api/source/include/nd_tasklet.h @@ -29,17 +29,6 @@ extern "C" { */ typedef void (*mesh_interface_cb)(mesh_connection_status_t mesh_status); -/* - * \brief Read own global IP address - * - * \param address where own 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_ip_address(char *address, int8_t len); - /* * \brief Read border router IP address * diff --git a/features/nanostack/mbed-mesh-api/source/include/thread_tasklet.h b/features/nanostack/mbed-mesh-api/source/include/thread_tasklet.h index 97777279e2..e26807e95f 100644 --- a/features/nanostack/mbed-mesh-api/source/include/thread_tasklet.h +++ b/features/nanostack/mbed-mesh-api/source/include/thread_tasklet.h @@ -29,17 +29,6 @@ extern "C" { */ typedef void (*mesh_interface_cb)(mesh_connection_status_t mesh_status); -/* - * \brief Read own global IP address - * - * \param address where own IP address will be written - * \param len length of provided address buffer - * - * \return 0 on success - * \return -1 if address reading fails - */ -int8_t thread_tasklet_get_ip_address(char *address, int8_t len); - /* * \brief Connect to mesh network * diff --git a/features/nanostack/mbed-mesh-api/source/nd_tasklet.c b/features/nanostack/mbed-mesh-api/source/nd_tasklet.c index 1eaa785f09..a3c939361e 100644 --- a/features/nanostack/mbed-mesh-api/source/nd_tasklet.c +++ b/features/nanostack/mbed-mesh-api/source/nd_tasklet.c @@ -340,20 +340,6 @@ void nd_tasklet_trace_bootstrap_info() #endif /* #define TRACE_ND_TASKLET */ /* Public functions */ -int8_t nd_tasklet_get_ip_address(char *address, int8_t len) -{ - uint8_t binary_ipv6[16]; - - if ((len >= 40) && (0 == arm_net_address_get( - tasklet_data_ptr->network_interface_id, ADDR_IPV6_GP, binary_ipv6))) { - ip6tos(binary_ipv6, address); - //tr_debug("IP address: %s", address); - return 0; - } else { - return -1; - } -} - int8_t nd_tasklet_get_router_ip_address(char *address, int8_t len) { network_layer_address_s nd_address; diff --git a/features/nanostack/mbed-mesh-api/source/thread_tasklet.c b/features/nanostack/mbed-mesh-api/source/thread_tasklet.c index d16271d13c..f09c9e9e27 100644 --- a/features/nanostack/mbed-mesh-api/source/thread_tasklet.c +++ b/features/nanostack/mbed-mesh-api/source/thread_tasklet.c @@ -390,20 +390,6 @@ void thread_tasklet_trace_bootstrap_info() } #endif /* #define TRACE_THREAD_TASKLET */ -int8_t thread_tasklet_get_ip_address(char *address, int8_t len) -{ - uint8_t binary_ipv6[16]; - - if ((len >= 40) && (0 == arm_net_address_get( - thread_tasklet_data_ptr->nwk_if_id, ADDR_IPV6_GP, binary_ipv6))) { - ip6tos(binary_ipv6, address); - //tr_debug("IP address: %s", address); - return 0; - } else { - return -1; - } -} - int8_t thread_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id) { int8_t re_connecting = true; diff --git a/features/nanostack/nanostack-interface/NanostackInterface.cpp b/features/nanostack/nanostack-interface/Nanostack.cpp similarity index 93% rename from features/nanostack/nanostack-interface/NanostackInterface.cpp rename to features/nanostack/nanostack-interface/Nanostack.cpp index c85cfca2a9..b585e8fac4 100644 --- a/features/nanostack/nanostack-interface/NanostackInterface.cpp +++ b/features/nanostack/nanostack-interface/Nanostack.cpp @@ -19,7 +19,7 @@ #include "mbed.h" #include "rtos.h" -#include "NanostackInterface.h" +#include "Nanostack.h" #include "NanostackLockGuard.h" #include "ns_address.h" @@ -444,20 +444,7 @@ void NanostackSocket::event_connection_reset(socket_callback_t *sock_cb) close(); } -NanostackInterface *NanostackInterface::_ns_interface; - -NanostackInterface *NanostackInterface::get_stack() -{ - NanostackLockGuard lock; - - if (NULL == _ns_interface) { - _ns_interface = new NanostackInterface(); - } - - return _ns_interface; -} - -const char * NanostackInterface::get_ip_address() +const char * Nanostack::get_ip_address() { NanostackLockGuard lock; @@ -474,7 +461,7 @@ const char * NanostackInterface::get_ip_address() return "::"; } -nsapi_error_t NanostackInterface::socket_open(void **handle, nsapi_protocol_t protocol) +nsapi_error_t Nanostack::socket_open(void **handle, nsapi_protocol_t protocol) { // Validate parameters if (NULL == handle) { @@ -511,7 +498,7 @@ nsapi_error_t NanostackInterface::socket_open(void **handle, nsapi_protocol_t pr return NSAPI_ERROR_OK; } -nsapi_error_t NanostackInterface::socket_close(void *handle) +nsapi_error_t Nanostack::socket_close(void *handle) { NanostackLockGuard lock; // Validate parameters @@ -528,7 +515,7 @@ nsapi_error_t NanostackInterface::socket_close(void *handle) } -nsapi_size_or_error_t NanostackInterface::do_sendto(void *handle, const ns_address_t *address, const void *data, nsapi_size_t size) +nsapi_size_or_error_t Nanostack::do_sendto(void *handle, const ns_address_t *address, const void *data, nsapi_size_t size) { // Validate parameters NanostackSocket * socket = static_cast(handle); @@ -601,7 +588,7 @@ out: return ret; } -nsapi_size_or_error_t NanostackInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, nsapi_size_t size) +nsapi_size_or_error_t Nanostack::socket_sendto(void *handle, const SocketAddress &address, const void *data, nsapi_size_t size) { if (address.get_ip_version() != NSAPI_IPv6) { return NSAPI_ERROR_UNSUPPORTED; @@ -613,7 +600,7 @@ nsapi_size_or_error_t NanostackInterface::socket_sendto(void *handle, const Sock return do_sendto(handle, &ns_address, data, size); } -nsapi_size_or_error_t NanostackInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, nsapi_size_t size) +nsapi_size_or_error_t Nanostack::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, nsapi_size_t size) { // Validate parameters NanostackSocket *socket = static_cast(handle); @@ -658,7 +645,7 @@ out: return ret; } -nsapi_error_t NanostackInterface::socket_bind(void *handle, const SocketAddress &address) +nsapi_error_t Nanostack::socket_bind(void *handle, const SocketAddress &address) { // Validate parameters NanostackSocket *socket = static_cast(handle); @@ -699,7 +686,7 @@ nsapi_error_t NanostackInterface::socket_bind(void *handle, const SocketAddress return ret; } -nsapi_error_t NanostackInterface::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) +nsapi_error_t Nanostack::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) { NanostackSocket *socket = static_cast(handle); if (handle == NULL) { @@ -753,7 +740,7 @@ nsapi_error_t NanostackInterface::setsockopt(void *handle, int level, int optnam } } -nsapi_error_t NanostackInterface::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) +nsapi_error_t Nanostack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) { NanostackSocket *socket = static_cast(handle); if (handle == NULL) { @@ -776,7 +763,7 @@ nsapi_error_t NanostackInterface::getsockopt(void *handle, int level, int optnam return ret; } -nsapi_error_t NanostackInterface::socket_listen(void *handle, int backlog) +nsapi_error_t Nanostack::socket_listen(void *handle, int backlog) { //Check if socket exists NanostackSocket *socket = static_cast(handle); @@ -798,7 +785,7 @@ nsapi_error_t NanostackInterface::socket_listen(void *handle, int backlog) return ret; } -nsapi_error_t NanostackInterface::socket_connect(void *handle, const SocketAddress &addr) +nsapi_error_t Nanostack::socket_connect(void *handle, const SocketAddress &addr) { // Validate parameters NanostackSocket *socket = static_cast(handle); @@ -850,7 +837,7 @@ out: return ret; } -nsapi_error_t NanostackInterface::socket_accept(void *server, void **handle, SocketAddress *address) +nsapi_error_t Nanostack::socket_accept(void *server, void **handle, SocketAddress *address) { NanostackSocket * socket = static_cast(server); NanostackSocket *accepted_sock = NULL; @@ -900,17 +887,17 @@ out: return ret; } -nsapi_size_or_error_t NanostackInterface::socket_send(void *handle, const void *data, nsapi_size_t size) +nsapi_size_or_error_t Nanostack::socket_send(void *handle, const void *data, nsapi_size_t size) { return do_sendto(handle, NULL, data, size); } -nsapi_size_or_error_t NanostackInterface::socket_recv(void *handle, void *data, nsapi_size_t size) +nsapi_size_or_error_t Nanostack::socket_recv(void *handle, void *data, nsapi_size_t size) { return socket_recvfrom(handle, NULL, data, size); } -void NanostackInterface::socket_attach(void *handle, void (*callback)(void *), void *id) +void Nanostack::socket_attach(void *handle, void (*callback)(void *), void *id) { // Validate parameters NanostackSocket * socket = static_cast(handle); @@ -926,3 +913,18 @@ void NanostackInterface::socket_attach(void *handle, void (*callback)(void *), v tr_debug("socket_attach(socket=%p) sock_id=%d", socket, socket->socket_id); } + +Nanostack &Nanostack::get_instance() { + static Nanostack nanostack; + return nanostack; +} + +// This works as long as it's not ever set to something which corresponds to +// a macro defined as a non-integer. Eg `#define Nanostack "Foo"` +#define NANOSTACK 0x99119911 +#if MBED_CONF_NSAPI_DEFAULT_STACK == NANOSTACK +#undef NANOSTACK +OnboardNetworkStack &OnboardNetworkStack::get_default_instance() { + return Nanostack::get_instance(); +} +#endif diff --git a/features/nanostack/nanostack-interface/Nanostack.h b/features/nanostack/nanostack-interface/Nanostack.h new file mode 100644 index 0000000000..da94e15865 --- /dev/null +++ b/features/nanostack/nanostack-interface/Nanostack.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2016-2017, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NANOSTACK_H_ +#define NANOSTACK_H_ + +#include "mbed.h" +#include "OnboardNetworkStack.h" +#include "NanostackMemoryManager.h" +#include "MeshInterface.h" +#include "mesh_interface_types.h" + +struct ns_address; + +class Nanostack : public OnboardNetworkStack, private mbed::NonCopyable { +public: + static Nanostack &get_instance(); + + // Our Nanostack::Interface etc are defined by mbed_mesh_api + class Interface; + class EthernetInterface; + class MeshInterface; + class LoWPANNDInterface; + class ThreadInterface; + + /* Implement OnboardNetworkStack method */ + virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out); + + /* Local variant with stronger typing and manual address specification */ + nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Nanostack::EthernetInterface **interface_out, const uint8_t *mac_addr = NULL); + +protected: + + /** Get the local IP address + * + * @return Null-terminated representation of the local IP address + * or null if not yet connected + */ + virtual const char *get_ip_address(); + + /** Opens a socket + * + * Creates a network socket and stores it in the specified handle. + * The handle must be passed to following calls on the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * @param handle Destination for the handle to a newly created socket + * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * + * Closes any open connection and deallocates any memory associated + * with the socket. + * + * @param handle Socket handle + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_close(void *handle); + + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to recieve + * data. If the IP address is zeroed, only the port is bound. + * + * @param handle Socket handle + * @param address Local address to bind + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_bind(void *handle, const SocketAddress &address); + + /** Listen for connections on a TCP socket + * + * Marks the socket as a passive socket that can be used to accept + * incoming connections. + * + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued + * simultaneously + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_listen(void *handle, int backlog); + + /** Connects TCP socket to a remote host + * + * Initiates a connection to a remote server specified by the + * indicated address. + * + * @param handle Socket handle + * @param address The SocketAddress of the remote host + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_connect(void *handle, const SocketAddress &address); + + /** Accepts a connection on a TCP socket + * + * The server socket must be bound and set to listen for connections. + * On a new connection, creates a network socket and stores it in the + * specified handle. The handle must be passed to following calls on + * the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * This call is non-blocking. If accept would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param server Socket handle to server to accept from + * @param handle Destination for a handle to the newly created socket + * @param address Destination for the remote address or NULL + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_accept(void *handle, void **server, SocketAddress *address); + + /** Send data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes sent from the buffer. + * + * This call is non-blocking. If send would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_send(void *handle, const void *data, nsapi_size_t size); + + /** Receive data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes received into the buffer. + * + * This call is non-blocking. If recv would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_recv(void *handle, void *data, nsapi_size_t size); + + /** Send a packet over a UDP socket + * + * Sends data to the specified address. Returns the number of bytes + * sent from the buffer. + * + * This call is non-blocking. If sendto would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param address The SocketAddress of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_sendto(void *handle, const SocketAddress &address, const void *data, nsapi_size_t size); + + /** Receive a packet over a UDP socket + * + * Receives data and stores the source address in address if address + * is not NULL. Returns the number of bytes received into the buffer. + * + * This call is non-blocking. If recvfrom would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param address Destination for the source address or NULL + * @param buffer Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_recvfrom(void *handle, SocketAddress *address, void *buffer, nsapi_size_t size); + + /** Register a callback on state change of the socket + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /* Set stack-specific socket options + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen); + + /* Get stack-specific socket options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen); + +private: + nsapi_size_or_error_t do_sendto(void *handle, const struct ns_address *address, const void *data, nsapi_size_t size); + char text_ip_address[40]; + NanostackMemoryManager memory_manager; +}; + +nsapi_error_t map_mesh_error(mesh_error_t err); + +#endif /* NANOSTACK_H_ */ diff --git a/features/nanostack/nanostack-interface/NanostackInterface.h b/features/nanostack/nanostack-interface/NanostackInterface.h index b4c1aa29da..d9c4c0020a 100644 --- a/features/nanostack/nanostack-interface/NanostackInterface.h +++ b/features/nanostack/nanostack-interface/NanostackInterface.h @@ -19,7 +19,6 @@ #define NANOSTACK_INTERFACE_H_ #include "mbed.h" -#include "NetworkStack.h" #include "MeshInterface.h" // Include here for backward compatibility #include "LoWPANNDInterface.h" @@ -27,217 +26,4 @@ #include "NanostackEthernetInterface.h" #include "MeshInterfaceNanostack.h" -struct ns_address; - -/** Network interface class for Nanostack */ -class NanostackInterface : public NetworkStack { -public: - static NanostackInterface *get_stack(); - -protected: - - /** Get the local IP address - * - * @return Null-terminated representation of the local IP address - * or null if not yet connected - */ - virtual const char *get_ip_address(); - - /** Opens a socket - * - * Creates a network socket and stores it in the specified handle. - * The handle must be passed to following calls on the socket. - * - * A stack may have a finite number of sockets, in this case - * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. - * - * @param handle Destination for the handle to a newly created socket - * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t socket_open(void **handle, nsapi_protocol_t proto); - - /** Close the socket - * - * Closes any open connection and deallocates any memory associated - * with the socket. - * - * @param handle Socket handle - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t socket_close(void *handle); - - /** Bind a specific address to a socket - * - * Binding a socket specifies the address and port on which to recieve - * data. If the IP address is zeroed, only the port is bound. - * - * @param handle Socket handle - * @param address Local address to bind - * @return 0 on success, negative error code on failure. - */ - virtual nsapi_error_t socket_bind(void *handle, const SocketAddress &address); - - /** Listen for connections on a TCP socket - * - * Marks the socket as a passive socket that can be used to accept - * incoming connections. - * - * @param handle Socket handle - * @param backlog Number of pending connections that can be queued - * simultaneously - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t socket_listen(void *handle, int backlog); - - /** Connects TCP socket to a remote host - * - * Initiates a connection to a remote server specified by the - * indicated address. - * - * @param handle Socket handle - * @param address The SocketAddress of the remote host - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t socket_connect(void *handle, const SocketAddress &address); - - /** Accepts a connection on a TCP socket - * - * The server socket must be bound and set to listen for connections. - * On a new connection, creates a network socket and stores it in the - * specified handle. The handle must be passed to following calls on - * the socket. - * - * A stack may have a finite number of sockets, in this case - * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. - * - * This call is non-blocking. If accept would block, - * NSAPI_ERROR_WOULD_BLOCK is returned immediately. - * - * @param server Socket handle to server to accept from - * @param handle Destination for a handle to the newly created socket - * @param address Destination for the remote address or NULL - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t socket_accept(void *handle, void **server, SocketAddress *address); - - /** Send data over a TCP socket - * - * The socket must be connected to a remote host. Returns the number of - * bytes sent from the buffer. - * - * This call is non-blocking. If send would block, - * NSAPI_ERROR_WOULD_BLOCK is returned immediately. - * - * @param handle Socket handle - * @param data Buffer of data to send to the host - * @param size Size of the buffer in bytes - * @return Number of sent bytes on success, negative error - * code on failure - */ - virtual nsapi_size_or_error_t socket_send(void *handle, const void *data, nsapi_size_t size); - - /** Receive data over a TCP socket - * - * The socket must be connected to a remote host. Returns the number of - * bytes received into the buffer. - * - * This call is non-blocking. If recv would block, - * NSAPI_ERROR_WOULD_BLOCK is returned immediately. - * - * @param handle Socket handle - * @param data Destination buffer for data received from the host - * @param size Size of the buffer in bytes - * @return Number of received bytes on success, negative error - * code on failure - */ - virtual nsapi_size_or_error_t socket_recv(void *handle, void *data, nsapi_size_t size); - - /** Send a packet over a UDP socket - * - * Sends data to the specified address. Returns the number of bytes - * sent from the buffer. - * - * This call is non-blocking. If sendto would block, - * NSAPI_ERROR_WOULD_BLOCK is returned immediately. - * - * @param handle Socket handle - * @param address The SocketAddress of the remote host - * @param data Buffer of data to send to the host - * @param size Size of the buffer in bytes - * @return Number of sent bytes on success, negative error - * code on failure - */ - virtual nsapi_size_or_error_t socket_sendto(void *handle, const SocketAddress &address, const void *data, nsapi_size_t size); - - /** Receive a packet over a UDP socket - * - * Receives data and stores the source address in address if address - * is not NULL. Returns the number of bytes received into the buffer. - * - * This call is non-blocking. If recvfrom would block, - * NSAPI_ERROR_WOULD_BLOCK is returned immediately. - * - * @param handle Socket handle - * @param address Destination for the source address or NULL - * @param buffer Destination buffer for data received from the host - * @param size Size of the buffer in bytes - * @return Number of received bytes on success, negative error - * code on failure - */ - virtual nsapi_size_or_error_t socket_recvfrom(void *handle, SocketAddress *address, void *buffer, nsapi_size_t size); - - /** Register a callback on state change of the socket - * - * The specified callback will be called on state changes such as when - * the socket can recv/send/accept successfully and on when an error - * occurs. The callback may also be called spuriously without reason. - * - * The callback may be called in an interrupt context and should not - * perform expensive operations such as recv/send calls. - * - * @param handle Socket handle - * @param callback Function to call on state change - * @param data Argument to pass to callback - */ - virtual void socket_attach(void *handle, void (*callback)(void *), void *data); - - /* Set stack-specific socket options - * - * The setsockopt allow an application to pass stack-specific hints - * to the underlying stack. For unsupported options, - * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. - * - * @param handle Socket handle - * @param level Stack-specific protocol level - * @param optname Stack-specific option identifier - * @param optval Option value - * @param optlen Length of the option value - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen); - - /* Get stack-specific socket options - * - * The getstackopt allow an application to retrieve stack-specific hints - * from the underlying stack. For unsupported options, - * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. - * - * @param handle Socket handle - * @param level Stack-specific protocol level - * @param optname Stack-specific option identifier - * @param optval Destination for option value - * @param optlen Length of the option value - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen); - -private: - nsapi_size_or_error_t do_sendto(void *handle, const struct ns_address *address, const void *data, nsapi_size_t size); - char text_ip_address[40]; - static NanostackInterface * _ns_interface; -}; - -nsapi_error_t map_mesh_error(mesh_error_t err); - #endif /* NANOSTACK_INTERFACE_H_ */ diff --git a/features/netsocket/MeshInterface.h b/features/netsocket/MeshInterface.h index eaa8b53446..6890314531 100644 --- a/features/netsocket/MeshInterface.h +++ b/features/netsocket/MeshInterface.h @@ -27,7 +27,7 @@ * * Common interface that is shared between mesh hardware */ -class MeshInterface : public NetworkInterface +class MeshInterface : public virtual NetworkInterface { virtual MeshInterface *meshInterface() { return this;