Browse Source

examples: provide example application that uses LWMAC.

master
zhuoshuguo 5 years ago
parent
commit
e195a08a77
  1. 61
      examples/gnrc_networking_mac/Makefile
  2. 79
      examples/gnrc_networking_mac/README.md
  3. 50
      examples/gnrc_networking_mac/main.c
  4. 174
      examples/gnrc_networking_mac/udp.c

61
examples/gnrc_networking_mac/Makefile

@ -0,0 +1,61 @@
# name of your application
APPLICATION = gnrc_networking_mac
# If no BOARD is found in the environment, use this default:
BOARD ?= samr21-xpro
# Currently, LWMAC is only tested and evaluated through on samr21-xpro.
# Once LWMAC has also been tested through on other boards, the whitelist should be
# then accordingly extended.
BOARD_WHITELIST := samr21-xpro
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..
# Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
# Specify the mandatory networking modules for IPv6 and UDP
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_udp
# Add a routing protocol
USEMODULE += gnrc_rpl
USEMODULE += auto_init_gnrc_rpl
# This application dumps received packets to STDIO using the pktdump module
USEMODULE += gnrc_pktdump
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
USEMODULE += netstats_l2
USEMODULE += netstats_ipv6
USEMODULE += netstats_rpl
# Use LWMAC as the MAC layer protocol
USEMODULE += gnrc_lwmac
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
CFLAGS += -DDEVELHELP
# Uncomment the following 2 lines to specify static link lokal IPv6 address
# this might be useful for testing, in cases where you cannot or do not want to
# run a shell with ifconfig to get the real link lokal address.
#IPV6_STATIC_LLADDR ?= '"fe80::cafe:cafe:cafe:1"'
#CFLAGS += -DGNRC_IPV6_STATIC_LLADDR=$(IPV6_STATIC_LLADDR)
# Uncomment this to join RPL DODAGs even if DIOs do not contain
# DODAG Configuration Options (see the doc for more info)
# CFLAGS += -DGNRC_RPL_DODAG_CONF_OPTIONAL_ON_JOIN
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
include $(RIOTBASE)/Makefile.include
# Set a custom channel
DEFAULT_CHANNEL ?= 26
CFLAGS += -DIEEE802154_DEFAULT_CHANNEL=$(DEFAULT_CHANNEL)

79
examples/gnrc_networking_mac/README.md

@ -0,0 +1,79 @@
# gnrc_networking_mac example
This example shows you how to try out communications between RIOT instances with LWMAC as the MAC layer ptotocol for IEEE 802.15.4 devices.
This example is generally based on `gnrc_networking` but embeds LWMAC to support low duty-cycle operation to conserve power. Also, it intends to show that the duty-cycled LWMAC can support popular upper layer protocols like UDP and RPL.
Currently, it seems that you can only use the samr21-xpro board to test this MAC, since some certain features of the protocol are only available on that platform. Also, the current implementation of LWMAC uses RTT as the underlying timer source. So, currently, LWMAC cannot run on nodes that don't have RTT. But, as a long-term plan, we will replace RTT by a general timer API as the underlying timer to make LWMAC available for more devices, when the related implementations are ready.
## Usage
Build, flash and start the application:
```
export BOARD=your_board
make
make flash
make term
```
## Print out the achieved duty-cyle of LWMAC
You can print out the radio duty-cyle (a roughly one) of LWMAC by setting the `LWMAC_ENABLE_DUTYCYLE_RECORD` flag in `sys/include/net/gnrc/lwmac/types.h` to "1". By doing so, each time when a device sends or receives a packet, it will print out its radio duty-cycle value.
Also, by further enabling the debug flag in `sys/net/gnrc/link_layer/lwmac/tx_state_machine.c`, you will get the printout of how many preamble (WR) and time (sending delay) cost for sending this packet in the TX procedure of LWMAC.
## Try UDP transmissions with LWMAC
In the RIOT shell, get to know the IP address of one node:
2017-06-06 15:05:48,279 - INFO # ifconfig
2017-06-06 15:05:48,284 - INFO # Iface 7 HWaddr: 79:f6 Channel: 26 Page: 0 NID: 0x23
2017-06-06 15:05:48,288 - INFO # Long HWaddr: 79:67:35:7e:54:3a:79:f6
2017-06-06 15:05:48,297 - INFO # TX-Power: 0dBm State: SLEEP max. Retrans.: 3 CSMA Retries: 4
2017-06-06 15:05:48,303 - INFO # CSMA MTU:1280 HL:64 6LO RTR IPHC
2017-06-06 15:05:48,306 - INFO # Source address length: 8
2017-06-06 15:05:48,309 - INFO # Link type: wireless
2017-06-06 15:05:48,314 - INFO # inet6 addr: ff02::1/128 scope: local [multicast]
2017-06-06 15:05:48,320 - INFO # inet6 addr: fe80::7b67:357e:543a:79f6/64 scope: local
2017-06-06 15:05:48,326 - INFO # inet6 addr: ff02::1:ff3a:79f6/128 scope: local [multicast]
2017-06-06 15:05:48,331 - INFO # inet6 addr: ff02::1a/128 scope: local [multicast]
and start a UDP server.
> udp server start 8808
This node is now ready to receive data on port `8808`.
In a second terminal, start a second RIOT instance, in the RIOT shell, you can now send a message to the first RIOT instance:
> udp send fe80::7b67:357e:543a:79f6 8808 testmessage
In your first terminal (the receiver side), you should now see output that looks like this:
2017-06-06 15:00:06,894 - INFO # [LWMAC]: achieved duty-cycle: 10 %
2017-06-06 15:00:06,896 - INFO # PKTDUMP: data received:
2017-06-06 15:00:06,901 - INFO # ~~ SNIP 0 - size: 11 byte, type: NETTYPE_UNDEF (0)
2017-06-06 15:00:06,907 - INFO # 00000000 74 65 73 74 6D 65 73 73 61 67 65
2017-06-06 15:00:06,911 - INFO # ~~ SNIP 1 - size: 8 byte, type: NETTYPE_UDP (5)
2017-06-06 15:00:06,914 - INFO # src-port: 8808 dst-port: 8808
2017-06-06 15:00:06,917 - INFO # length: 19 cksum: 0xf729
2017-06-06 15:00:06,921 - INFO # ~~ SNIP 2 - size: 40 byte, type: NETTYPE_IPV6 (3)
2017-06-06 15:00:06,925 - INFO # traffic class: 0x00 (ECN: 0x0, DSCP: 0x00)
2017-06-06 15:00:06,927 - INFO # flow label: 0x00000
2017-06-06 15:00:06,930 - INFO # length: 19 next header: 17 hop limit: 64
2017-06-06 15:00:06,934 - INFO # source address: fe80::7b67:877:19f:331e
2017-06-06 15:00:06,938 - INFO # destination address: fe80::7b67:357e:543a:79f6
2017-06-06 15:00:06,943 - INFO # ~~ SNIP 3 - size: 24 byte, type: NETTYPE_NETIF (-1)
2017-06-06 15:00:06,945 - INFO # if_pid: 7 rssi: 51 lqi: 255
2017-06-06 15:00:06,946 - INFO # flags: 0x0
2017-06-06 15:00:06,949 - INFO # src_l2addr: 79:67:08:77:01:9f:33:1e
2017-06-06 15:00:06,952 - INFO # dst_l2addr: 79:67:35:7e:54:3a:79:f6
2017-06-06 15:00:06,956 - INFO # ~~ PKT - 4 snips, total size: 83 byte
In your second terminal (the sender side), you should now see output that looks like this:
2017-06-06 15:00:06,871 - INFO # udp send fe80::7b67:357e:543a:79f6 8808 testmessage
2017-06-06 15:00:06,877 - INFO # Success: sent 11 byte(s) to [fe80::7b67:357e:543a:79f6]:8808
2017-06-06 15:00:06,890 - INFO # [LWMAC-tx]: spent 1 WR in TX
2017-06-06 15:00:06,894 - INFO # [LWMAC-tx]: pkt sending delay in TX: 8422 us
2017-06-06 15:00:06,898 - INFO # [LWMAC]: achieved duty-cycle: 10 %

50
examples/gnrc_networking_mac/main.c

@ -0,0 +1,50 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief Example application for demonstrating the RIOT network stack
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include "shell.h"
#include "msg.h"
#define MAIN_QUEUE_SIZE (8)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
extern int udp_cmd(int argc, char **argv);
static const shell_command_t shell_commands[] = {
{ "udp", "send data over UDP and listen on UDP ports", udp_cmd },
{ NULL, NULL, NULL }
};
int main(void)
{
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
puts("RIOT network stack example application");
/* start shell */
puts("All up, running the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should be never reached */
return 0;
}

174
examples/gnrc_networking_mac/udp.c

@ -0,0 +1,174 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief Demonstrating the sending and receiving of UDP data
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdio.h>
#include <inttypes.h>
#include "net/gnrc.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/udp.h"
#include "net/gnrc/pktdump.h"
#include "timex.h"
#include "xtimer.h"
static gnrc_netreg_entry_t server = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
KERNEL_PID_UNDEF);
static void send(char *addr_str, char *port_str, char *data, unsigned int num,
unsigned int delay)
{
uint16_t port;
ipv6_addr_t addr;
/* parse destination address */
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
puts("Error: unable to parse destination address");
return;
}
/* parse port */
port = (uint16_t)atoi(port_str);
if (port == 0) {
puts("Error: unable to parse destination port");
return;
}
for (unsigned int i = 0; i < num; i++) {
gnrc_pktsnip_t *payload, *udp, *ip;
unsigned payload_size;
/* allocate payload */
payload = gnrc_pktbuf_add(NULL, data, strlen(data), GNRC_NETTYPE_UNDEF);
if (payload == NULL) {
puts("Error: unable to copy data to packet buffer");
return;
}
/* store size for output */
payload_size = (unsigned)payload->size;
/* allocate UDP header, set source port := destination port */
udp = gnrc_udp_hdr_build(payload, port, port);
if (udp == NULL) {
puts("Error: unable to allocate UDP header");
gnrc_pktbuf_release(payload);
return;
}
/* allocate IPv6 header */
ip = gnrc_ipv6_hdr_build(udp, NULL, &addr);
if (ip == NULL) {
puts("Error: unable to allocate IPv6 header");
gnrc_pktbuf_release(udp);
return;
}
/* send packet */
if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_UDP, GNRC_NETREG_DEMUX_CTX_ALL, ip)) {
puts("Error: unable to locate UDP thread");
gnrc_pktbuf_release(ip);
return;
}
/* access to `payload` was implicitly given up with the send operation above
* => use temporary variable for output */
printf("Success: sent %u byte(s) to [%s]:%u\n", payload_size, addr_str,
port);
xtimer_usleep(delay);
}
}
static void start_server(char *port_str)
{
uint16_t port;
/* check if server is already running */
if (server.target.pid != KERNEL_PID_UNDEF) {
printf("Error: server already running on port %" PRIu32 "\n",
server.demux_ctx);
return;
}
/* parse port */
port = (uint16_t)atoi(port_str);
if (port == 0) {
puts("Error: invalid port specified");
return;
}
/* start server (which means registering pktdump for the chosen port) */
server.target.pid = gnrc_pktdump_pid;
server.demux_ctx = (uint32_t)port;
gnrc_netreg_register(GNRC_NETTYPE_UDP, &server);
printf("Success: started UDP server on port %" PRIu16 "\n", port);
}
static void stop_server(void)
{
/* check if server is running at all */
if (server.target.pid == KERNEL_PID_UNDEF) {
printf("Error: server was not running\n");
return;
}
/* stop server */
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &server);
server.target.pid = KERNEL_PID_UNDEF;
puts("Success: stopped UDP server");
}
int udp_cmd(int argc, char **argv)
{
if (argc < 2) {
printf("usage: %s [send|server]\n", argv[0]);
return 1;
}
if (strcmp(argv[1], "send") == 0) {
uint32_t num = 1;
uint32_t delay = 1000000;
if (argc < 5) {
printf("usage: %s send <addr> <port> <data> [<num> [<delay in us>]]\n",
argv[0]);
return 1;
}
if (argc > 5) {
num = (uint32_t)atoi(argv[5]);
}
if (argc > 6) {
delay = (uint32_t)atoi(argv[6]);
}
send(argv[2], argv[3], argv[4], num, delay);
}
else if (strcmp(argv[1], "server") == 0) {
if (argc < 3) {
printf("usage: %s server [start|stop]\n", argv[0]);
return 1;
}
if (strcmp(argv[2], "start") == 0) {
if (argc < 4) {
printf("usage %s server start <port>\n", argv[0]);
return 1;
}
start_server(argv[3]);
}
else if (strcmp(argv[2], "stop") == 0) {
stop_server();
}
else {
puts("error: invalid command");
}
}
else {
puts("error: invalid command");
}
return 0;
}
Loading…
Cancel
Save