From 43f7f55ca06864b22ddd2e9181d9a42799175333 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 7 Feb 2016 19:52:31 +0100 Subject: [PATCH] tests: add emb6 test --- tests/emb6/Makefile | 38 ++++++++++ tests/emb6/common.c | 57 +++++++++++++++ tests/emb6/common.h | 79 +++++++++++++++++++++ tests/emb6/main.c | 109 ++++++++++++++++++++++++++++ tests/emb6/ping.c | 136 +++++++++++++++++++++++++++++++++++ tests/emb6/udp.c | 168 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 587 insertions(+) create mode 100644 tests/emb6/Makefile create mode 100644 tests/emb6/common.c create mode 100644 tests/emb6/common.h create mode 100644 tests/emb6/main.c create mode 100644 tests/emb6/ping.c create mode 100644 tests/emb6/udp.c diff --git a/tests/emb6/Makefile b/tests/emb6/Makefile new file mode 100644 index 000000000000..874ed139e15b --- /dev/null +++ b/tests/emb6/Makefile @@ -0,0 +1,38 @@ +APPLICATION = emb6 + +FEATURES_REQUIRED = periph_gpio periph_spi # for at86rf231 + +BOARD ?= samr21-xpro + +RIOTBASE ?= $(CURDIR)/../.. + +BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery weio z1 + +USEMODULE += emb6_router +USEMODULE += emb6_conn_udp +USEMODULE += ipv6_addr +USEMODULE += shell +USEMODULE += shell_commands +USEMODULE += ps +USEMODULE += od + +# define the driver to be used for selected boards +ifneq (,$(filter samr21-xpro,$(BOARD))) + DRIVER := at86rf233 +endif +ifneq (,$(filter iotlab-m3 fox,$(BOARD))) + DRIVER := at86rf231 +endif +ifneq (,$(filter mulle,$(BOARD))) + DRIVER := at86rf212b +endif + +# use the at86rf231 as fallback device +DRIVER ?= at86rf231 + +# include the selected driver +USEMODULE += $(DRIVER) + +QUIET ?= 1 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/emb6/common.c b/tests/emb6/common.c new file mode 100644 index 000000000000..ec50688980a2 --- /dev/null +++ b/tests/emb6/common.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 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. + */ + +/** + * @{ + * + * @file + * @author Martine Lenders + */ + +#include + +#include "common.h" + +size_t hex2ints(uint8_t *out, const char *in) +{ + bool upper = true; + size_t out_size = 0; + + while (*in != '\0') { + char c; + if ((*in >= '0') && (*in <= '9')) { + c = '0'; + } + else if ((*in >= 'a') && (*in <= 'f')) { + c = 'a' - 10; + } + else if ((*in >= 'A') && (*in <= 'F')) { + c = 'A' - 10; + } + else { + in++; + continue; + } + if (upper) { + *out = (char)(*in - c) << 4; + } + else { + *out |= (char)(*in - c); + out++; + out_size++; + } + upper = !upper; + in++; + } + if (!upper) { + out_size++; + } + return out_size; +} + +/** @} */ diff --git a/tests/emb6/common.h b/tests/emb6/common.h new file mode 100644 index 000000000000..0efd9e9afa1d --- /dev/null +++ b/tests/emb6/common.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 Martine Lenders + * + * 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 Definitions for tests/lwip/ + * + * @author Martine Lenders + */ +#ifndef MAIN_H_ +#define MAIN_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Application configuration + * @{ + */ +#define CONN_INBUF_SIZE (256) +#define SERVER_MSG_QUEUE_SIZE (8) +#define SERVER_BUFFER_SIZE (64) +/** + * @} + */ + +/** + * @brief Converts hex string to byte array. + * + * @param[out] out Resulting byte array + * @param[in] in `\0` terminated string. Non-hex characters (all except 0-9, a-f, A-F) + * will be ignored. + * + * @return Length of @p out. + */ +size_t hex2ints(uint8_t *out, const char *in); + +/** + * @brief Ping shell command + * + * @param[in] argc number of arguments + * @param[in] argv array of arguments + * + * @return 0 on success + * @return other on error + */ +int ping_cmd(int argc, char **argv); + +#ifdef MODULE_CONN_UDP +/** + * @brief UDP IP shell command + * + * @param[in] argc number of arguments + * @param[in] argv array of arguments + * + * @return 0 on success + * @return other on error + */ +int udp_cmd(int argc, char **argv); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MAIN_H_ */ +/** @} */ diff --git a/tests/emb6/main.c b/tests/emb6/main.c new file mode 100644 index 000000000000..0929b4ef465f --- /dev/null +++ b/tests/emb6/main.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 Test for raw IPv6 connections + * + * @author Martine Lenders + * + * This test application tests the gnrc_conn_ip module. If you select protocol 58 you can also + * test if gnrc is able to deal with multiple subscribers to ICMPv6 (gnrc_icmpv6 and this + * application). + * + * @} + */ + +#include +#include + +#include "at86rf2xx.h" +#include "at86rf2xx_params.h" +#include "common.h" +#include "emb6.h" +#include "emb6/netdev2.h" +#include "uip-ds6.h" +#include "net/ipv6/addr.h" +#include "shell.h" +#include "thread.h" +#include "xtimer.h" + +#define EMB6_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define EMB6_PRIO (THREAD_PRIORITY_MAIN - 3) +#define EMB6_DELAY (500) + +static at86rf2xx_t at86rf2xx; +static s_ns_t emb6 = { + .hc = &sicslowpan_driver, + .llsec = &nullsec_driver, + .hmac = &nullmac_driver, + .lmac = &sicslowmac_driver, + .frame = &framer_802154, + .c_configured = 1, +}; +static char emb6_stack[EMB6_STACKSIZE]; + +static int ifconfig(int argc, char **argv) +{ + (void)argc; + (void)argv; + char addrstr[IPV6_ADDR_MAX_STR_LEN]; + printf("0: "); + for (int i = 0; i < UIP_DS6_ADDR_NB; i++) { + if (uip_ds6_if.addr_list[i].isused) { + printf("inet6 %s\n", + ipv6_addr_to_str(addrstr, + (ipv6_addr_t *)&uip_ds6_if.addr_list[i].ipaddr, + sizeof(addrstr))); + if (i != 0) { + printf(" "); + } + } + } + puts(""); + return 0; +} + +static void *_emb6_thread(void *args) +{ + emb6_process(500); /* never stops */ + return NULL; +} + +static const shell_command_t shell_commands[] = { + { "ping6", "Send pings and receive pongs", ping_cmd }, +#ifdef MODULE_CONN_UDP + { "udp", "Send UDP messages and listen for messages on UDP port", udp_cmd }, +#endif + { "ifconfig", "Shows assigned IPv6 addresses", ifconfig }, + { NULL, NULL, NULL } +}; +static char line_buf[SHELL_DEFAULT_BUFSIZE]; + +char conn_inbuf[CONN_INBUF_SIZE]; + +int main(void) +{ + netdev2_t *netdev = (netdev2_t *)&at86rf2xx; + + puts("RIOT lwip test application"); + + at86rf2xx_setup(&at86rf2xx, at86rf2xx_params); + netdev->driver->init((netdev2_t *)&at86rf2xx); + emb6_netdev2_setup(netdev); + emb6_init(&emb6); + thread_create(emb6_stack, sizeof(emb6_stack), EMB6_PRIO, + THREAD_CREATE_STACKTEST, _emb6_thread, NULL, "emb6"); + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + /* should be never reached */ + return 0; +} diff --git a/tests/emb6/ping.c b/tests/emb6/ping.c new file mode 100644 index 000000000000..73ffa5e4ce3e --- /dev/null +++ b/tests/emb6/ping.c @@ -0,0 +1,136 @@ +/* + * 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 over POSIX sockets. + * + * @author Martine Lenders + * + * @} + */ + +#include +#include +#include + +#include "atomic.h" +#include "byteorder.h" +#include "net/icmpv6.h" +#include "net/ipv6.h" +#include "xtimer.h" + +#include "uip.h" +#include "uip-icmp6.h" + +#include "common.h" + +#define ECHO_ID (0xd1e9) + +static struct uip_icmp6_echo_reply_notification recv_ntfy = { NULL, NULL }; +static uint16_t seq = 0; +static atomic_int_t received, num; + +static bool _waiting = true; + +static inline icmpv6_echo_t *uip_icmp_buf(void) +{ + return ((icmpv6_echo_t *)&uip_buf[uip_l2_l3_hdr_len]); +} + +static inline int max_len(void) +{ + return UIP_BUFSIZE - (((uint8_t *)uip_icmp_buf()) - uip_buf) - + sizeof(icmpv6_echo_t); +} + +static int ping_send(const uip_ipaddr_t *dst, int payload_len) +{ + int len = payload_len; + icmpv6_echo_t *ping = uip_icmp_buf(); + + ping->id = byteorder_htons(ECHO_ID); + + if (payload_len > max_len()) { + puts("Payload too long for buffer."); + return -1; + } + + for (network_uint16_t *payload = (network_uint16_t *)(ping + 1); + len >= 0; + payload++, len -= 2) { + *payload = byteorder_htons(seq); + } + + ping->seq = byteorder_htons(seq++); + + uip_icmp6_send((const uip_ipaddr_t *)dst, ICMPV6_ECHO_REQ, 0, + payload_len + (sizeof(icmpv6_echo_t) - sizeof(icmpv6_hdr_t))); + + return 0; +} + +static void handle_reply(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data, + uint16_t datalen) +{ + char addr_str[IPV6_ADDR_MAX_STR_LEN]; + icmpv6_echo_t *ping = (icmpv6_echo_t *)data; + + _waiting = false; + + ipv6_addr_to_str(addr_str, (ipv6_addr_t *)source, sizeof(addr_str)); + + atomic_inc(&received); + printf("%" PRIu16 " bytes from %s: icmp_seq=%" PRIu16 " ttl=%u quota=%i/%i\n", + datalen, addr_str, byteorder_ntohs(ping->seq), (unsigned)ttl, + ATOMIC_VALUE(received), ATOMIC_VALUE(num)); +} + +void usage(char *cmd) +{ + printf("usage: %s [] []\n", cmd); +} + +int ping_cmd(int argc, char **argv) +{ + ipv6_addr_t dst; + int payload_len, _num; + + if ((argc < 2) || (ipv6_addr_from_str(&dst, argv[1]) == NULL)) { + usage(argv[0]); + return 1; + } + if ((argc < 3) || ((_num = atoi(argv[2])) == 0)) { + _num = 3; + } + if ((argc < 4) || ((payload_len = atoi(argv[3])) == 0)) { + payload_len = 16; + } + atomic_set_to_zero(&num); + atomic_cas(&num, 0, _num); + atomic_set_to_zero(&received); + seq = 0; + if (recv_ntfy.callback == NULL) { + uip_icmp6_echo_reply_callback_add(&recv_ntfy, handle_reply); + } + for (uint16_t i = 0; i < _num; i++) { + _waiting = true; + ping_send((uip_ipaddr_t *)&dst, payload_len); + xtimer_usleep(1000000); + if (_waiting) { + puts("Timeout"); + } + } + + return 0; +} + +/** @} */ diff --git a/tests/emb6/udp.c b/tests/emb6/udp.c new file mode 100644 index 000000000000..748110cc6eef --- /dev/null +++ b/tests/emb6/udp.c @@ -0,0 +1,168 @@ +/* + * 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 over POSIX sockets. + * + * @author Martine Lenders + * + * @} + */ + +#include +#include +#include + +#include "common.h" +#include "od.h" +#include "net/af.h" +#include "net/conn/udp.h" +#include "net/ipv6.h" +#include "thread.h" +#include "xtimer.h" + +#ifdef MODULE_CONN_UDP +static char conn_inbuf[CONN_INBUF_SIZE]; +static bool server_running; +static conn_udp_t server_conn; +static char server_stack[THREAD_STACKSIZE_DEFAULT]; +static msg_t server_msg_queue[SERVER_MSG_QUEUE_SIZE]; + +static void *_server_thread(void *args) +{ + ipv6_addr_t server_addr = IPV6_ADDR_UNSPECIFIED; + uint16_t port; + int res; + + msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE); + /* parse port */ + port = (uint16_t)atoi((char *)args); + if ((res = conn_udp_create(&server_conn, &server_addr, + sizeof(server_addr), AF_INET6, port)) < 0) { + printf("Unable to open UDP server on port %" PRIu16 " (error code %d)\n", + port, -res); + return NULL; + } + server_running = true; + printf("Success: started UDP server on port %" PRIu16 "\n", port); + while (1) { + int res; + ipv6_addr_t src; + size_t src_len = sizeof(ipv6_addr_t); + uint16_t sport; + if ((res = conn_udp_recvfrom(&server_conn, conn_inbuf, sizeof(conn_inbuf), &src, + &src_len, &sport)) < 0) { + puts("Error on receive"); + } + else if (res == 0) { + puts("No data received"); + } + else { + char addrstr[IPV6_ADDR_MAX_STR_LEN]; + printf("Received from [%s]:%" PRIu16 ":\n", ipv6_addr_to_str(addrstr, &src, + sizeof(addrstr)), sport); + od_hex_dump(conn_inbuf, res, 0); + } + } + return NULL; +} + +static int udp_send(char *addr_str, char *port_str, char *data, unsigned int num, + unsigned int delay) +{ + ipv6_addr_t src = IPV6_ADDR_UNSPECIFIED, dst; + uint16_t port; + uint8_t byte_data[strlen(data) / 2]; + size_t data_len; + + /* parse destination address */ + if (ipv6_addr_from_str(&dst, addr_str) == NULL) { + puts("Error: unable to parse destination address"); + return 1; + } + /* parse port */ + port = (uint16_t)atoi(port_str); + data_len = hex2ints(byte_data, data); + for (unsigned int i = 0; i < num; i++) { + if (conn_udp_sendto(byte_data, data_len, &src, sizeof(src), (struct sockaddr *)&dst, + sizeof(dst), AF_INET6, port, port) < 0) { + puts("could not send"); + } + else { + printf("Success: send %u byte to [%s]:%" PRIu16 ")\n", + (unsigned)data_len, addr_str, port); + } + xtimer_usleep(delay); + } + return 0; +} + +static int udp_start_server(char *port_str) +{ + if (thread_create(server_stack, sizeof(server_stack), THREAD_PRIORITY_MAIN - 1, + THREAD_CREATE_STACKTEST, _server_thread, port_str, + "UDP server") <= KERNEL_PID_UNDEF) { + return 1; + } + 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 = 1000000; + if (argc < 5) { + printf("usage: %s send [ []]\n", + argv[0]); + return 1; + } + if (argc > 5) { + num = (uint32_t)atoi(argv[5]); + } + if (argc > 6) { + delay = (uint32_t)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|stop]\n", argv[0]); + return 1; + } + if (strcmp(argv[2], "start") == 0) { + if (argc < 4) { + printf("usage %s server start \n", argv[0]); + return 1; + } + return udp_start_server(argv[3]); + } + else { + puts("error: invalid command"); + return 1; + } + } + else { + puts("error: invalid command"); + return 1; + } +} +#else +typedef int dont_be_pedantic; +#endif + +/** @} */