1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

tests/pkg_openwsn: initial import

Co-authored-by: Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
This commit is contained in:
Francisco Molina 2020-06-25 22:36:41 +02:00
parent 844ccfbeb3
commit 985a706733
No known key found for this signature in database
GPG Key ID: 3E94EAC3DBDEEDA8
4 changed files with 902 additions and 0 deletions

View File

@ -0,0 +1,67 @@
BOARD ?= iotlab-m3
include ../Makefile.tests_common
# list of arm boards that provide at86rf2xx radios, can't require it so
# add whitelist
BOARD_WHITELIST = \
fox \
iotlab-m3 \
iotlab-a8-m3 \
samr21-xpro \
samr30-xpro \
#
## OpenWSN Modules
USEPKG += openwsn
USEMODULE += openwsn_openstack
USEMODULE += openwsn_scheduler
# Optional Module required for root nodes
# USEMODULE += openwsn_serial
# Optional Modules
USEMODULE += openwsn_leds
USEMODULE += openwsn_debugpins
ifneq (,$(filter openwsn_serial,$(USEMODULE)))
# Uncomment to use STDIO_UART_DEV as the uart for OpenWSN openserial
# USEMODULE += stdio_null
ifneq (,$(filter iotlab-m3 iotlab-a8-m3,$(BOARD)))
USEMODULE += stdio_null
endif
# OpenWSN serial module can't handle data at more than 115200 bauds/s,
# depending on the platform this might be even lower (e.g. 57600 bauds
# for iotlab-m3, 19200 for samr21-xpro).
# NOTE: baudrate can'y be changed when testing over IotLab.
OPENSERIAL_BAUD ?=
ifneq (,$(OPENSERIAL_BAUD))
CFLAGS += -DOPENWSN_UART_BAUDRATE=$(OPENSERIAL_BAUD)
ifneq (,$(filter stdio_null,$(USEMODULE)))
BAUD ?= $(OPENSERIAL_BAUD)
endif
endif
endif
# To enable debugging prints on OpenWSN code
# export OPENWSN_LOG_LEVEL ?= LOG_ERROR
## Test application Modules
USEMODULE += ipv6_addr
USEMODULE += ps
USEMODULE += od_string
USEMODULE += shell
USEMODULE += shell_commands
# ztimer is used instead of xtimer because it's a dependency of some
# OpenWSN modules.
USEMODULE += ztimer_usec
include $(RIOTBASE)/Makefile.include
# We want the highest possible frequency set for periph_rtt, but not all
# platforms can configure this value. use highest possible RTT_FREQUENCY
# for platforms that allow it
ifneq (,$(filter stm32,$(CPU)))
RTT_FREQUENCY ?= RTT_MAX_FREQUENCY
CFLAGS += -DRTT_FREQUENCY=$(RTT_FREQUENCY)
endif

316
tests/pkg_openwsn/README.md Normal file
View File

@ -0,0 +1,316 @@
# OpenWSN on RIOT
This test demonstrates the [OpenWSN](https://github.com/openwsn-berkeley/openwsn-fw) full
stack (UDP, IPv6, RPL, 6TiSCH) running on RIOT. When flashed, it will initialize the stack
and provide the user with some minimal shell commands to:
- print the own IPv6 address `ifconfig`
- change the UDP destination port `udp server start <port>`
- send a UDP packet `udp send <addr> <port> <data>`
A tun interface can also be set to allow traffic out of the network. This
allows pinging nodes in the network from the host.
Please note that this port is still in experimental status. For further information
about the port refer to the [pkg documentation](../../pkg/openwsn/doc.txt).
## Experimental setups
The following setup act as a starting point for testing and debugging. Either
build and flash local nodes or incorporate the [FIT IoT-LAB](https://www.iot-lab.info/)
Testbed. Please check the ports [documentation](../../pkg/openwsn/doc.txt) for information
about supported hardware platforms.
This port currently needs `openvisualizer`, please make sure you follow the
[pre-requisites](../../dist/tools/openvisualizer/makefile.openvisualizer.inc.mk)
to install a patched version of `openvisualizer`.
An OpenWSN root node acts as a border router, it tunnels IEEE80215.4.E
between `openvisualizer` and the network without looking at the frame content.
This means that a root node will not be reachable when 'pinging' from the host
or if trying to send udp packets to it.
Two test cases are described with different requirements:
1. From host [ping](#Communicating-with-host-(IPV6)) nodes in network over ipv6:
```
- 1 root node + tun interface
- +1 leaf node
```
2. Sending [UDP](#Communicating-over-udp) packets between nodes:
```
- 1 root node
- +2 leaf node
```
### Synchronization
There are 3 things that can be done to speed up and help nodes synchronization,
all related to how often a node will receive an EB (enhanced beacon).
- disable channel hopping
- increase EB_PORTION
- reduce SLOTFRAME_LENGTH
If you want to disable channel hopping to speed up synchronization you can set
a fix channel.
$ export CFLAGS=-DIEEE802154E_SINGLE_CHANNEL=17
Enhanced beacon are sent once per slotframe with a likelihood of 1/EB_PORTION.
The default value is EB_PORTION = 10 (10%), reducing the value of EB_PORTION
increases the frequency at which beacons are sent, this will also help nodes
to stay synchronized.
$ export CFLAGS=-DEB_PORTION=4
EB gets an opportunity to be sent (depending on 1/EB_PORTION) once in every
slotframe, reducing the soltframe length will cause EB to be sent more often.
Beware that this could have an impact on the MSF (Minimal Scheduling Function).
$ export CFLAGS=-DSLOTFRAME_LENGTH=51
See [documentation](../../pkg/openwsn/doc.txt#Synchronization) for more on
synchronization.
## IMPORTANT!
OpenWSN uses source routing and this means all network traffic must go through
from the root node to OpenVisualizer. If the root node configuration can't
handle the configured baudrate correctly this will lead to packet loss.
Currently these are the tested configurations:
(a) samr21-xpro network:
- leaf nodes using `openwsn_sctimer_rtt`
- root node using `openwsn_sctimer_rtt` and 19200 baudrate directly
connected to UART pins (not through the usb debugger)
(b) iotlab-m3 network:
- leaf nodes using `openwsn_sctimer_rtt` or `sctimer_ztimer`
- root node using `openwsn_sctimer_rtt` and 57600 baudrate
For more details on this please refer to [pkg documentation](../../pkg/openwsn/doc.txt).
## Testing configuration (a) (three local samr21-xpro nodes)
1. figure out each node's serial number (`edbg -l` output might help)
2. hook up the root node to an external USB-serial-converter. For that, connect
the converter's RXD/TXD pins to the node's PA22/PA23.
3. flash the root node:
$ SERIAL=${ROOT_SERIAL_NODE} OPENSERIAL_BAUD=19200 USEMODULE=openwsn_serial \
BOARD=samr21-xpro make flash -j4
4. flash the leaf nodes:
$ BOARD=samr21-xpro make all -j4
$ BOARD=samr21-xpro SERIAL=${LEAF_SERIAL_NODE0} make flash-only
$ BOARD=samr21-xpro SERIAL=${LEAF_SERIAL_NODE1} make flash-only
5. open a shell to the leaf nodes
so in two shell windows, do (one in each):
$ BOARD=samr21-xpro SERIAL=${LEAF_SERIAL_NODE0} make term
$ BOARD=samr21-xpro SERIAL=${LEAF_SERIAL_NODE1} make term
6. in a third shell, launch openvisualizer:
$ BOARD=samr21-xpro PORT=<USB-serial-port, e.g., /dev/ttyUSB0> BAUD=19200 \
make openv-termroot
## Testing configuration (b) (iotlab-m3 network on iotlab)
When using OpenVisualizer over iot-lab an ssh-tunnel is opened to connect to the
IoT-LAB motes' TCP port. For this to work you will need:
- A valid IoT-LAB [account](https://www.iot-lab.info/testbed/signup)
- Authenticate locally to IoT-LAB `$ iotlab-auth -u <login>`
1. Launch an experiment booking 3+ `iotlab-m3` nodes:
$ iotlab-experiment submit -d 120 -l 3,archi=m3:at86rf231+site=saclay
$ iotlab-experiment wait
$ iotlab-experiment get --nodes
Since multiple nodes where configured for the experiment `IOTLAB_NODE` needs
to be specified for every node, `IOTLAB_NODE=m3-%.saclay.iot-lab.info`
2. flash the root node
$ IOTLAB_NODE=${ROOT_IOTLAB_NODE} USEMODULE=openwsn_serial \
BOARD=iotlab-m3 make -C tests/pkg_openwsn flash
3. open a shell to the leaf nodes so in two shell windows, do (one in each):
$ BOARD=iotlab-m3 make -C tests/pkg_openwsn all -j4
$ BOARD=iotlab-m3 IOTLAB_NODE=${LEAF_IOTLAB_NODE0} make -C tests/pkg_openwsn flash-only
$ BOARD=iotlab-m3 IOTLAB_NODE=${LEAF_IOTLAB_NODE1} make -C tests/pkg_openwsn flash-only
4. open a shell to the leaf nodes
so in two shell windows, do (one in each):
$ BOARD=iotlab-m3 IOTLAB_NODE=${LEAF_IOTLAB_NODE0} make -C tests/pkg_openwsn term
$ BOARD=iotlab-m3 IOTLAB_NODE=${LEAF_IOTLAB_NODE1} make -C tests/pkg_openwsn term
5. in a third shell, launch openvisualizer:
$ BOARD=iotlab-m3 IOTLAB_NODE=${ROOT_IOTLAB_NODE} make -C tests/pkg_openwsn openv-termroot
### Network Setup
If (a) and (b) where followed then on each lead node you should be able
to see the ipv6 address:
main(): This is RIOT! (Version: 2020.04-devel-1649-g96fa9-pr_openwsn)
OpenWSN UDP test
You are running RIOT on a(n) iotlab-m3 board.
This board features a(n) stm32f1 MCU.
> ifconfig
ifconfig
Iface 3 HWaddr: 07:C2 NID: CA:FE
Long HWaddr: 96:35:9A:92:4E:3D:65:78
inet6 addr: fe80::9635:9a92:4e3d:6578
IEEE802154E sync: 0
6TiSCH joined: 0
NO RPL parent
On the root node Openvisualizer is launched and the DAGroot is setup.
[OpenVisualizerServer:INFO] Extracting firmware definitions.
[Utils:VERBOSE] Extracting firmware component names
[Utils:VERBOSE] Extracting firmware log descriptions.
[Utils:VERBOSE] Extracting 6top return codes.
[Utils:VERBOSE] Extracting 6top states.
[OpenVisualizerServer:INFO] Starting RPC server
[OpenVisualizerServer:SUCCESS] Setting mote 43eb as root
[ParserIEC:ERROR] 43eb [IEEE802154E] wrong state 1 in startSlot, at slotOffset 1
[RPL:INFO] registering DAGroot 82-6b-de-ec-58-34-65-78
The root node will now start sending beacons and other nodes will synchronize, and
join. If channel hopping is enabled this can take quite some time (see
[Synchronization](../../pkg/openwsn/doc.txt#Synchronization). Once leaf nodes
have joined the network when issuing `ifconfing` you should see:
ifconfig
Iface 3 HWaddr: 0F:F4 NID: CA:FE
Long HWaddr: 06:84:F6:65:10:6B:11:14
inet6 addr: bbbb::684:f665:106b:1114
IEEE802154E sync: 1
6TiSCH joined: 1
RPL rank: 2816
RPL parent: 2A:BA:F7:65:10:6B:11:14
RPL children:
RPL DODAG ID: bbbb::2aba:f765:106b:1114
The root node should start receiving RPL DAOs:
[RPL:INFO] received RPL DAO from bbbb:0:0:0:ab8:fc65:106b:1114
- parents:
bbbb:0:0:0:2aba:f765:106b:1114
- children:
bbbb:0:0:0:684:f665:106b:1114
[RPL:INFO] received RPL DAO from bbbb:0:0:0:684:f665:106b:1114
- parents:
bbbb:0:0:0:2aba:f765:106b:1114
- children:
bbbb:0:0:0:ab8:fc65:106b:1114
[RPL:INFO] received RPL DAO from bbbb:0:0:0:684:f665:106b:1114
- parents:
bbbb:0:0:0:2aba:f765:106b:1114
- children:
bbbb:0:0:0:ab8:fc65:106b:1114
Once DAOs for all nodes start being received the network is setup and you
should be able to send packets between nodes or ping from the host.
### Communicating over udp
On one node setup a udp-server:
> ifconfig
ifconfig
Iface 3 HWaddr: 0F:F4 NID: CA:FE
Long HWaddr: 06:84:F6:65:10:6B:11:14
inet6 addr: bbbb::684:f665:106b:1114
IEEE802154E sync: 1
6TiSCH joined: 1
RPL rank: 2816
RPL parent: 2A:BA:F7:65:10:6B:11:14
RPL children:
RPL DODAG ID: bbbb::2aba:f765:106b:1114
> udp server start 3000
udp server start 3000
Set UDP server port to 3000
On the other node send udp messages
> udp send bbbb::684:f665:106b:1114 3000 hello
udp send bbbb::684:f665:106b:1114 3000 hello
Send 5 byte over UDP to [bbbb::684:f665:106b:1114]:3000
> msg.l2_sendDoneError: 0
Send success
The first node should receive the message
> Received 12 bytes on port 3000
00000000 A6 28 00 00 00 02 00 68 65 6C 6C 6F .(.....hello
### Communicating with host (IPV6)
OpenVisualizer can set up a tun interface to communicate with the host computer.
This will require starting `OpenVisualizer` with root privileges. The only
difference with the previous setup is that the root node must be setup as
follows:
on iotlab:
$ IOTLAB_NODE=${ROOT_IOTLAB_NODE} BOARD=iotlab-m3 \
make -C tests/pkg_openwsn openv-termtun
on local boards:
$ PORT=<USB-serial-port, e.g., /dev/ttyUSB0> BOARD=samr21-xpro \
make -C tests/pkg_openwsn openv-termtun
Once DAOs are received you can ping nodes in the network from your host:
```
$ ping6 -s 40 -i 5 bbbb:0:0:0:2ab5:fc65:106b:1114
PING bbbb:0:0:0:2ab5:fc65:106b:1114(bbbb::2ab5:fc65:106b:1114) 40 data bytes
48 bytes from bbbb::2ab5:fc65:106b:1114: icmp_seq=1 ttl=64 time=1064 ms
48 bytes from bbbb::2ab5:fc65:106b:1114: icmp_seq=2 ttl=64 time=2111 ms
48 bytes from bbbb::2ab5:fc65:106b:1114: icmp_seq=3 ttl=64 time=1141 ms
48 bytes from bbbb::2ab5:fc65:106b:1114: icmp_seq=4 ttl=64 time=2197 ms
48 bytes from bbbb::2ab5:fc65:106b:1114: icmp_seq=5 ttl=64 time=1228 ms
48 bytes from bbbb::2ab5:fc65:106b:1114: icmp_seq=6 ttl=64 time=2306 ms
48 bytes from bbbb::2ab5:fc65:106b:1114: icmp_seq=7 ttl=64 time=1324 ms
```
If openserial is used on the leaf node you would get the following output:
```
16:02:38 [ParserIEC:INFO] 768f [ICMPv6ECHO] received an echo request
16:02:44 [ParserIEC:INFO] 768f [ICMPv6ECHO] received an echo request
16:02:48 [ParserIEC:INFO] 768f [ICMPv6ECHO] received an echo request
16:02:54 [ParserIEC:INFO] 768f [ICMPv6ECHO] received an echo request
```
Some considerations:
- Nodes duty cycle is ~0.5%, so nodes get a chance to transmit roughly every
2s, so the worst case scenario is ~4s RTT. This is increased for big payloads
since it will lead to fragmentation.
- If incoming packet rate is too fast the internal packet queue can be
be overloaded.

324
tests/pkg_openwsn/main.c Normal file
View File

@ -0,0 +1,324 @@
/*
* Copyright (C) 2017 Hamburg University of Applied Sciences
*
* 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 tests
* @{
*
* @file
* @brief OpenWSN test application
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#include "od.h"
#include "fmt.h"
#include "shell.h"
#include "openwsn.h"
#include "net/ipv6/addr.h"
#include "opendefs.h"
#include "scheduler.h"
#include "02a-MAClow/IEEE802154E.h"
#include "02b-MAChigh/neighbors.h"
#include "03b-IPv6/icmpv6rpl.h"
#include "04-TRAN/openudp.h"
#include "cjoin.h"
#include "cross-layers/openqueue.h"
#include "cross-layers/idmanager.h"
#include "cross-layers/packetfunctions.h"
extern idmanager_vars_t idmanager_vars;
extern icmpv6rpl_vars_t icmpv6rpl_vars;
extern neighbors_vars_t neighbors_vars;
extern openqueue_vars_t openqueue_vars;
extern schedule_vars_t schedule_vars;
extern scheduler_dbg_t scheduler_dbg;
udp_resource_desc_t uinject_vars;
char addr_str[IPV6_ADDR_MAX_STR_LEN];
void uinject_sendDone(OpenQueueEntry_t *msg, owerror_t error)
{
(void)error;
printf("msg.l2_sendDoneError: %x\n", msg->l2_sendDoneError);
openqueue_freePacketBuffer(msg);
puts("Send success");
}
void uinject_receive(OpenQueueEntry_t *pkt)
{
printf("Received %i bytes on port %i\n", (int)pkt->length,
pkt->l4_destination_port);
od_hex_dump(pkt->payload, pkt->length, OD_WIDTH_DEFAULT);
openqueue_freePacketBuffer(pkt);
}
void uinject_init(void)
{
uinject_vars.port = WKP_UDP_INJECT;
uinject_vars.callbackReceive = &uinject_receive;
uinject_vars.callbackSendDone = &uinject_sendDone;
openudp_register(&uinject_vars);
}
char *_array_2_string(const uint8_t *addr, size_t addr_len, char *out)
{
char *res = out;
assert((out != NULL) && ((addr != NULL) || (addr_len == 0U)));
out[0] = '\0';
for (size_t i = 0; i < addr_len; i++) {
out += fmt_byte_hex((out), *(addr++));
*(out++) = (i == (addr_len - 1)) ? '\0' : ':';
}
return res;
}
static int ifconfig_cmd(int argc, char **argv)
{
(void)argc;
(void)argv;
open_addr_t *hwaddr;
open_addr_t temp_my128bID;
memcpy(&temp_my128bID.addr_128b[0], &idmanager_vars.myPrefix.prefix, 8);
memcpy(&temp_my128bID.addr_128b[8], &idmanager_vars.my64bID.addr_64b, 8);
printf("Iface %d ", openwsn_get_pid());
hwaddr = idmanager_getMyID(ADDR_16B);
printf("\tHWaddr: %s ", _array_2_string(hwaddr->addr_16b, 2, addr_str));
hwaddr = idmanager_getMyID(ADDR_PANID);
printf("NID: %s\n", _array_2_string(hwaddr->panid, 2, addr_str));
printf("\n");
hwaddr = idmanager_getMyID(ADDR_64B);
printf("\t\tLong HWaddr: %s\n", _array_2_string(hwaddr->addr_64b, 8, addr_str));
ipv6_addr_to_str(addr_str, (ipv6_addr_t *)temp_my128bID.addr_128b,
sizeof(addr_str));
printf("\t\tinet6 addr: %s\n", addr_str);
printf("\n");
printf("\t\tIEEE802154E sync: %i\n", ieee154e_isSynch());
printf("\t\t6TiSCH joined: %i\n", cjoin_getIsJoined());
printf("\n");
if (idmanager_vars.isDAGroot) {
puts("\t\tNode is DAG root");
}
else {
if (icmpv6rpl_vars.haveParent) {
printf("\t\tRPL rank: %i\n", icmpv6rpl_vars.myDAGrank);
printf("\t\tRPL parent: %s\n", \
_array_2_string(neighbors_vars.neighbors[icmpv6rpl_vars.
ParentIndex].
addr_64b.addr_64b, 8, addr_str));
printf("\t\tRPL children:\n");
for (uint8_t i = 0; i < MAXNUMNEIGHBORS; i++) {
if ((neighbors_isNeighborWithHigherDAGrank(i)) == true) {
printf("\t\t\t%s\n", \
_array_2_string(neighbors_vars.neighbors[i].
addr_64b.addr_64b, 8, addr_str));
}
}
ipv6_addr_to_str(addr_str,
(ipv6_addr_t *)icmpv6rpl_vars.dao.DODAGID,
sizeof(addr_str));
printf("\t\tRPL DODAG ID: %16s\n", addr_str);
}
else {
puts("\t\tNO RPL parent");
}
}
return 0;
}
static int nc_cmd(int argc, char **argv)
{
(void)argc;
(void)argv;
for (int i = 0; i < MAXNUMNEIGHBORS; i++) {
_array_2_string(neighbors_vars.neighbors[i].addr_64b.addr_64b, 8,
addr_str);
if (memcmp(addr_str, "00:00:00:00:00:00:00:00", 8) != 0) {
printf("%02i. %s\n", i, addr_str);
}
}
return 0;
}
static const struct {
char *name;
int id;
} names[] = {
{ "?", COMPONENT_NULL },
{ "owsn", COMPONENT_OPENWSN },
{ "idmanager", COMPONENT_IDMANAGER },
{ "oqueue", COMPONENT_OPENQUEUE },
{ "oserial", COMPONENT_OPENSERIAL },
{ "pktfuncs", COMPONENT_PACKETFUNCTIONS },
{ "random", COMPONENT_RANDOM },
{ "radio", COMPONENT_RADIO },
{ "154", COMPONENT_IEEE802154 },
{ "154e", COMPONENT_IEEE802154E },
{ "6top2154e", COMPONENT_SIXTOP_TO_IEEE802154E },
{ "154e26top", COMPONENT_IEEE802154E_TO_SIXTOP },
{ "6top", COMPONENT_SIXTOP },
{ "neigh", COMPONENT_NEIGHBORS },
{ "sched", COMPONENT_SCHEDULE },
{ "6topres", COMPONENT_SIXTOP_RES },
{ "bridge", COMPONENT_OPENBRIDGE },
{ "iphc", COMPONENT_IPHC },
{ "frag", COMPONENT_FRAG },
{ "fwd", COMPONENT_FORWARDING },
{ "icmpv6", COMPONENT_ICMPv6 },
{ "icmpv6ech", COMPONENT_ICMPv6ECHO },
{ "icmpv6rtr", COMPONENT_ICMPv6ROUTER },
{ "icmpv6rpl", COMPONENT_ICMPv6RPL },
{ "udp", COMPONENT_OPENUDP },
{ "coap", COMPONENT_OPENCOAP },
{ "cjoin", COMPONENT_CJOIN },
{ "openoscoap", COMPONENT_OPENOSCOAP },
{ "c6t", COMPONENT_C6T },
{ "uinject", COMPONENT_UINJECT },
};
char *_get_name(int id)
{
for (unsigned i = 0; i < ARRAY_SIZE(names); i++) {
if (id == names[i].id) {
return names[i].name;
}
}
return NULL;
}
static int q_cmd(int argc, char **argv)
{
(void)argc;
(void)argv;
bool queue = 1;
for (uint8_t i = 0; i < QUEUELENGTH; i++) {
if (openqueue_vars.queue[i].creator || openqueue_vars.queue[i].owner) {
queue = 0;
uint8_t creator = openqueue_vars.queue[i].creator;
uint8_t owner = openqueue_vars.queue[i].owner;
printf("Creator: %.9s [%d], ", _get_name(creator), creator);
printf("Owner: %.9s [%d]\n", _get_name(owner), owner);
}
}
if (queue) {
puts("openqueue empty");
}
return 0;
}
static int q_rmv(int argc, char **argv)
{
if (argc < 2) {
printf("usage: %s [creator]\n", argv[0]);
return 1;
}
uint8_t creator = atoi(argv[1]);
if (creator == 0) {
printf("error: invalid input value\n");
return 1;
}
else {
printf("Removing entries created by: %.9s [%d]\n", _get_name(creator), creator);
openqueue_removeAllCreatedBy(creator);
}
return 0;
}
static int as_cmd(int argc, char **argv)
{
(void)argc;
(void)argv;
for (int i = 0; i < MAXACTIVESLOTS; i++) {
switch (schedule_vars.scheduleBuf[i].type) {
case CELLTYPE_TX:
printf("neigh: %s, slot: %03i, chan: %02i, type: TX\n", \
_array_2_string(
schedule_vars.scheduleBuf[i].neighbor.addr_64b,
8, addr_str),
schedule_vars.scheduleBuf[i].slotOffset, \
schedule_vars.scheduleBuf[i].channelOffset);
break;
case CELLTYPE_RX:
printf("slot: %03i, chan: %02i, type: RX\n", \
schedule_vars.scheduleBuf[i].slotOffset, \
schedule_vars.scheduleBuf[i].channelOffset);
break;
case CELLTYPE_TXRX:
printf("neigh: %s, slot: %03i, chan: %02i, type: RXTX\n", \
_array_2_string(
schedule_vars.scheduleBuf[i].neighbor.addr_64b,
8, addr_str),
schedule_vars.scheduleBuf[i].slotOffset, \
schedule_vars.scheduleBuf[i].channelOffset);
break;
default:
break;
}
}
return 0;
}
static int sc_cmd(int argc, char **argv)
{
(void)argc;
(void)argv;
/* TODO allow other prefixes via shell ?!? */
printf("Current tasks:%i\n", scheduler_dbg.numTasksCur);
printf("Max tasks: %i\n", scheduler_dbg.numTasksMax);
return 0;
}
extern int udp_cmd(int argc, char **argv);
static const shell_command_t shell_commands[] = {
{ "ifconfig", "Shows assigned IPv6 addresses", ifconfig_cmd },
{ "nc", "Shows neighbor table", nc_cmd },
{ "q", "Shows Openqueue", q_cmd },
{ "q-rmv", "Remove entries from creator in queue", q_rmv },
{ "as", "Shows active cells", as_cmd },
{ "sc", "Shows scheduler (openos) dbg states", sc_cmd },
{ "udp", "Send data over UDP and listen on UDP ports", udp_cmd },
{ NULL, NULL, NULL }
};
int main(void)
{
puts("OpenWSN UDP test");
printf("You are running RIOT on a(n) %s board.\n", RIOT_BOARD);
printf("This board features a(n) %s MCU.\n", RIOT_MCU);
uinject_init();
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
}

195
tests/pkg_openwsn/udp.c Normal file
View File

@ -0,0 +1,195 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
* Copyright (C) 2018 Hamburg University of Applied Sciences
*
* 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 tests
* @{
*
* @file
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @}
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "ztimer.h"
#include "net/ipv6.h"
#include "opendefs.h"
#include "scheduler.h"
#include "02a-MAClow/IEEE802154E.h"
#include "03b-IPv6/icmpv6rpl.h"
#include "04-TRAN/openudp.h"
#include "cross-layers/openqueue.h"
#include "cross-layers/idmanager.h"
#include "cross-layers/packetfunctions.h"
extern udp_resource_desc_t uinject_vars;
extern idmanager_vars_t idmanager_vars;
extern openudp_vars_t openudp_vars;
static uint16_t counter = 0;
OpenQueueEntry_t *pkt;
void push_pkt_cb(void){
owerror_t ret = openudp_send(pkt);
if (ret == E_FAIL) {
puts("could not send");
openqueue_freePacketBuffer(pkt);
}
}
static int udp_send(char *addr_str, char *port_str, char *data,
unsigned int num, unsigned int delay)
{
size_t data_len;
open_addr_t parentNeighbor;
ipv6_addr_t addr;
data_len = strlen(data);
uint8_t asnArray[data_len];
/* parse destination address */
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
puts("Error: unable to parse destination address, exit");
return 1;
}
for (unsigned int i = 0; i < num; i++) {
printf("Send %u byte over UDP to [%s]:%s\n",
(unsigned)data_len, addr_str, port_str);
/* don't run if not in synch */
if (ieee154e_isSynch() == FALSE) {
puts("Error: Node not in sync, exit");
return 1;
}
/* don't run on dagroot */
if (idmanager_getIsDAGroot()) {
puts("Error: Node is DAGROOT, exit");
return 1;
}
bool foundNeighbor = icmpv6rpl_getPreferredParentEui64(&parentNeighbor);
if (foundNeighbor==FALSE) {
puts("Error: No preferred parent EUI64, exit");
return 1;
}
/* get a free packet buffer */
pkt = openqueue_getFreePacketBuffer(COMPONENT_UINJECT);
if (pkt == NULL) {
puts("Error: could not create packet buffer, exit");
return 1;
}
pkt->owner = COMPONENT_UINJECT;
pkt->creator = COMPONENT_UINJECT;
pkt->l4_protocol = IANA_UDP;
pkt->l4_destination_port = atoi(port_str);
pkt->l4_sourcePortORicmpv6Type = uinject_vars.port;
pkt->l3_destinationAdd.type = ADDR_128B;
memcpy(&pkt->l3_destinationAdd.addr_128b[0], (void *)&addr, 16);
/* add payload */
packetfunctions_reserveHeaderSize(pkt, data_len);
memcpy(&pkt->payload[0], data, data_len);
packetfunctions_reserveHeaderSize(pkt, sizeof(uint16_t));
pkt->payload[1] = (uint8_t)((counter & 0xff00) >> 8);
pkt->payload[0] = (uint8_t)(counter & 0x00ff);
counter++;
packetfunctions_reserveHeaderSize(pkt, sizeof(asn_t));
ieee154e_getAsn(asnArray);
pkt->payload[0] = asnArray[0];
pkt->payload[1] = asnArray[1];
pkt->payload[2] = asnArray[2];
pkt->payload[3] = asnArray[3];
pkt->payload[4] = asnArray[4];
scheduler_push_task(push_pkt_cb, TASKPRIO_COAP);
ztimer_sleep(ZTIMER_USEC, delay);
}
return 0;
}
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 = 1000000LU;
/* don't send as root */
if (idmanager_vars.isDAGroot) {
puts("Error: Node is root, exit");
return 1;
}
if (argc < 5) {
printf("usage: %s send <addr> <port> <hex data> [<num> [<delay in us>]]\n",
argv[0]);
return 1;
}
if (argc > 5) {
num = atoi(argv[5]);
}
if (argc > 6) {
delay = atoi(argv[6]);
}
return udp_send(argv[2], argv[3], argv[4], num, delay);
}
else if (strcmp(argv[1], "server") == 0) {
if (argc < 3) {
printf("usage: %s server [start|list]\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;
}
uint16_t port = atoi(argv[3]);
uinject_vars.port = port;
printf("Set UDP server port to %" PRIu16 "\n", port);
return 0;
}
else if (strcmp(argv[2], "list") == 0) {
udp_resource_desc_t* resource = openudp_vars.resources;
printf("Open UDP Ports: ");
while (NULL != resource) {
printf("%i ", resource->port);
resource = resource->next;
}
puts("");
}
else {
puts("error: invalid command");
return 1;
}
}
else {
puts("error: invalid command");
return 1;
}
return 1;
}
/** @} */