Mistake on this page?
Report an issue in GitHub or email us

Mesh

MeshInterface class hierarchy

The Arm Mbed Mesh API allows the application to use the IPv6 mesh network topologies through the Nanostack networking stack.

Mbed OS provides two types of IPv6 based mesh networks:

  • 6LoWPAN_ND, loosely following the Zigbee-IP specification.
  • Thread, following the specification from Thread Group.

Nanostack is the networking stack that provides both of these protocols. For more information on the stack internals, please refer to the 6LoWPAN mesh technology section. Application developers use Nanostack through the Mbed Mesh API.

The application can use the LoWPANNDInterface or ThreadInterface object for connecting to the mesh network. When successfully connected, the application can use the Mbed C++ socket APIs to create a socket to start communication with a remote peer.

You can configure the mesh interface by providing values in mbed_app.json, as the mesh configuration section documents.

Usage

  1. Create a network interface and driver objects.
  2. Initialize the interface with given PHY driver.
  3. Connect to network.

Supported mesh networking modes

Currently, 6LoWPAN-ND (neighbor discovery) and Thread bootstrap modes are supported.

Network connection states

After the initialization, the network state is MESH_DISCONNECTED. After a successful connection, the state changes to MESH_CONNECTED and when disconnected from the network the state is changed back to MESH_DISCONNECTED.

In case of connection errors, the state is changed to some of the connection error states. In an error state, there is no need to make a disconnect request and the application is allowed to attempt connecting again.

Getting started

See the example application mbed-os-example-mesh-minimal for usage.

Mesh class reference

Public Types
typedef mbed::Callback< void(nsapi_error_t result, SocketAddress *address)> hostbyname_cb_t
 Hostname translation callback (for use with gethostbyname_async()). More...
Public Member Functions
virtual MeshInterfacemeshInterface ()
 Return pointer to a MeshInterface. More...
virtual const char * get_mac_address ()
 Get the local MAC address. More...
virtual const char * get_ip_address ()
 Get the local IP address. More...
virtual const char * get_netmask ()
 Get the local network mask. More...
virtual const char * get_gateway ()
 Get the local gateway. More...
virtual nsapi_error_t set_network (const char *ip_address, const char *netmask, const char *gateway)
 Configure this network interface to use a static IP address. More...
virtual nsapi_error_t set_dhcp (bool dhcp)
 Enable or disable DHCP on connecting the network. More...
virtual nsapi_error_t connect ()=0
 Start the interface. More...
virtual nsapi_error_t disconnect ()=0
 Stop the interface. More...
virtual nsapi_error_t gethostbyname (const char *host, SocketAddress *address, nsapi_version_t version=NSAPI_UNSPEC)
 Translate a hostname to an IP address with specific version. More...
virtual nsapi_value_or_error_t gethostbyname_async (const char *host, hostbyname_cb_t callback, nsapi_version_t version=NSAPI_UNSPEC)
 Translate a hostname to an IP address (asynchronous). More...
virtual nsapi_error_t gethostbyname_async_cancel (int id)
 Cancel asynchronous hostname translation. More...
virtual nsapi_error_t add_dns_server (const SocketAddress &address)
 Add a domain name server to list of servers to query. More...
virtual void attach (mbed::Callback< void(nsapi_event_t, intptr_t)> status_cb)
 Register callback for status reporting. More...
virtual nsapi_connection_status_t get_connection_status () const
 Get the connection status. More...
virtual nsapi_error_t set_blocking (bool blocking)
 Set blocking status of connect() which by default should be blocking. More...
virtual EthInterfaceethInterface ()
 Return pointer to an EthInterface. More...
virtual WiFiInterfacewifiInterface ()
 Return pointer to a WiFiInterface. More...
virtual CellularBasecellularBase ()
 Return pointer to a CellularBase. More...
virtual EMACInterfaceemacInterface ()
 Return pointer to an EMACInterface. More...
Static Public Member Functions
static MeshInterfaceget_default_instance ()
 Get the default Mesh interface. More...

Mesh example

The application below demonstrates a simple light control application, where devices can control the LED status of all devices in the network. You can build the application for the unsecure 6LoWPAN-ND or Thread network.

/*
 * 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 "mbed.h"
#include "nanostack/socket_api.h"
#include "mesh_led_control_example.h"
#include "common_functions.h"
#include "ip6string.h"
#include "mbed-trace/mbed_trace.h"

static void init_socket();
static void handle_socket();
static void receive();
static void my_button_isr();
static void send_message();
static void blink();
static void update_state(uint8_t state);
static void handle_message(char* msg);

#define multicast_addr_str "ff15::810a:64d1"
#define TRACE_GROUP "example"
#define UDP_PORT 1234
#define MESSAGE_WAIT_TIMEOUT (30.0)
#define MASTER_GROUP 0
#define MY_GROUP 1

DigitalOut led_1(MBED_CONF_APP_LED, 1);
InterruptIn my_button(MBED_CONF_APP_BUTTON);
DigitalOut output(MBED_CONF_APP_RELAY_CONTROL, 1);

NetworkInterface * network_if;
UDPSocket* my_socket;
// queue for sending messages from button press.
EventQueue queue;
// for LED blinking
Ticker ticker;
// Handle for delayed message send
int queue_handle = 0;

uint8_t multi_cast_addr[16] = {0};
uint8_t receive_buffer[20];
// how many hops the multicast message can go
static const int16_t multicast_hops = 10;
bool button_status = 0;

void start_mesh_led_control_example(NetworkInterface * interface){
    tr_debug("start_mesh_led_control_example()");
    MBED_ASSERT(MBED_CONF_APP_LED != NC);
    MBED_ASSERT(MBED_CONF_APP_BUTTON != NC);

    network_if = interface;
    stoip6(multicast_addr_str, strlen(multicast_addr_str), multi_cast_addr);
    init_socket();
}

static void blink() {
    led_1 = !led_1;
}

void start_blinking() {
    ticker.attach(blink, 1.0);
}

void cancel_blinking() {
    ticker.detach();
    led_1=1;
}

static void send_message() {
    tr_debug("send msg %d", button_status);

    char buf[20];
    int length;

    /**
    * Multicast control message is a NUL terminated string of semicolon separated
    * <field identifier>:<value> pairs.
    *
    * Light control message format:
    * t:lights;g:<group_id>;s:<1|0>;\0
    */
    length = snprintf(buf, sizeof(buf), "t:lights;g:%03d;s:%s;", MY_GROUP, (button_status ? "1" : "0")) + 1;
    MBED_ASSERT(length > 0);
    tr_debug("Sending lightcontrol message, %d bytes: %s", length, buf);
    SocketAddress send_sockAddr(multi_cast_addr, NSAPI_IPv6, UDP_PORT);
    my_socket->sendto(send_sockAddr, buf, 20);
    //After message is sent, it is received from the network
}

// As this comes from isr, we cannot use printing or network functions directly from here.
static void my_button_isr() {
    button_status = !button_status;
    queue.call(send_message);
}

static void update_state(uint8_t state) {
    if (state == 1) {
       tr_debug("Turning led on\n");
       led_1 = 0;
       button_status=1;
       output = 0;
       }
    else {
       tr_debug("Turning led off\n");
       led_1 = 1;
       button_status=0;
       output = 1;
   }
}

static void handle_message(char* msg) {
    // Check if this is lights message
    uint8_t state=button_status;
    uint16_t group=0xffff;

    if (strstr(msg, "t:lights;") == NULL) {
       return;
    }

    if (strstr(msg, "s:1;") != NULL) {
        state = 1;
    }
    else if (strstr(msg, "s:0;") != NULL) {
        state = 0;
    }

    // 0==master, 1==default group
    char *msg_ptr = strstr(msg, "g:");
    if (msg_ptr) {
        char *ptr;
        group = strtol(msg_ptr, &ptr, 10);
    }

    // in this example we only use one group
    if (group==MASTER_GROUP || group==MY_GROUP) {
        update_state(state);
    }
}

static void receive() {
    // Read data from the socket
    SocketAddress source_addr;
    memset(receive_buffer, 0, sizeof(receive_buffer));
    bool something_in_socket=true;
    // read all messages
    while (something_in_socket) {
        int length = my_socket->recvfrom(&source_addr, receive_buffer, sizeof(receive_buffer) - 1);
        if (length > 0) {
            int timeout_value = MESSAGE_WAIT_TIMEOUT;
            tr_debug("Packet from %s\n", source_addr.get_ip_address());
            timeout_value += rand() % 30;
            tr_debug("Advertisiment after %d seconds", timeout_value);
            queue.cancel(queue_handle);
            queue_handle = queue.call_in((timeout_value * 1000), send_message);
            // Handle command - "on", "off"
            handle_message((char*)receive_buffer);
        }
        else if (length!=NSAPI_ERROR_WOULD_BLOCK) {
            tr_error("Error happened when receiving %d\n", length);
            something_in_socket=false;
        }
        else {
            // there was nothing to read.
            something_in_socket=false;
        }
    }
}

static void handle_socket() {
    // call-back might come from ISR
    queue.call(receive);
}

static void init_socket()
{
    my_socket = new UDPSocket();
    my_socket->open(network_if);
    my_socket->set_blocking(false);
    my_socket->bind(UDP_PORT);
    my_socket->setsockopt(SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, &multicast_hops, sizeof(multicast_hops));

    ns_ipv6_mreq_t mreq;
    memcpy(mreq.ipv6mr_multiaddr, multi_cast_addr, 16);
    mreq.ipv6mr_interface = 0;

    my_socket->setsockopt(SOCKET_IPPROTO_IPV6, SOCKET_IPV6_JOIN_GROUP, &mreq, sizeof mreq);

    if (MBED_CONF_APP_BUTTON != NC) {
        my_button.fall(&my_button_isr);
        my_button.mode(MBED_CONF_APP_BUTTON_MODE);
    }
    //let's register the call-back function.
    //If something happens in socket (packets in or out), the call-back is called.
    my_socket->sigio(callback(handle_socket));
    // dispatch forever
    queue.dispatch();
}

Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.