From 97de8aa52b4626fd06b5354cfa200b84520fb251 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Tue, 16 Feb 2016 17:17:58 +0100 Subject: [PATCH 1/2] netdev2_test: initial import Imports a generic framework to test and experiment with netdev2-based modules. --- sys/Makefile | 3 + sys/include/net/netdev2_test.h | 306 ++++++++++++++++++++++++++++ sys/net/netdev2_test/Makefile | 1 + sys/net/netdev2_test/netdev2_test.c | 144 +++++++++++++ 4 files changed, 454 insertions(+) create mode 100644 sys/include/net/netdev2_test.h create mode 100644 sys/net/netdev2_test/Makefile create mode 100644 sys/net/netdev2_test/netdev2_test.c diff --git a/sys/Makefile b/sys/Makefile index 01986396d..9fce303df 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -22,6 +22,9 @@ endif ifneq (,$(filter ieee802154,$(USEMODULE))) DIRS += net/link_layer/ieee802154 endif +ifneq (,$(filter netdev2_test,$(USEMODULE))) + DIRS += net/netdev2_test +endif ifneq (,$(filter ipv4_addr,$(USEMODULE))) DIRS += net/network_layer/ipv4/addr endif diff --git a/sys/include/net/netdev2_test.h b/sys/include/net/netdev2_test.h new file mode 100644 index 000000000..8d4c448b4 --- /dev/null +++ b/sys/include/net/netdev2_test.h @@ -0,0 +1,306 @@ +/* + * 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 sys_netdev2_test Netdev2 dummy test driver + * @ingroup drivers_netdev_netdev2 + * @brief Provides a test dummy for the netdev2 interface. + * + * See the following simple packet traversal timer for an example. Note that + * this example assumes that the stack doesn't require any option values from + * the device and that the stack doesn't create packets on its own or looses + * packets (neither of those can be assumed for in-production stacks). + * + * ~~~~~~~~~~~ {.c} + * #include + * + * #include "mutex.h" + * #include "net/af.h" + * #include "net/conn/udp.h" + * #include "net/ipv6/addr.h" + * #include "net/netdev2_test.h" + * #include "xtimer.h" + * + * #define PKT_NUMBER (1000) + * + * static netdev2_test_t dev; + * static uint32_t last_start; + * static uint32_t sum = 0; + * static mutex_t wait = MUTEX_INIT; + * + * int _send_timer(netdev2_t *dev, const struct iovec *vector, int count) + * { + * (void)dev; + * (void)vector; + * (void)count; + * + * sum += (xtimer_now() - last_start); + * mutex_unlock(&wait); + * } + * + * int main(void) { + * ipv6_addr_t dst = IPV6_ADDR_UNSPECIFIED; + * + * netdev2_test_setup(&dev, NULL); + * dev->driver->init((netdev2_t *)&dev) + * // initialize stack and connect `dev` to it + * // ... + * mutex_lock(&wait); + * for (int i = 0; i < PKT_NUMBER; i++) { + * last_start = xtimer_now(); + * conn_udp_sendto("abcd", sizeof("abcd"), NULL, 0, &dst, sizeof(dst), + * AF_INET6, 0xcafe, 0xcafe); + * mutex_lock(&wait); + * } + * printf("Average send packet traversal time: %u\n", sum / PKT_NUMBER); + * mutex_unlock(&wait); + * return 0; + * } + * ~~~~~~~~~~~ + * + * To provide options to the stack, the + * @ref netdev2_test_t::get_cbs "get callbacks" for the specific options need + * to be set. + * To catch lost packets and additional sent by the stack the send handler needs + * to be adapted accordingly. + * + * @{ + * + * @file + * @brief @ref sys_netdev2_test definitions + * + * @author Martine Lenders + */ +#ifndef NETDEV2_TEST_H_ +#define NETDEV2_TEST_H_ + +#include "mutex.h" + +#ifdef MODULE_NETDEV2_IEEE802154 +#include "net/netdev2/ieee802154.h" +#endif + +#include "net/netdev2.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Callback type to handle send command + * + * @param[in] dev network device descriptor + * @param[in] vector io vector array to send + * @param[in] count number of entries in vector + * + * @return number of bytes sent + * @return <= 0 on error + */ +typedef int (*netdev2_test_send_cb_t)(netdev2_t *dev, + const struct iovec *vector, + int count); + +/** + * @brief Callback type to handle receive command + * + * @param[in] dev network device descriptor + * @param[out] buf buffer to write into or `NULL` + * @param[in] len maximum number of bytes to read + * @param[out] info status information for the received packet. Might + * be of different type for different netdev2 devices. + * May be NULL if not needed or applicable + * + * @return <=0 on error + * @return number of bytes read if buf != NULL + * @return currently received packet size if buf == NULL + */ +typedef int (*netdev2_test_recv_cb_t)(netdev2_t *dev, char *buf, int len, + void *info); + +/** + * @brief Callback type to handle device initialization + * + * @param[in] dev network device descriptor + * + * @return <= on error + * @return 0 on success + */ +typedef int (*netdev2_test_init_cb_t)(netdev2_t *dev); + +/** + * @brief Callback type to handle user-space ISR events + * + * @param[in] dev network device descriptor + */ +typedef void (*netdev2_test_isr_cb_t)(netdev2_t *dev); + +/** + * @brief Callback type to handle get commands + * + * @param[in] dev network device descriptor + * @param[out] value pointer to store the option's value in + * @param[in] max_len maximal amount of bytes that fit into @p value + * + * @return number of bytes written to @p value + * @return <0 on error + */ +typedef int (*netdev2_test_get_cb_t)(netdev2_t *dev, void *value, + size_t max_len); + +/** + * @brief Callback type to handle set commands + * + * @param[in] dev network device descriptor + * @param[out] value value to set + * @param[in] value_len the length of @p value + * + * @return number of bytes used from @p value + * @return <0 on error + */ +typedef int (*netdev2_test_set_cb_t)(netdev2_t *dev, void *value, + size_t value_len); + +/** + * @brief Device descriptor for @ref sys_netdev2_test devices + * + * @extends netdev2_t + */ +typedef struct { + /** + * @brief netdev2 fields + * @{ + */ +#ifdef MODULE_NETDEV2_IEEE802154 + netdev2_ieee802154_t netdev; /**< superclass */ +#else /* MODULE_NETDEV2_IEEE802154 */ + netdev2_t netdev; /**< superclass */ +#endif /* MODULE_NETDEV2_IEEE802154 */ + /** @} */ + + /** + * @brief device specific fields + * @{ + */ + netdev2_test_send_cb_t send_cb; /**< callback to handle send command */ + netdev2_test_recv_cb_t recv_cb; /**< callback to handle receive command */ + netdev2_test_init_cb_t init_cb; /**< callback to handle initialization events */ + netdev2_test_isr_cb_t isr_cb; /**< callback to handle ISR events */ + netdev2_test_get_cb_t get_cbs[NETOPT_NUMOF]; /**< callback to handle get command */ + netdev2_test_set_cb_t set_cbs[NETOPT_NUMOF]; /**< callback to handle set command */ + void *state; /**< external state for the device */ + mutex_t mutex; /**< mutex for the device */ + /** @} */ +} netdev2_test_t; + +/** + * @brief override send callback + * + * @param[in] dev a @ref sys_netdev2_test device + * @param[in] send_cb a send callback + */ +static inline void netdev2_test_set_send_cb(netdev2_test_t *dev, + netdev2_test_send_cb_t send_cb) +{ + mutex_lock(&dev->mutex); + dev->send_cb = send_cb; + mutex_unlock(&dev->mutex); +} + +/** + * @brief override receive callback + * + * @param[in] dev a @ref sys_netdev2_test device + * @param[in] recv_cb a receive callback + */ +static inline void netdev2_test_set_recv_cb(netdev2_test_t *dev, + netdev2_test_recv_cb_t recv_cb) +{ + mutex_lock(&dev->mutex); + dev->recv_cb = recv_cb; + mutex_unlock(&dev->mutex); +} + +/** + * @brief override initialization callback + * + * @param[in] dev a @ref sys_netdev2_test device + * @param[in] init_cb an initialization callback + */ +static inline void netdev2_test_set_init_cb(netdev2_test_t *dev, + netdev2_test_init_cb_t init_cb) +{ + mutex_lock(&dev->mutex); + dev->init_cb = init_cb; + mutex_unlock(&dev->mutex); +} + +/** + * @brief override ISR event handler callback + * + * @param[in] dev a @ref sys_netdev2_test device + * @param[in] isr_cb an ISR event handler callback + */ +static inline void netdev2_test_set_isr_cb(netdev2_test_t *dev, + netdev2_test_isr_cb_t isr_cb) +{ + mutex_lock(&dev->mutex); + dev->isr_cb = isr_cb; + mutex_unlock(&dev->mutex); +} + +/** + * @brief override get callback for a certain option type + * + * @param[in] dev a @ref sys_netdev2_test device + * @param[in] opt an option type + * @param[in] get_cb a get callback for @p opt + */ +static inline void netdev2_test_set_get_cb(netdev2_test_t *dev, netopt_t opt, + netdev2_test_get_cb_t get_cb) +{ + mutex_lock(&dev->mutex); + dev->get_cbs[opt] = get_cb; + mutex_unlock(&dev->mutex); +} + +/** + * @brief override get callback for a certain option type + * + * @param[in] dev a @ref sys_netdev2_test device + * @param[in] opt an option type + * @param[in] set_cb a set callback for @p opt + */ +static inline void netdev2_test_set_set_cb(netdev2_test_t *dev, netopt_t opt, + netdev2_test_set_cb_t set_cb) +{ + mutex_lock(&dev->mutex); + dev->set_cbs[opt] = set_cb; + mutex_unlock(&dev->mutex); +} + +/** + * @brief Setup a given @ref sys_netdev2_test device + * + * @param[in] dev a @ref sys_netdev2_test device to initialize + * @param[in] state external state for the device + */ +void netdev2_test_setup(netdev2_test_t *dev, void *state); + +/** + * @brief Resets all callbacks for the device to NULL + * + * @param[in] dev a @ref sys_netdev2_test device to initialize + */ +void netdev2_test_reset(netdev2_test_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* NETDEV2_TEST_H_ */ +/** @} */ diff --git a/sys/net/netdev2_test/Makefile b/sys/net/netdev2_test/Makefile new file mode 100644 index 000000000..48422e909 --- /dev/null +++ b/sys/net/netdev2_test/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/netdev2_test/netdev2_test.c b/sys/net/netdev2_test/netdev2_test.c new file mode 100644 index 000000000..7859cae5c --- /dev/null +++ b/sys/net/netdev2_test/netdev2_test.c @@ -0,0 +1,144 @@ +/* + * 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 + */ + +#include +#include +#include + +#include "net/netdev2_test.h" + +static int _send(netdev2_t *netdev, const struct iovec *vector, int count); +static int _recv(netdev2_t *netdev, char *buf, int len, void *info); +static int _init(netdev2_t *dev); +static void _isr(netdev2_t *dev); +static int _get(netdev2_t *dev, netopt_t opt, void *value, size_t max_len); +static int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len); + +static const netdev2_driver_t _driver = { + .send = _send, + .recv = _recv, + .init = _init, + .isr = _isr, + .get = _get, + .set = _set, +}; + +void netdev2_test_setup(netdev2_test_t *dev, void *state) +{ + netdev2_t *netdev = (netdev2_t *)dev; + + netdev->driver = &_driver; + dev->state = state; + mutex_init(&dev->mutex); + netdev2_test_reset(dev); +} + +void netdev2_test_reset(netdev2_test_t *dev) +{ + mutex_lock(&dev->mutex); + dev->send_cb = NULL; + dev->recv_cb = NULL; + dev->init_cb = NULL; + dev->isr_cb = NULL; + memset(dev->get_cbs, 0, sizeof(dev->get_cbs)); + memset(dev->set_cbs, 0, sizeof(dev->set_cbs)); + mutex_unlock(&dev->mutex); +} + +static int _send(netdev2_t *netdev, const struct iovec *vector, int count) +{ + netdev2_test_t *dev = (netdev2_test_t *)netdev; + int res = count; /* assume everything would be fine */ + + mutex_lock(&dev->mutex); + if (dev->send_cb != NULL) { + res = dev->send_cb(netdev, vector, count); + } + mutex_unlock(&dev->mutex); + return res; +} + +static int _recv(netdev2_t *netdev, char *buf, int len, void *info) +{ + netdev2_test_t *dev = (netdev2_test_t *)netdev; + int res = (buf == NULL) ? 0 : len; /* assume everything would be fine */ + + mutex_lock(&dev->mutex); + if (dev->recv_cb != NULL) { + /* could fire context change and call _recv so we need to unlock */ + mutex_unlock(&dev->mutex); + res = dev->recv_cb(netdev, buf, len, info); + } + else { + mutex_unlock(&dev->mutex); + } + return res; +} + +static int _init(netdev2_t *netdev) +{ + netdev2_test_t *dev = (netdev2_test_t *)netdev; + int res = 0; /* assume everything would be fine */ + + mutex_lock(&dev->mutex); + if (dev->init_cb != NULL) { + res = dev->init_cb(netdev); + } + mutex_unlock(&dev->mutex); + return res; +} + +static void _isr(netdev2_t *netdev) +{ + netdev2_test_t *dev = (netdev2_test_t *)netdev; + + mutex_lock(&dev->mutex); + if (dev->isr_cb != NULL) { + mutex_unlock(&dev->mutex); + dev->isr_cb(netdev); + } + else { + mutex_unlock(&dev->mutex); + } +} + +static int _get(netdev2_t *netdev, netopt_t opt, void *value, size_t max_len) +{ + netdev2_test_t *dev = (netdev2_test_t *)netdev; + int res = -ENOTSUP; /* option assumed to be not supported */ + + mutex_lock(&dev->mutex); + if (dev->get_cbs[opt] != NULL) { + res = dev->get_cbs[opt](netdev, value, max_len); + } + mutex_unlock(&dev->mutex); + return res; +} + +static int _set(netdev2_t *netdev, netopt_t opt, void *value, size_t value_len) +{ + netdev2_test_t *dev = (netdev2_test_t *)netdev; + int res = -ENOTSUP; /* option assumed to be not supported */ + + mutex_lock(&dev->mutex); + if (dev->set_cbs[opt] != NULL) { + res = dev->set_cbs[opt](netdev, value, value_len); + } + mutex_unlock(&dev->mutex); + return res; +} + + +/** @} */ From 076a49b51281b642ca9ea053d3e59062cc9e357d Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sun, 21 Feb 2016 20:34:29 +0100 Subject: [PATCH 2/2] tests: add test application for netdev2_test --- tests/netdev2_test/Makefile | 17 ++ tests/netdev2_test/main.c | 359 ++++++++++++++++++++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 tests/netdev2_test/Makefile create mode 100644 tests/netdev2_test/main.c diff --git a/tests/netdev2_test/Makefile b/tests/netdev2_test/Makefile new file mode 100644 index 000000000..e98659d22 --- /dev/null +++ b/tests/netdev2_test/Makefile @@ -0,0 +1,17 @@ +APPLICATION = netdev2_test +include ../Makefile.tests_common + +DISABLE_MODULE = auto_init + +FEATURES_REQUIRED += periph_timer # xtimer required for this application + +USEMODULE += gnrc +USEMODULE += gnrc_neterr +USEMODULE += gnrc_netif +USEMODULE += gnrc_netdev2 +USEMODULE += netdev2_test +USEMODULE += od + +CFLAGS += -DGNRC_PKTBUF_SIZE=200 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/netdev2_test/main.c b/tests/netdev2_test/main.c new file mode 100644 index 000000000..f5a4408a5 --- /dev/null +++ b/tests/netdev2_test/main.c @@ -0,0 +1,359 @@ +/* + * 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 + * @brief Show case application for netdev2_test + * + * @author Martine Lenders + * + * @} + */ + +#include + +#include "msg.h" +#include "net/ethernet.h" +#include "net/gnrc.h" +#include "net/gnrc/netdev2/eth.h" +#include "net/netdev2_test.h" +#include "od.h" +#include "thread.h" +#include "utlist.h" + +#define _EXP_LENGTH (64) + +#define _MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF) +#define _MAC_PRIO (THREAD_PRIORITY_MAIN - 4) + +#define _MAIN_MSG_QUEUE_SIZE (2) + +#define _TEST_PAYLOAD1 "gO3Xt,fP)6* MR161Auk?W^mTb\"LmY^Qc5w1h:C<+n(*/@4k(" +#define _TEST_PAYLOAD2 "*b/'XKkraEBexaU\\O-X&dst, _test_dst, sizeof(_test_dst)); + memcpy(exp_mac->src, _dev_addr, sizeof(_dev_addr)); + exp_mac->type = byteorder_htons(ETHERTYPE_UNKNOWN); + memcpy(exp_payload, _TEST_PAYLOAD1, sizeof(_TEST_PAYLOAD1) - 1); + _tmp_len = sizeof(_TEST_PAYLOAD1) + sizeof(ethernet_hdr_t) - 1; + /* register for returned packet status */ + if (gnrc_neterr_reg(pkt) != 0) { + puts("Can not register for error reporting"); + return 0; + } + /* send packet to MAC layer */ + gnrc_netapi_send(_mac_pid, pkt); + /* wait for packet status and check */ + msg_receive(&msg); + if ((msg.type != GNRC_NETERR_MSG_TYPE) || + (msg.content.value != GNRC_NETERR_SUCCESS)) { + puts("Error sending packet"); + return 0; + } + return 1; +} + +/* tests receiving */ +static int test_receive(void) +{ + ethernet_hdr_t *rcv_mac = (ethernet_hdr_t *)_tmp; + uint8_t *rcv_payload = _tmp + sizeof(ethernet_hdr_t); + gnrc_pktsnip_t *pkt, *hdr; + gnrc_netreg_entry_t me = { NULL, GNRC_NETREG_DEMUX_CTX_ALL, + thread_getpid() }; + msg_t msg; + + if (_dev.netdev.event_callback == NULL) { + puts("Device's event_callback not set"); + return 0; + } + /* prepare receive buffer */ + memcpy(rcv_mac->dst, _dev_addr, sizeof(_dev_addr)); + memcpy(rcv_mac->src, _test_src, sizeof(_test_src)); + /* no gnrc_ipv6 in compile unit => ETHERTYPE_IPV6 translates to + * GNRC_NETTYPE_UNDEF */ + rcv_mac->type = byteorder_htons(ETHERTYPE_IPV6); + memcpy(rcv_payload, _TEST_PAYLOAD2, sizeof(_TEST_PAYLOAD2) - 1); + _tmp_len = sizeof(_TEST_PAYLOAD2) + sizeof(ethernet_hdr_t) - 1; + + /* register for GNRC_NETTYPE_UNDEF */ + gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &me); + /* fire ISR event */ + _dev.netdev.event_callback((netdev2_t *)&_dev.netdev, NETDEV2_EVENT_ISR, + &_dev.netdev.isr_arg); + /* wait for packet from MAC layer*/ + msg_receive(&msg); + /* check message */ + if (msg.sender_pid != _mac_pid) { + puts("Unexpected sender of netapi receive message"); + return 0; + } + if (msg.type != GNRC_NETAPI_MSG_TYPE_RCV) { + puts("Expected netapi receive message"); + return 0; + } + pkt = (gnrc_pktsnip_t *)msg.content.ptr; + /* check payload */ + if (pkt->size != _tmp_len - sizeof(ethernet_hdr_t)) { + puts("Payload of unexpected size"); + } + if ((pkt->type != GNRC_NETTYPE_UNDEF) || + (memcmp(pkt->data, _TEST_PAYLOAD2, pkt->size) != 0)) { + puts("Unexpected payload"); + puts("==========================================================="); + puts("expected"); + puts("==========================================================="); + od_hex_dump(_TEST_PAYLOAD2, pkt->size, OD_WIDTH_DEFAULT); + puts("==========================================================="); + puts("send data"); + puts("==========================================================="); + od_hex_dump(pkt->data, pkt->size, OD_WIDTH_DEFAULT); + return 0; + } + hdr = pkt->next; + /* check netif header */ + if ((hdr->type != GNRC_NETTYPE_NETIF) || (hdr->next != NULL) || + (hdr->size) != (sizeof(gnrc_netif_hdr_t) + (2 * ETHERNET_ADDR_LEN))) { + puts("Malformed header received"); + return 0; + } + if (memcmp(gnrc_netif_hdr_get_src_addr(hdr->data), _test_src, + ETHERNET_ADDR_LEN) != 0) { + char addr_str[ETHERNET_ADDR_LEN * 3]; + puts("Unexpected source received"); + puts("================="); + puts("expected"); + puts("================="); + puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), + _test_src, + ETHERNET_ADDR_LEN)); + puts("================="); + puts("received source"); + puts("================="); + puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), + gnrc_netif_hdr_get_src_addr(hdr->data), + ETHERNET_ADDR_LEN)); + return 0; + } + if (memcmp(gnrc_netif_hdr_get_dst_addr(hdr->data), _dev_addr, + ETHERNET_ADDR_LEN) != 0) { + char addr_str[ETHERNET_ADDR_LEN * 3]; + puts("Unexpected destination received"); + puts("================="); + puts("expected"); + puts("================="); + puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), + _dev_addr, + ETHERNET_ADDR_LEN)); + puts("===================="); + puts("received destination"); + puts("===================="); + puts(gnrc_netif_addr_to_str(addr_str, sizeof(addr_str), + gnrc_netif_hdr_get_dst_addr(hdr->data), + ETHERNET_ADDR_LEN)); + return 0; + } + + gnrc_pktbuf_release(pkt); + gnrc_netreg_unregister(GNRC_NETTYPE_UNDEF, &me); + return 1; +} + +static int test_set_addr(void) +{ + static const uint8_t new_addr[] = { 0x71, 0x29, 0x5b, 0xc8, 0x52, 0x65 }; + uint8_t tmp[sizeof(new_addr)]; + + if (gnrc_netapi_set(_mac_pid, NETOPT_ADDRESS, 0, (void *)new_addr, + sizeof(new_addr)) != sizeof(new_addr)) { + puts("Error setting device address"); + return 0; + } + if (gnrc_netapi_get(_mac_pid, NETOPT_ADDRESS, 0, tmp, + sizeof(tmp)) != sizeof(tmp)) { + puts("Error setting device address"); + return 0; + } + else if (memcmp(tmp, new_addr, sizeof(new_addr)) != 0) { + puts("Set to wrong device address"); + return 0; + } + return 1; +} + +int main(void) +{ + /* initialization */ + gnrc_pktbuf_init(); + msg_init_queue(_main_msg_queue, _MAIN_MSG_QUEUE_SIZE); + netdev2_test_setup(&_dev, NULL); + netdev2_test_set_isr_cb(&_dev, _dev_isr); + netdev2_test_set_recv_cb(&_dev, _dev_recv); + netdev2_test_set_send_cb(&_dev, _dev_send); + netdev2_test_set_get_cb(&_dev, NETOPT_ADDRESS, _dev_get_addr); + netdev2_test_set_set_cb(&_dev, NETOPT_ADDRESS, _dev_set_addr); + gnrc_netdev2_eth_init(&_gnrc_dev, (netdev2_t *)(&_dev)); + _mac_pid = gnrc_netdev2_init(_mac_stack, _MAC_STACKSIZE, _MAC_PRIO, + "gnrc_netdev_eth_test", &_gnrc_dev); + if (_mac_pid <= KERNEL_PID_UNDEF) { + puts("Could not start MAC thread\n"); + return 1; + } + + /* test execution */ + EXECUTE(test_get_addr); + EXECUTE(test_send); + EXECUTE(test_receive); + EXECUTE(test_set_addr); + puts("ALL TESTS SUCCESSFUL"); + + return 0; +} + +/* netdev2_test callbacks */ +static void _dev_isr(netdev2_t *dev) +{ + (void)dev; + if (dev->event_callback) { + dev->event_callback(dev, NETDEV2_EVENT_RX_COMPLETE, dev->isr_arg); + } +} + +static int _dev_recv(netdev2_t *dev, char *buf, int len, void *info) +{ + (void)dev; + (void)info; + if (buf == NULL) { + return _tmp_len; + } + else if (len < _tmp_len) { + return -ENOBUFS; + } + else { + memcpy(buf, _tmp, _tmp_len); + return _tmp_len; + } +} + +static int _dev_send(netdev2_t *dev, const struct iovec *vector, int count) +{ + int idx = 0; + + (void)dev; + /* check packet content with expected data */ + for (int i = 0; i < count; i++) { + if (memcmp(&(_tmp[idx]), vector[i].iov_base, vector[i].iov_len) != 0) { + printf("Unexpected send data (vector index = %d)\n", i); + puts("==========================================================="); + puts("expected"); + puts("==========================================================="); + od_hex_dump(&_tmp[idx], vector[i].iov_len, OD_WIDTH_DEFAULT); + puts("==========================================================="); + puts("send data"); + puts("==========================================================="); + od_hex_dump(vector[i].iov_base, vector[i].iov_len, OD_WIDTH_DEFAULT); + return -EINVAL; + } + idx += vector[i].iov_len; + } + if (idx != _tmp_len) { + printf("Unexpected send length: %d (expected: %d)\n", idx, _tmp_len); + return -EINVAL; + } + + return idx; +} + +static int _dev_get_addr(netdev2_t *dev, void *value, size_t max_len) +{ + (void)dev; + if (max_len < sizeof(_dev_addr)) { + return -ENOBUFS; + } + memcpy(value, _dev_addr, sizeof(_dev_addr)); + return sizeof(_dev_addr); +} + +static int _dev_set_addr(netdev2_t *dev, void *value, size_t value_len) +{ + (void)dev; + if (value_len != sizeof(_dev_addr)) { + return -EOVERFLOW; + } + memcpy(_dev_addr, value, sizeof(_dev_addr)); + return sizeof(_dev_addr); +}