diff --git a/Makefile.dep b/Makefile.dep index 96202e7fd7e86c2b847d550bfe526c0b3154cc8b..178b3c9a52807e267dfd997215da7e2fa6fbe823 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -357,6 +357,29 @@ ifneq (,$(filter posix_semaphore,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter emb6_conn_udp,$(USEMODULE))) + USEMODULE += emb6_sock +endif + +ifneq (,$(filter emb6_%,$(USEMODULE))) + USEMODULE += emb6 +endif + +ifneq (,$(filter emb6,$(USEMODULE))) + USEPKG += emb6 + USEMODULE += emb6_bsp + USEMODULE += emb6_common + USEMODULE += emb6_contrib + USEMODULE += emb6_ipv6 + USEMODULE += emb6_ipv6_multicast + USEMODULE += emb6_llsec + USEMODULE += emb6_mac + USEMODULE += emb6_netdev2 + USEMODULE += emb6_rpl + USEMODULE += emb6_sicslowpan + USEMODULE += emb6_utils +endif + ifneq (,$(filter lwip_sixlowpan,$(USEMODULE))) USEMODULE += lwip_ipv6_autoconfig endif @@ -411,6 +434,25 @@ ifneq (,$(filter lwip_contrib,$(USEMODULE))) USEMODULE += sema endif +ifneq (,$(filter emb6_%,$(USEMODULE))) + USEMODULE += emb6 +endif + +ifneq (,$(filter emb6,$(USEMODULE))) + USEPKG += emb6 + USEMODULE += emb6_bsp + USEMODULE += emb6_common + USEMODULE += emb6_contrib + USEMODULE += emb6_ipv6 + USEMODULE += emb6_ipv6_multicast + USEMODULE += emb6_llsec + USEMODULE += emb6_mac + USEMODULE += emb6_netdev2 + USEMODULE += emb6_rpl + USEMODULE += emb6_sicslowpan + USEMODULE += emb6_utils +endif + ifneq (,$(filter sema,$(USEMODULE))) USEMODULE += xtimer endif diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules index 8886d73da234f2b7d5c2af77af4681d8f7879e48..1a45bacc107a8157bf3e9a6590639ac81ab99b0f 100644 --- a/Makefile.pseudomodules +++ b/Makefile.pseudomodules @@ -4,6 +4,7 @@ PSEUDOMODULES += conn_tcp PSEUDOMODULES += conn_udp PSEUDOMODULES += core_msg PSEUDOMODULES += core_thread_flags +PSEUDOMODULES += emb6_router PSEUDOMODULES += gnrc_netdev_default PSEUDOMODULES += gnrc_ipv6_default PSEUDOMODULES += gnrc_ipv6_router diff --git a/pkg/emb6/Makefile b/pkg/emb6/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..40d3bfaf07eb5957707c1ad51a82bcf68cbfd0fe --- /dev/null +++ b/pkg/emb6/Makefile @@ -0,0 +1,11 @@ +PKG_NAME=emb6 +PKG_URL=https://github.com/hso-esk/emb6.git +PKG_VERSION=14e4a3cfff01644e078870e14e16a1fe60dcc895 +PKG_BUILDDIR ?= $(BINDIRBASE)/pkg/$(BOARD)/$(PKG_NAME) + +.PHONY: all + +all: git-download + "$(MAKE)" -C $(PKG_BUILDDIR) + +include $(RIOTBASE)/pkg/pkg.mk diff --git a/pkg/emb6/Makefile.include b/pkg/emb6/Makefile.include new file mode 100644 index 0000000000000000000000000000000000000000..090cebac9c0a716af82dfd90b684e2629bef15af --- /dev/null +++ b/pkg/emb6/Makefile.include @@ -0,0 +1,71 @@ +PKG_BUILDDIR ?= $(BINDIRBASE)/pkg/$(BOARD)/emb6 +EMB6_DIR := $(PKG_BUILDDIR) +EMB6_CONTRIB := $(RIOTBASE)/pkg/emb6/contrib + +INCLUDES += -I$(PKG_BUILDDIR)/target +INCLUDES += -I$(RIOTBASE)/pkg/emb6/include + +ifeq (,$(filter emb6_router,$(USEMODULE))) + CFLAGS += -DEMB6_CONF_ROUTER=FALSE +endif + +ifneq (,$(filter emb6_bsp,$(USEMODULE))) + DIRS += $(EMB6_DIR)/target/bsp +endif + +ifneq (,$(filter emb6_common,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6 + INCLUDES += -I$(EMB6_DIR)/emb6 +endif + +ifneq (,$(filter emb6_contrib,$(USEMODULE))) + DIRS += $(EMB6_CONTRIB) +endif + +ifneq (,$(filter emb6_conn_udp,$(USEMODULE))) + DIRS += $(EMB6_CONTRIB)/conn/udp +endif + +ifneq (,$(filter emb6_ipv6,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6/src/net/ipv6 + INCLUDES += -I$(EMB6_DIR)/emb6/inc/net/ipv6 +endif + +ifneq (,$(filter emb6_ipv6_multicast,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6/src/net/ipv6/multicast + INCLUDES += -I$(EMB6_DIR)/emb6/inc/net/ipv6/multicast +endif + +ifneq (,$(filter emb6_llsec,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6/src/mac/llsec + INCLUDES += -I$(EMB6_DIR)/emb6/inc/mac/llsec +endif + +ifneq (,$(filter emb6_mac,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6/src/mac + INCLUDES += -I$(EMB6_DIR)/emb6/inc/mac +endif + +ifneq (,$(filter emb6_netdev2,$(USEMODULE))) + DIRS += $(EMB6_CONTRIB)/netdev2 +endif + +ifneq (,$(filter emb6_rpl,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6/src/net/rpl + INCLUDES += -I$(EMB6_DIR)/emb6/inc/net/rpl +endif + +ifneq (,$(filter emb6_sicslowpan,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6/src/net/sicslowpan + INCLUDES += -I$(EMB6_DIR)/emb6/inc/net/sicslowpan +endif + +ifneq (,$(filter emb6_sock,$(USEMODULE))) + DIRS += $(EMB6_DIR)/emb6/src/tport + INCLUDES += -I$(EMB6_DIR)/emb6/inc/tport +endif + +ifneq (,$(filter emb6_utils,$(USEMODULE))) + DIRS += $(EMB6_DIR)/utils/src + INCLUDES += -I$(EMB6_DIR)/utils/inc +endif diff --git a/pkg/emb6/contrib/Makefile b/pkg/emb6/contrib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..600b0c807bb1c68b3910ffdad113e45d2cc77c28 --- /dev/null +++ b/pkg/emb6/contrib/Makefile @@ -0,0 +1,3 @@ +MODULE = emb6_contrib + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/emb6/contrib/board_conf.c b/pkg/emb6/contrib/board_conf.c new file mode 100644 index 0000000000000000000000000000000000000000..1ba6463a688bb854119a8d39dcfe3abfde589395 --- /dev/null +++ b/pkg/emb6/contrib/board_conf.c @@ -0,0 +1,37 @@ +/* + * 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 <mlenders@inf.fu-berlin.de> + */ + +#include "emb6/netdev2.h" + +#include "etimer.h" +#include "board_conf.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +uint8_t board_conf(s_ns_t *ps_nStack) +{ + if (ps_nStack != NULL) { + ps_nStack->inif = &emb6_netdev2_driver; + etimer_init(); + return ps_nStack->inif->init(ps_nStack); + } + else { + DEBUG("Network stack pointer is NULL"); + return 0; + } +} + +/** @} */ diff --git a/pkg/emb6/contrib/conn/udp/Makefile b/pkg/emb6/contrib/conn/udp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e5dbafaedd9b426abbbf7df36189fb6c0895d9fe --- /dev/null +++ b/pkg/emb6/contrib/conn/udp/Makefile @@ -0,0 +1,3 @@ +MODULE = emb6_conn_udp + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/emb6/contrib/conn/udp/emb6_conn_udp.c b/pkg/emb6/contrib/conn/udp/emb6_conn_udp.c new file mode 100644 index 0000000000000000000000000000000000000000..bbd488edfe3f9ddb346037d8e52189883cac6eab --- /dev/null +++ b/pkg/emb6/contrib/conn/udp/emb6_conn_udp.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2016 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 <mlenders@inf.fu-berlin.de> + */ + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> + +#include "evproc.h" +#include "msg.h" +#include "mutex.h" +#include "net/af.h" +#include "net/conn/udp.h" +#include "net/ipv6/hdr.h" +#include "sched.h" +#include "uip.h" + +#define _MSG_TYPE_CLOSE (0x4123) +#define _MSG_TYPE_RCV (0x4124) + +/* struct to describe a sendto command for emb6 thread */ +typedef struct { + struct udp_socket sock; + mutex_t mutex; + const void *data; + int res; + uint16_t data_len; +} _send_cmd_t; + +extern uint16_t uip_slen; + +static bool send_registered = false; + +static void _input_callback(struct udp_socket *c, void *ptr, + const uip_ipaddr_t *src_addr, uint16_t src_port, + const uip_ipaddr_t *dst_addr, uint16_t dst_port, + const uint8_t *data, uint16_t datalen); +static void _output_callback(c_event_t c_event, p_data_t p_data); + +static int _reg_and_bind(struct udp_socket *c, void *ptr, + udp_socket_input_callback_t cb, uint16_t port) +{ + if (udp_socket_register(c, ptr, cb) < 0) { + return -EMFILE; + } + if (udp_socket_bind(c, port) < 0) { + udp_socket_close(c); + return -EALREADY; + } + return 0; +} + +int conn_udp_create(conn_udp_t *conn, const void *addr, size_t addr_len, + int family, uint16_t port) +{ + int res; + + (void)addr; + (void)addr_len; + if (family != AF_INET6) { + return -EAFNOSUPPORT; + } + if (conn->sock.input_callback != NULL) { + return -EINVAL; + } + mutex_init(&conn->mutex); + mutex_lock(&conn->mutex); + if ((res = _reg_and_bind(&conn->sock, conn, _input_callback, port)) < 0) { + conn->sock.input_callback = NULL; + mutex_unlock(&conn->mutex); + return res; + } + conn->waiting_thread = KERNEL_PID_UNDEF; + mutex_unlock(&conn->mutex); + return 0; +} + +void conn_udp_close(conn_udp_t *conn) +{ + if (conn->sock.input_callback != NULL) { + mutex_lock(&conn->mutex); + if (conn->waiting_thread != KERNEL_PID_UNDEF) { + msg_t msg; + msg.type = _MSG_TYPE_CLOSE; + msg.content.ptr = (char *)conn; + mutex_unlock(&conn->mutex); + msg_send(&msg, conn->waiting_thread); + mutex_lock(&conn->mutex); + } + udp_socket_close(&conn->sock); + conn->sock.input_callback = NULL; + mutex_unlock(&conn->mutex); + } +} + +int conn_udp_getlocaladdr(conn_udp_t *conn, void *addr, uint16_t *port) +{ + if (conn->sock.input_callback != NULL) { + mutex_lock(&conn->mutex); + memset(addr, 0, sizeof(ipv6_addr_t)); + *port = NTOHS(conn->sock.udp_conn->lport); + mutex_unlock(&conn->mutex); + return sizeof(ipv6_addr_t); + } + return -EBADF; +} + +int conn_udp_recvfrom(conn_udp_t *conn, void *data, size_t max_len, void *addr, + size_t *addr_len, uint16_t *port) +{ + int res = -EIO; + msg_t msg; + + if (conn->sock.input_callback == NULL) { + return -ENOTSOCK; + } + mutex_lock(&conn->mutex); + if (conn->waiting_thread != KERNEL_PID_UNDEF) { + mutex_unlock(&conn->mutex); + return -EALREADY; + } + conn->waiting_thread = sched_active_pid; + mutex_unlock(&conn->mutex); + msg_receive(&msg); + if (msg.type == _MSG_TYPE_CLOSE) { + conn->waiting_thread = KERNEL_PID_UNDEF; + return -EINTR; + } + else if (msg.type == _MSG_TYPE_RCV) { + mutex_lock(&conn->mutex); + if (msg.content.ptr == (char *)conn) { + if (max_len < conn->recv_info.datalen) { + conn->waiting_thread = KERNEL_PID_UNDEF; + mutex_unlock(&conn->mutex); + return -ENOBUFS; + } + memcpy(data, conn->recv_info.data, conn->recv_info.datalen); + memcpy(addr, conn->recv_info.src, sizeof(ipv6_addr_t)); + *addr_len = sizeof(ipv6_addr_t); + *port = conn->recv_info.src_port; + res = (int)conn->recv_info.datalen; + } + conn->waiting_thread = KERNEL_PID_UNDEF; + mutex_unlock(&conn->mutex); + } + return res; +} + +int conn_udp_sendto(const void *data, size_t len, const void *src, size_t src_len, + const void *dst, size_t dst_len, int family, uint16_t sport, + uint16_t dport) +{ + int res; + _send_cmd_t send_cmd; + + if (!send_registered) { + if (evproc_regCallback(EVENT_TYPE_CONN_SEND, _output_callback) != E_SUCCESS) { + return -EIO; + } + else { + send_registered = true; + } + } + mutex_init(&send_cmd.mutex); + if ((len > (UIP_BUFSIZE - (UIP_LLH_LEN + UIP_IPUDPH_LEN))) || + (len > UINT16_MAX)) { + return -EMSGSIZE; + } + if ((dst_len > sizeof(ipv6_addr_t)) || (family != AF_INET6)) { + return -EAFNOSUPPORT; + } + mutex_lock(&send_cmd.mutex); + send_cmd.data = data; + send_cmd.data_len = (uint16_t)len; + if ((res = _reg_and_bind(&send_cmd.sock, NULL, NULL, sport)) < 0) { + mutex_unlock(&send_cmd.mutex); + return res; + } + udp_socket_connect(&send_cmd.sock, (uip_ipaddr_t *)dst, dport); /* can't fail at this point */ + /* change to emb6 thread context */ + if (evproc_putEvent(E_EVPROC_TAIL, EVENT_TYPE_CONN_SEND, &send_cmd) != E_SUCCESS) { + udp_socket_close(&send_cmd.sock); + mutex_unlock(&send_cmd.mutex); + return -EIO; + } + /* block thread until data was send */ + mutex_lock(&send_cmd.mutex); + udp_socket_close(&send_cmd.sock); + mutex_unlock(&send_cmd.mutex); + + return send_cmd.res; +} + +static void _input_callback(struct udp_socket *c, void *ptr, + const uip_ipaddr_t *src_addr, uint16_t src_port, + const uip_ipaddr_t *dst_addr, uint16_t dst_port, + const uint8_t *data, uint16_t datalen) +{ + conn_udp_t *conn = ptr; + + (void)dst_addr; + (void)dst_port; + mutex_lock(&conn->mutex); + if (conn->waiting_thread != KERNEL_PID_UNDEF) { + msg_t msg; + conn->recv_info.src_port = src_port; + conn->recv_info.src = (const ipv6_addr_t *)src_addr; + conn->recv_info.data = data; + conn->recv_info.datalen = datalen - sizeof(ipv6_hdr_t); + msg.type = _MSG_TYPE_RCV; + msg.content.ptr = (char *)conn; + mutex_unlock(&conn->mutex); + msg_send(&msg, conn->waiting_thread); + } + else { + mutex_unlock(&conn->mutex); + } +} + +static void _output_callback(c_event_t c_event, p_data_t p_data) +{ + _send_cmd_t *send_cmd = (_send_cmd_t *)p_data; + + if ((c_event != EVENT_TYPE_CONN_SEND) || (p_data == NULL)) { + return; + } + if ((send_cmd->res = udp_socket_send(&send_cmd->sock, send_cmd->data, send_cmd->data_len)) < 0) { + send_cmd->res = -EHOSTUNREACH; + } + mutex_unlock(&send_cmd->mutex); +} + +/** @} */ diff --git a/pkg/emb6/contrib/netdev2/Makefile b/pkg/emb6/contrib/netdev2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bdc2e75de0764773d0f519ff415e212db5c40e89 --- /dev/null +++ b/pkg/emb6/contrib/netdev2/Makefile @@ -0,0 +1,3 @@ +MODULE = emb6_netdev2 + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/emb6/contrib/netdev2/emb6_netdev2.c b/pkg/emb6/contrib/netdev2/emb6_netdev2.c new file mode 100644 index 0000000000000000000000000000000000000000..039db6f7627b88806e7390cd75909919ab528f45 --- /dev/null +++ b/pkg/emb6/contrib/netdev2/emb6_netdev2.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2016 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 <mlenders@inf.fu-berlin.de> + */ + +#include <assert.h> +#include <stdint.h> +#include <sys/uio.h> + +#include "msg.h" +#include "net/netdev2.h" + +#include "evproc.h" +#include "emb6.h" +#include "linkaddr.h" +#include "packetbuf.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +extern uip_lladdr_t uip_lladdr; + +static netdev2_t *_dev = NULL; +static s_nsLowMac_t *_lowmac = NULL; +static int8_t _rssi_base_value = -100; +static uint8_t _last_rssi; + +static int8_t _netdev2_init(s_ns_t *p_ns); +static int8_t _netdev2_send(const void *pr_payload, uint8_t c_len); +static int8_t _netdev2_on(void); +static int8_t _netdev2_off(void); +static void _netdev2_set_txpower(int8_t power); +static int8_t _netdev2_get_txpower(void); +static void _netdev2_set_sensitivity(int8_t sens); +static int8_t _netdev2_get_sensitivity(void); +static int8_t _netdev2_get_rssi(void); +static void _netdev2_set_promisc(uint8_t c_on_off); + +const s_nsIf_t emb6_netdev2_driver = { + .name = "netdev2", + .init = &_netdev2_init, + .send = &_netdev2_send, + .on = &_netdev2_on, + .off = &_netdev2_off, + .set_txpower = &_netdev2_set_txpower, + .get_txpower = &_netdev2_get_txpower, + .set_sensitivity = &_netdev2_set_sensitivity, + .get_sensitivity = &_netdev2_get_sensitivity, + .get_rssi = &_netdev2_get_rssi, + .ant_div = NULL, + .ant_rf_switch = NULL, + .set_promisc = &_netdev2_set_promisc, +}; + +static void _get_recv_pkt(void) +{ + char *dataptr; + struct netdev2_radio_rx_info rx_info; + int8_t len; + + packetbuf_clear(); + + dataptr = packetbuf_dataptr(); + len = _dev->driver->recv(_dev, dataptr, PACKETBUF_SIZE, &rx_info); + _last_rssi = rx_info.rssi; + + if ((len > 0) && (_lowmac != NULL)) { + packetbuf_set_datalen(len); + _lowmac->input(); + } +} + +static void _event_cb(netdev2_t *dev, netdev2_event_t event, void *arg) +{ + (void)arg; + if (event == NETDEV2_EVENT_ISR) { + /* EVENT_TYPE_PCK_LL is supposed to be used by drivers, so use it + * (though NETDEV2_EVENT_ISR technically doesn't only signify + * incoming packets) */ + evproc_putEvent(E_EVPROC_HEAD, EVENT_TYPE_PCK_LL, NULL); + } + else { + switch (event) { + case NETDEV2_EVENT_RX_COMPLETE: { + _get_recv_pkt(); + } + break; + default: + break; + } + } +} + +static void _emb6_netdev2_callback(c_event_t c_event, p_data_t p_data) +{ + (void)p_data; + if (c_event == EVENT_TYPE_PCK_LL) { + _dev->driver->isr(_dev); + } +} + +int emb6_netdev2_setup(netdev2_t *dev) +{ + if (_dev == NULL) { + _dev = dev; + return 0; + } + return -1; +} + +static int8_t _netdev2_init(s_ns_t *p_ns) +{ + if ((_dev != NULL) && (p_ns != NULL) && (p_ns->lmac != NULL)) { + _dev->event_callback = _event_cb; + _dev->driver->get(_dev, NETOPT_ADDRESS_LONG, &mac_phy_config.mac_address, + sizeof(mac_phy_config.mac_address)); + memcpy(&uip_lladdr, mac_phy_config.mac_address, + sizeof(mac_phy_config.mac_address)); + _dev->driver->get(_dev, NETOPT_NID, &mac_phy_config.pan_id, + sizeof(mac_phy_config.pan_id)); + linkaddr_set_node_addr((linkaddr_t *)&uip_lladdr); + _lowmac = p_ns->lmac; + evproc_regCallback(EVENT_TYPE_PCK_LL, _emb6_netdev2_callback); + return 1; + } + return 0; +} + +static int8_t _netdev2_send(const void *pr_payload, uint8_t c_len) +{ + if (_dev != NULL) { + const struct iovec vector = { + .iov_base = (void *)pr_payload, + .iov_len = c_len + }; + if (_dev->driver->send(_dev, &vector, 1) < 0) { + DEBUG("Error on send\n"); + return RADIO_TX_ERR; + } + DEBUG("Packet of length %u was transmitted\n", (unsigned)c_len); + return RADIO_TX_OK; + } + DEBUG("Device was not initialized\n"); + return RADIO_TX_ERR; +} + +static int8_t _netdev2_on(void) +{ + /* TODO: turn netdev2 on */ + return 1; +} + +static int8_t _netdev2_off(void) +{ + /* TODO: turn netdev2 off */ + return 1; +} + +static void _netdev2_set_txpower(int8_t power) +{ + int16_t pwr = power; + + _dev->driver->set(_dev, NETOPT_TX_POWER, &pwr, sizeof(pwr)); +} + +static int8_t _netdev2_get_txpower(void) +{ + int16_t power = 0; + + _dev->driver->get(_dev, NETOPT_TX_POWER, &power, sizeof(power)); + return (int8_t)power; +} + +static void _netdev2_set_sensitivity(int8_t sens) +{ + /* TODO: set sensitivity */ +} + +static int8_t _netdev2_get_sensitivity(void) +{ + /* TODO: get sensitivity */ + return 0; +} + +static int8_t _netdev2_get_rssi(void) +{ + return (int8_t)(_rssi_base_value + 1.03 * _last_rssi); +} + +static void _netdev2_set_promisc(uint8_t c_on_off) +{ + netopt_enable_t en = (c_on_off) ? NETOPT_ENABLE : NETOPT_DISABLE; + + _dev->driver->set(_dev, NETOPT_PROMISCUOUSMODE, &en, sizeof(en)); +} + +/** @} */ diff --git a/pkg/emb6/contrib/target.c b/pkg/emb6/contrib/target.c new file mode 100644 index 0000000000000000000000000000000000000000..ac256b4d670fa95672f9673b09d221ad4e3d778d --- /dev/null +++ b/pkg/emb6/contrib/target.c @@ -0,0 +1,213 @@ +/* + * 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 <mlenders@inf.fu-berlin.de> + */ + +#include <inttypes.h> + +#include "cpu.h" +#include "led.h" +#include "mutex.h" +#include "periph/gpio.h" +#include "periph/hwrng.h" +#include "xtimer.h" + +#include "target.h" +#include "bsp.h" + +static mutex_t critical_mutex = MUTEX_INIT; + +void hal_enterCritical(void) +{ + mutex_lock(&critical_mutex); +} + +void hal_exitCritical(void) +{ + mutex_unlock(&critical_mutex); +} + +int8_t hal_init(void) +{ + /* Should have happened long before emb6 started, so nothing to do */ + return 1; +} + +uint8_t hal_getrand(void) +{ +#if RANDOM_NUMOF + uint8_t res; + hwnrg_read((char *)&res, sizeof(res)); + return res; +#elif defined(MODULE_RANDOM) + return (uint8_t)(genrand_uint32() % UINT8_MAX); +#else + return 4; /* keeping the meme alive ;-) */ +#endif +} + +void hal_ledOn(uint16_t ui_led) +{ + switch (ui_led) { + case E_BSP_LED_RED: + LED0_ON; + break; + case E_BSP_LED_YELLOW: + LED1_ON; + break; + case E_BSP_LED_GREEN: + LED2_ON; + break; + default: + break; + } +} + +void hal_ledOff(uint16_t ui_led) +{ + switch (ui_led) { + case E_BSP_LED_RED: + LED0_OFF; + break; + case E_BSP_LED_YELLOW: + LED1_OFF; + break; + case E_BSP_LED_GREEN: + LED2_OFF; + break; + default: + break; + } +} + +uint8_t hal_extIntInit(en_targetExtInt_t e_extInt, pfn_intCallb_t pfn_intCallback) +{ + /* RIOT does this in netdev2 initialization so nothing to do here. */ + return 0; +} + +void hal_delay_us(uint32_t i_delay) +{ + xtimer_usleep(i_delay); +} + +uint8_t hal_gpioPinInit(uint8_t c_pin, uint8_t c_dir, uint8_t c_initState) +{ + /* Only used in board init code => not needed */ + (void)c_pin; + (void)c_dir; + (void)c_initState; + return 0; +} + +void *hal_ctrlPinInit(en_targetExtPin_t e_pinType) +{ + (void)e_pinType; + return NULL; +} + +void hal_pinSet(void *p_pin) +{ + /* Only used in board/driver-related code code => not needed */ +} + +void hal_pinClr(void *p_pin) +{ + /* Only used in board/driver-related code code => not needed */ +} + +uint8_t hal_pinGet(void *p_pin) +{ + /* Only used in board/driver-related code code => not needed */ + return 0; +} + +void *hal_spiInit(void) +{ + /* Only used in board/driver-related code code => not needed */ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/** \brief This function selects slave with which we will work + * \param p_spi Pointer to spi description entity + * \param action true or false + * + * \return 0 if failed, 1 id ok + */ +/*---------------------------------------------------------------------------*/ +uint8_t hal_spiSlaveSel(void *p_spi, bool action) +{ + /* Only used in board/driver-related code code => not needed */ + return 0; +} + +uint8_t hal_spiTransceive( uint8_t *txData, uint8_t *p_reg) +{ + /* Only used in board/driver-related code code => not needed */ + return 0; +} + +uint8_t hal_spiRead(uint8_t *p_reg, uint16_t i_length) +{ + /* Only used in board/driver-related code code => not needed */ + return 0; +} + + +/*----------------------------------------------------------------------------*/ +/** \brief This function writes a new value via given SPI interface + * registers. + * + * + * \param value Pointer to a value. + * \param i_length Length of a data to be received + */ +/*----------------------------------------------------------------------------*/ +void hal_spiWrite(uint8_t *value, uint16_t i_length) +{ + /* Only used in board/driver-related code code => not needed */ +} + +void hal_watchdogReset(void) +{ + /* WDT and tick-less scheduling don't make much sense */ +} + +void hal_watchdogStart(void) +{ + /* WDT and tick-less scheduling don't make much sense */ +} + +void hal_watchdogStop(void) +{ + /* WDT and tick-less scheduling don't make much sense */ +} + +clock_time_t hal_getTick(void) +{ + return (clock_time_t)xtimer_now(); +} + +clock_time_t hal_getSec(void) +{ + return (clock_time_t)xtimer_now() / SEC_IN_USEC; +} + + +clock_time_t hal_getTRes(void) +{ + return SEC_IN_USEC; +} + +/** @} */ diff --git a/pkg/emb6/doc.txt b/pkg/emb6/doc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8afb9ee9db05debcf5081a1b51223710b5a300f7 --- /dev/null +++ b/pkg/emb6/doc.txt @@ -0,0 +1,9 @@ +/** + * @defgroup pkg_emb6 emb6 network stack + * @ingroup pkg + * @brief emb6 network stack + * @see https://github.com/hso-esk/emb6/raw/develop/doc/pdf/emb6.pdf + * + * emb6 is a fork of Contiki's uIP network stack without its usage of + * proto-threads. It uses periodic event polling instead. + */ diff --git a/pkg/emb6/include/board_conf.h b/pkg/emb6/include/board_conf.h new file mode 100644 index 0000000000000000000000000000000000000000..56c765618874e2714b9641de25a2c93bae1f0aaf --- /dev/null +++ b/pkg/emb6/include/board_conf.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 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. + */ + +/** + * @defgroup emb6 emb6 network stack + * @ingroup pkg + * @brief + * @{ + * + * @file + * @brief "Board" configuration for emb6 + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ + +#ifndef EMB6_BOARD_CONF_H_ +#define EMB6_BOARD_CONF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "emb6.h" + +/** + * @brief emb6 board configuration function + * + * @param[in] ps_nStack pointer to global netstack struct + * + * @return success 1 + * @return failure 0 + */ +uint8_t board_conf(s_ns_t *ps_nStack); + +#ifdef __cplusplus +} +#endif + +#endif /* EMB6_BOARD_CONF_H_ */ +/** @} */ +/** @} */ diff --git a/pkg/emb6/include/emb6/conn/udp.h b/pkg/emb6/include/emb6/conn/udp.h new file mode 100644 index 0000000000000000000000000000000000000000..dc835ca06bd0e7cd6e9467e4deca5628ec9c4962 --- /dev/null +++ b/pkg/emb6/include/emb6/conn/udp.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 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. + */ + +/** + * @defgroup emb6_conn_udp udp_conn wrapper for emb6 + * @ingroup emb6 + * @brief UDP conn for emb6 + * + * For this implementation to receive with an open connection only with one + * thread at once. If you use @ref conn_udp_recvfrom() with more than one thread + * simultaneously, it will return `-EALREADY`. + * + * @{ + * + * @file + * @brief UDP conn definitions + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef EMB6_CONN_UDP_H_ +#define EMB6_CONN_UDP_H_ + +#include <stdint.h> + +#include "kernel_types.h" +#include "mutex.h" +#include "net/ipv6/addr.h" + +#include "uip.h" +#include "udp-socket.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief @ref net_conn_udp definition for emb6 + */ +struct conn_udp { + struct udp_socket sock; /**< emb6 internal socket */ + mutex_t mutex; /**< mutex for the connection */ + kernel_pid_t waiting_thread; /**< thread waiting for an incoming packet + * on this connection */ + struct { + uint16_t src_port; /**< source port */ + const ipv6_addr_t *src; /**< source address */ + const void *data; /**< data of received packet */ + size_t datalen; /**< length of received packet data */ + } recv_info; /**< info on received packet */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EMB6_CONN_UDP_H_ */ +/** @} */ diff --git a/pkg/emb6/include/emb6/netdev2.h b/pkg/emb6/include/emb6/netdev2.h new file mode 100644 index 0000000000000000000000000000000000000000..3076603ffcd7b66fad4ac7734934649a06597798 --- /dev/null +++ b/pkg/emb6/include/emb6/netdev2.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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. + */ + +/** + * @defgroup pkgemb6_netdev2 netdev2 wrapper for emb6 + * @ingroup pkg_emb6 + * @brief + * @{ + * + * @file + * @brief + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef EMB6_NETDEV2_H_ +#define EMB6_NETDEV2_H_ + +#include "net/netdev2.h" + +#include "emb6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The emb6 network interface. + * + * @note emb6 only supports one network interface. + * + * This variable is used by @ref board_conf() to set the interface for the + * stack. + */ +extern const s_nsIf_t emb6_netdev2_driver; + +/** + * @brief Setup a network device as the emb6 interface. + * + * @param[in] dev The network device for the interface + * + * @return 0 on success. + * @return <= 0 on error. + */ +int emb6_netdev2_setup(netdev2_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* EMB6_NETDEV2_H_ */ +/** @} */ diff --git a/pkg/emb6/patches/0001-Add-RIOT-Makefiles.patch b/pkg/emb6/patches/0001-Add-RIOT-Makefiles.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f92930002684c0c5f05740b1d91469f09d9f540 Binary files /dev/null and b/pkg/emb6/patches/0001-Add-RIOT-Makefiles.patch differ diff --git a/pkg/emb6/patches/0002-Rename-colliding-files-and-functions.patch b/pkg/emb6/patches/0002-Rename-colliding-files-and-functions.patch new file mode 100644 index 0000000000000000000000000000000000000000..5dfcfd962655f49f0be870ff2dbce066f41ddb3a Binary files /dev/null and b/pkg/emb6/patches/0002-Rename-colliding-files-and-functions.patch differ diff --git a/pkg/emb6/patches/0003-Fix-warnings.patch b/pkg/emb6/patches/0003-Fix-warnings.patch new file mode 100644 index 0000000000000000000000000000000000000000..dfa59d43821b2bce8fb816fbc97422c39f9aeb0d Binary files /dev/null and b/pkg/emb6/patches/0003-Fix-warnings.patch differ diff --git a/pkg/emb6/patches/0004-Provide-event-type-for-RIOT-s-conn_.-_send.patch b/pkg/emb6/patches/0004-Provide-event-type-for-RIOT-s-conn_.-_send.patch new file mode 100644 index 0000000000000000000000000000000000000000..ba76384872852942319836a2fde16d572ccb1d9c Binary files /dev/null and b/pkg/emb6/patches/0004-Provide-event-type-for-RIOT-s-conn_.-_send.patch differ diff --git a/sys/include/net/conn/udp.h b/sys/include/net/conn/udp.h index 2e400a0cf7a269ed9997413d550d8913d327458f..b59ac07ce49d2066851641eeea1af06306611e13 100644 --- a/sys/include/net/conn/udp.h +++ b/sys/include/net/conn/udp.h @@ -31,6 +31,10 @@ #include "lwip/conn.h" #endif +#ifdef MODULE_EMB6_CONN_UDP +#include "emb6/conn/udp.h" +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/tests/emb6/Makefile b/tests/emb6/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..874ed139e15b2887adb468620bd8000828371a35 --- /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 0000000000000000000000000000000000000000..ec50688980a225f408b26a0cc6f22b804eb28752 --- /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 <mlenders@inf.fu-berlin.de> + */ + +#include <stdbool.h> + +#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 0000000000000000000000000000000000000000..0efd9e9afa1df0cece7f6e54d1460b04ab5efea8 --- /dev/null +++ b/tests/emb6/common.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * 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 <mlenders@inf.fu-berlin.de> + */ +#ifndef MAIN_H_ +#define MAIN_H_ + +#include <stdint.h> +#include <sys/types.h> + +#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 0000000000000000000000000000000000000000..0929b4ef465f28317a99483f23c4fe5e636d9b8b --- /dev/null +++ b/tests/emb6/main.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * 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 <mlenders@inf.fu-berlin.de> + * + * 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 <errno.h> +#include <stdio.h> + +#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 0000000000000000000000000000000000000000..73ffa5e4ce3ebda6db023aea02ab9f7fabbc6f2f --- /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 <mlenders@inf.fu-berlin.de> + * + * @} + */ + +#include <stdbool.h> +#include <inttypes.h> +#include <stdio.h> + +#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 <dst> [<num>] [<payload_len>]\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 0000000000000000000000000000000000000000..748110cc6eef71389d8f387fdc75283d10ec66e2 --- /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 <mlenders@inf.fu-berlin.de> + * + * @} + */ + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +#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 <addr> <port> <hex 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]); + } + 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 <port>\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 + +/** @} */