mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
examples: provide example application that uses LWMAC.
This commit is contained in:
parent
9e640ae79a
commit
e195a08a77
61
examples/gnrc_networking_mac/Makefile
Normal file
61
examples/gnrc_networking_mac/Makefile
Normal file
@ -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
Normal file
79
examples/gnrc_networking_mac/README.md
Normal file
@ -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
Normal file
50
examples/gnrc_networking_mac/main.c
Normal file
@ -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
Normal file
174
examples/gnrc_networking_mac/udp.c
Normal file
@ -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…
Reference in New Issue
Block a user