diff --git a/sys/Makefile b/sys/Makefile index 2461904134..beba5a7217 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -16,6 +16,9 @@ endif ifneq (,$(filter l2_ping,$(USEMODULE))) DIRS += net/link_layer/ping endif +ifneq (,$(filter nomac,$(USEMODULE))) + DIRS += net/link_layer/nomac +endif ifneq (,$(filter transport_layer,$(USEMODULE))) USEMODULE += udp USEMODULE += tcp diff --git a/sys/Makefile.include b/sys/Makefile.include index fa45959152..d56b9809e7 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -1,3 +1,6 @@ +ifneq (,$(filter nomac,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include +endif ifneq (,$(filter transport_layer,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include endif diff --git a/sys/auto_init/Makefile b/sys/auto_init/Makefile index d0a6370718..6579f361bc 100644 --- a/sys/auto_init/Makefile +++ b/sys/auto_init/Makefile @@ -2,4 +2,8 @@ ifneq (,$(filter net_if,$(USEMODULE))) INCLUDES += -I$(RIOTBASE)/sys/net/include/ endif +ifneq (,$(filter nomac,$(USEMODULE))) + INCLUDES += -I$(RIOTBASE)/sys/net/include/ +endif + include $(RIOTBASE)/Makefile.base diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 86cbaf7acd..df52d0c97a 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -67,6 +67,10 @@ #include "tcp.h" #endif +#ifdef MODULE_NOMAC +#include "nomac.h" +#endif + #ifdef MODULE_NET_IF #include "cpu-conf.h" #include "cpu.h" @@ -241,6 +245,10 @@ void auto_init(void) DEBUG("Auto init net_if module.\n"); l2_ping_init(); #endif +#ifdef MODULE_NOMAC + DEBUG("Auto init nomac module.\n"); + nomac_init_module(); +#endif #ifdef MODULE_NET_IF DEBUG("Auto init net_if module.\n"); auto_init_net_if(); diff --git a/sys/net/include/nomac.h b/sys/net/include/nomac.h new file mode 100644 index 0000000000..8323078191 --- /dev/null +++ b/sys/net/include/nomac.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 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 nomac Link layer with no medium access + * @ingroup net + * @brief Link layer protocol to speak with any transceiver driver + * directly without any medium access. + * @{ + * + * @file + * @brief Link layer protocol to speak with any transceiver driver + * directly without any medium access. + * + * @author Martine Lenders + */ + +#ifndef __NOMAC_H_ +#define __NOMAC_H_ + +#include + +#include "netdev/base.h" +#include "netapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NOMAC_REGISTRY_SIZE +/** + * @brief The size of NOMAC's registry of receiving threads. + */ +#define NOMAC_REGISTRY_SIZE (1) +#endif + +/** + * @brief Recommended stack size for a NOMAC thread + * TODO: determine real minimal size based on thread_print_all() output + */ +#define NOMAC_CONTROL_STACKSIZE (KERNEL_CONF_STACKSIZE_DEFAULT) + +/** + * @brief Basic configuration types + * + * @extends netapi_conf_type_t + */ +typedef enum { + NOMAC_PROTO = NETAPI_CONF_PROTO, /**< Set or get protocol */ + NOMAC_CHANNEL = NETAPI_CONF_CARRIER, /**< Set or get channel */ + NOMAC_ADDRESS = NETAPI_CONF_ADDRESS, /**< Set or get address */ + NOMAC_NID = NETAPI_CONF_SUBNETS, /**< Set or get network id + * (e.g. PAN ID in 802.15.4)*/ + NOMAC_MAX_PACKET_SIZE = NETAPI_CONF_MAX_PACKET_SIZE, /**< Set or get maximum + * packet size */ + NOMAC_SRC_LEN = NETAPI_CONF_SRC_LEN, /**< Set or get default source length */ + NOMAC_REGISTRY = NETAPI_CONF_REGISTRY, /**< get registered threads */ + NOMAC_ADDRESS2 = NETDEV_OPT_ADDRESS_LONG, /**< Set or get alternative address + * format (e.g EUI-64 in 802.15.4) */ +} nomac_conf_type_t; + +/** + * @brief Initializes the module + */ +void nomac_init_module(void); + +/** + * @brief Initialize new NOMAC layer. + * + * @param[in] stack Stack for the control thread + * @param[in] stacksize Size of *stack* + * @param[in] priority Priority for the control thread + * @param[in] name Name for the control thread + * @param[in] dev An *initialized* network device to use with this MAC + * layer + * + * @see @ref thread_create + * + * @return PID of NOMAC control thread on success + * @return -EINVAL if priority is invalid + * @return -EOVERFLOW if no slot for the new thread is available + */ +kernel_pid_t nomac_init(char *stack, int stacksize, char priority, + const char *name, netdev_t *dev); + +#ifdef MODULE_NETDEV_DUMMY +/** + * @brief Re-updates the receive callback of a network device for testing + * purposes + * + * @param[in] dev A network device + */ +void nomac_update_callback(netdev_t *dev); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __NOMAC_H_ */ + +/** @} */ diff --git a/sys/net/link_layer/nomac/Makefile b/sys/net/link_layer/nomac/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/net/link_layer/nomac/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/link_layer/nomac/nomac.c b/sys/net/link_layer/nomac/nomac.c new file mode 100644 index 0000000000..aaa16492ff --- /dev/null +++ b/sys/net/link_layer/nomac/nomac.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2014 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. + */ +#include +#include + +#include "netapi.h" +#include "msg.h" +#include "netdev/base.h" +#include "thread.h" + +#include "nomac.h" + +#ifdef MODULE_NETDEV_DUMMY +#include "netdev_dummy.h" +#endif + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define NOMAC_MSG_QUEUE_SIZE (16) + +static struct { + kernel_pid_t registrar_pid; /**< Thread recipient is registered to */ + kernel_pid_t recipient_pid; /**< Registered recipient thread */ +} _nomac_registry[NOMAC_REGISTRY_SIZE]; + +static int _nomac_recv_cb(netdev_t *dev, void *src, size_t src_len, void *dest, + size_t dest_len, void *payload, size_t payload_len) +{ + (void)dev; + kernel_pid_t current_pid = thread_getpid(); + size_t offset; + netapi_rcv_pkt_t packet; + netapi_ack_t ack_mem; + msg_t msg_pkt, msg_ack; + + packet.type = NETAPI_CMD_RCV; + packet.ack = &ack_mem; + packet.src = src; + packet.src_len = src_len; + packet.dest = dest; + packet.dest_len = dest_len; + msg_pkt.type = NETAPI_MSG_TYPE; + msg_pkt.content.ptr = (char *)(&packet); + + for (unsigned int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { + if (_nomac_registry[i].registrar_pid == current_pid) { + offset = 0; + + while (offset < payload_len) { + netapi_ack_t *ack; + packet.data = (void *)(((char *)payload) + offset); + packet.data_len = payload_len - offset; + + msg_send_receive(&msg_pkt, &msg_ack, + _nomac_registry[i].recipient_pid); + ack = (netapi_ack_t *)(msg_ack.content.ptr); + + if ((msg_ack.type == NETAPI_MSG_TYPE) && + (ack->type == NETAPI_CMD_ACK) && + (ack->orig == NETAPI_CMD_RCV)) { + if (ack->result > 0) { + offset += (ack->result); + } + else { + DEBUG("Error code received for registrar %" PRIkernel_pid + " with recipient %" PRIkernel_pid ": %d", + _nomac_registry[i].registrar_pid, + _nomac_registry[i].recipient_pid, + -(ack->result)); + + return ack->result; + } + } + else { + DEBUG("Unexpected msg instead of ACK. Abort for registrar " + "\"%s\" with recipient \"%s\": msg.type = %d, " + "ack->type = %d, ack->orig = %d", + thread_getname(_nomac_registry[i].registrar_pid), + thread_getname(_nomac_registry[i].recipient_pid), + msg_ack.type, ack->type, ack->orig); + + return -ENOMSG; + } + + } + } + } + + return payload_len; +} + +static inline int _nomac_send(netdev_t *dev, netapi_snd_pkt_t *pkt) +{ + return dev->driver->send_data(dev, pkt->dest, pkt->dest_len, pkt->ulh, + pkt->data, pkt->data_len); +} + +static int _nomac_get_registry(netapi_conf_t *conf) +{ + kernel_pid_t current_pid = thread_getpid(); + kernel_pid_t registry[NOMAC_REGISTRY_SIZE]; + uint8_t size = 0; + + for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { + if ((size * sizeof(kernel_pid_t)) > (conf->data_len)) { + return -EOVERFLOW; + } + + if (_nomac_registry[i].registrar_pid == current_pid) { + registry[size++] = _nomac_registry[i].recipient_pid; + } + } + + conf->data_len = size * sizeof(kernel_pid_t); + memcpy(conf->data, registry, conf->data_len); + + return 0; +} + +static int _nomac_get_option(netdev_t *dev, netapi_conf_t *conf) +{ + int res; + + switch ((nomac_conf_type_t)conf->param) { + case NOMAC_PROTO: + case NOMAC_CHANNEL: + case NOMAC_ADDRESS: + case NOMAC_NID: + case NOMAC_MAX_PACKET_SIZE: + case NOMAC_ADDRESS2: + if ((res = dev->driver->get_option(dev, (netdev_opt_t)conf->param, + conf->data, &(conf->data_len)) + ) == 0) { + return (int)conf->data_len; + } + else { + return res; + } + + case NOMAC_REGISTRY: + return _nomac_get_registry(conf); + + default: + break; + } + + return -ENOTSUP; +} + +static int _nomac_set_option(netdev_t *dev, netapi_conf_t *conf) +{ + switch ((nomac_conf_type_t)(conf->param)) { + case NOMAC_PROTO: + case NOMAC_CHANNEL: + case NOMAC_ADDRESS: + case NOMAC_NID: + case NOMAC_ADDRESS2: + return dev->driver->set_option(dev, (netdev_opt_t)conf->param, + conf->data, conf->data_len); + + default: + break; + } + + return -ENOTSUP; +} + +static void *_nomac_runner(void *args) +{ + netdev_t *dev = (netdev_t *)args; + msg_t msg_cmd, msg_ack, msg_queue[NOMAC_MSG_QUEUE_SIZE]; + + netapi_cmd_t *cmd; + netapi_ack_t *ack; + + msg_ack.type = NETAPI_MSG_TYPE; + + msg_init_queue(msg_queue, NOMAC_MSG_QUEUE_SIZE); + + dev->driver->init(dev); + dev->driver->add_receive_data_callback(dev, _nomac_recv_cb); + + while (1) { + msg_receive(&msg_cmd); + + if (msg_cmd.type == NETDEV_MSG_EVENT_TYPE) { + dev->driver->event(dev, msg_cmd.content.value); + } + else if (msg_cmd.type == NETAPI_MSG_TYPE) { + cmd = (netapi_cmd_t *)(msg_cmd.content.ptr); + ack = cmd->ack; + msg_ack.content.ptr = (char *)ack; + + switch (cmd->type) { + case NETAPI_CMD_SND: + ack->result = _nomac_send(dev, (netapi_snd_pkt_t *)cmd); + break; + + case NETAPI_CMD_GET: + ack->result = _nomac_get_option(dev, (netapi_conf_t *)cmd); + break; + + case NETAPI_CMD_SET: + ack->result = _nomac_set_option(dev, (netapi_conf_t *)cmd); + break; + + case NETAPI_CMD_REG: + ack->result = -ENOBUFS; + + for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { + if (_nomac_registry[i].registrar_pid == KERNEL_PID_UNDEF) { + netapi_reg_t *reg = (netapi_reg_t *)cmd; + + _nomac_registry[i].registrar_pid = thread_getpid(); + _nomac_registry[i].recipient_pid = reg->reg_pid; + ack->result = NETAPI_STATUS_OK; + + break; + } + } + + break; + + case NETAPI_CMD_UNREG: + ack->result = NETAPI_STATUS_OK; + + for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { + netapi_reg_t *reg = (netapi_reg_t *)cmd; + + if (_nomac_registry[i].registrar_pid == thread_getpid() && + _nomac_registry[i].recipient_pid == reg->reg_pid) { + _nomac_registry[i].recipient_pid = KERNEL_PID_UNDEF; + + break; + } + + } + + break; + +#ifdef MODULE_NETDEV_DUMMY + + case NETAPI_CMD_FIRE_RCV: + ack->result = unittest_netdev_dummy_fire_rcv_event(dev, + ((netapi_rcv_pkt_t *)cmd)->src, + ((netapi_rcv_pkt_t *)cmd)->src_len, + ((netapi_rcv_pkt_t *)cmd)->dest, + ((netapi_rcv_pkt_t *)cmd)->dest_len, + ((netapi_rcv_pkt_t *)cmd)->data, + ((netapi_rcv_pkt_t *)cmd)->data_len); + break; +#endif + + default: + ack->result = -ENOTSUP; + break; + } + + ack->type = NETAPI_CMD_ACK; + ack->orig = cmd->type; + msg_reply(&msg_cmd, &msg_ack); + } + } + + /* never reached */ + return NULL; +} + +void nomac_init_module(void) +{ + for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { + _nomac_registry[i].registrar_pid = KERNEL_PID_UNDEF; + _nomac_registry[i].recipient_pid = KERNEL_PID_UNDEF; + } +} + +kernel_pid_t nomac_init(char *stack, int stacksize, char priority, + const char *name, netdev_t *dev) +{ + return thread_create(stack, stacksize, priority, CREATE_STACKTEST, + _nomac_runner, (void *)dev, name); +} + +#ifdef MODULE_NETDEV_DUMMY +void nomac_update_callback(netdev_t *dev) +{ + dev->driver->add_receive_data_callback(dev, _nomac_recv_cb); +} +#endif diff --git a/tests/unittests/tests-nomac/Makefile b/tests/unittests/tests-nomac/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/tests/unittests/tests-nomac/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/unittests/tests-nomac/Makefile.include b/tests/unittests/tests-nomac/Makefile.include new file mode 100644 index 0000000000..ea5dcc746b --- /dev/null +++ b/tests/unittests/tests-nomac/Makefile.include @@ -0,0 +1,4 @@ +USEMODULE += netapi +USEMODULE += nomac +USEMODULE += netdev_dummy +USEMODULE += vtimer diff --git a/tests/unittests/tests-nomac/tests-nomac.c b/tests/unittests/tests-nomac/tests-nomac.c new file mode 100644 index 0000000000..9c8b0e9772 --- /dev/null +++ b/tests/unittests/tests-nomac/tests-nomac.c @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2014 Martin 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. + */ +#include +#include +#include + +#include "clist.h" +#include "nomac.h" +#include "netdev_dummy.h" +#include "thread.h" +#include "vtimer.h" + +#include "embUnit/embUnit.h" + +#include "tests-nomac.h" + +#define UNITTEST_DONE (TEST_UINT16) +#define UNITTESTS_NOMAC_NAME "unittests_nomac" +#define UNITTESTS_NOMAC_STACKSIZE (KERNEL_CONF_STACKSIZE_DEFAULT) +#define UNITTESTS_NOMAC_QSIZE (4) + +static char unittests_nomac_stack[UNITTESTS_NOMAC_STACKSIZE]; +static char unittests_nomac_rcv_stack[KERNEL_CONF_STACKSIZE_IDLE]; +static msg_t unittests_nomac_rcv_queue[UNITTESTS_NOMAC_QSIZE]; + +static netdev_t *dev = &(unittest_netdev_dummy_devs[0]); +static kernel_pid_t nomac_pid = KERNEL_PID_UNDEF; +static kernel_pid_t nomac_receiver = KERNEL_PID_UNDEF; +static kernel_pid_t main_pid = KERNEL_PID_UNDEF; + +static char received_data[UNITTESTS_NETDEV_DUMMY_MAX_PACKET]; +static char received_src[UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN]; +static char received_dst[UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN]; +static size_t received_data_len = 0, received_src_len = 0, received_dst_len = 0; + +#define SET_OPTION_NUMBER (3) +#define GET_OPTION_NUMBER (7) +#define RANDOM_SET_OPTION ((TEST_UINT8 % SET_OPTION_NUMBER) + 1) +#define RANDOM_GET_OPTION (TEST_UINT8 % SET_OPTION_NUMBER) + +static void _reset_received(void) +{ + memset(received_data, 0, sizeof(received_data)); + memset(received_src, 0, sizeof(received_src)); + memset(received_dst, 0, sizeof(received_dst)); + received_data_len = 0; + received_src_len = 0; + received_dst_len = 0; +} + +static void _fill_received(netapi_rcv_pkt_t *rcv) +{ + netapi_ack_t *ack = rcv->ack; + ack->type = NETAPI_CMD_ACK; + ack->orig = rcv->type; + + if (rcv->type != NETAPI_CMD_RCV) { + ack->result = -ENOMSG; + return; + } + + memcpy(received_src, rcv->src, rcv->src_len); + received_src_len = rcv->src_len; + memcpy(received_dst, rcv->dest, rcv->dest_len); + received_dst_len = rcv->dest_len; + memcpy(received_data, rcv->data, rcv->data_len); + received_data_len = rcv->data_len; + + ack->result = received_data_len; + return; +} + +static void *test_nomac_receive_thread(void *args) +{ + msg_t msg_rcv, msg_ack, done; + + netapi_rcv_pkt_t *rcv; + + (void)args; + + msg_init_queue(unittests_nomac_rcv_queue, UNITTESTS_NOMAC_QSIZE); + + msg_ack.type = NETAPI_MSG_TYPE; + done.type = UNITTEST_DONE; + + msg_receive(&msg_rcv); + + if (msg_rcv.type != NETAPI_MSG_TYPE) { + msg_ack.type = 0; /* Send arbitrary reply, API handles this case */ + msg_reply(&msg_rcv, &msg_ack); + msg_send(&done, main_pid); + return NULL; + } + + rcv = (netapi_rcv_pkt_t *)(msg_rcv.content.ptr); + msg_ack.content.ptr = (char *)rcv->ack; + + _fill_received(rcv); + + msg_reply(&msg_rcv, &msg_ack); + msg_send(&done, main_pid); + return NULL; +} + +static void set_up(void) +{ + unittest_netdev_dummy_init(); + dev->driver->init(dev); + nomac_update_callback(dev); + nomac_init_module(); +} + +static void set_up_with_thread(void) +{ + set_up(); + main_pid = thread_getpid(); + nomac_receiver = thread_create(unittests_nomac_rcv_stack, + sizeof(unittests_nomac_stack), + PRIORITY_MAIN - 3, 0, + test_nomac_receive_thread, NULL, + "nomac_rcv"); +} + +static void tear_down(void) +{ + _reset_received(); + nomac_receiver = KERNEL_PID_UNDEF; +} + +/********************************************* + * thread tests * + *********************************************/ +static void test_nomac_thread(void) +{ + TEST_ASSERT(KERNEL_PID_UNDEF != nomac_pid); +} + +/********************************************* + * NETAPI_CMD_SND tests * + *********************************************/ +static void test_nomac_send_data_dest_too_long(void) +{ + char dest[] = TEST_STRING8; + char data[] = TEST_STRING64; + TEST_ASSERT_EQUAL_INT(-EAFNOSUPPORT, netapi_send_payload(nomac_pid, dest, + UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN + TEST_UINT8, + data, 1)); +} + +static void test_nomac_send_data_data_too_long(void) +{ + char dest[] = TEST_STRING8; + char data[] = TEST_STRING64; + TEST_ASSERT_EQUAL_INT(-EMSGSIZE, netapi_send_payload(nomac_pid, dest, + UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN, data, + UNITTESTS_NETDEV_DUMMY_MAX_PACKET + TEST_UINT8)); +} + +static void test_nomac_send_data_send(void) +{ + char dest[] = TEST_STRING64; + size_t dest_len = UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN; + char data[] = TEST_STRING8; +#if UNITTESTS_NETDEV_DUMMY_MAX_PACKET < 8 + size_t data_len = UNITTESTS_NETDEV_DUMMY_MAX_PACKET; +#else + size_t data_len = 8; +#endif + TEST_ASSERT_EQUAL_INT((int)data_len, netapi_send_payload(nomac_pid, + dest, dest_len, data, data_len)); + TEST_ASSERT_EQUAL_INT(0, unittest_netdev_dummy_check_transmitted(dev, + dest, dest_len, data, data_len)); +} + +#if UNITTESTS_NETDEV_DUMMY_MAX_PACKET > 4 +static void test_nomac_send_data_send2(void) +{ + netdev_hlist_t hlist_node = {NULL, NULL, NETDEV_PROTO_UNKNOWN, TEST_STRING8, 4}; + netdev_hlist_t *hlist = NULL; + char dest[] = TEST_STRING64; + size_t dest_len = UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN; + char data[] = TEST_STRING16; +#if UNITTESTS_NETDEV_DUMMY_MAX_PACKET < 12 + size_t data_len = UNITTESTS_NETDEV_DUMMY_MAX_PACKET - 4; + char expected[UNITTESTS_NETDEV_DUMMY_MAX_PACKET]; +#else + size_t data_len = 8; + char expected[12]; +#endif + + memcpy(expected, TEST_STRING8, 4); + memcpy(&(expected[4]), TEST_STRING16, data_len); + + clist_add((clist_node_t **)&hlist, (clist_node_t *)&hlist_node); + TEST_ASSERT_EQUAL_INT((int)sizeof(expected), netapi_send_packet(nomac_pid, + hlist, dest, dest_len, data, data_len)); + TEST_ASSERT_EQUAL_INT(0, unittest_netdev_dummy_check_transmitted(dev, + dest, dest_len, expected, data_len + 4)); +} +#endif + +/********************************************* + * NETAPI_CMD_REG tests * + *********************************************/ +static void test_nomac_reg_buffer_full(void) +{ + for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) { + TEST_ASSERT_EQUAL_INT(0, netapi_register(nomac_pid, (kernel_pid_t)(i + 1), 0)); + } + + TEST_ASSERT_EQUAL_INT(-ENOBUFS, + netapi_register_current_thread(nomac_pid, 0)); +} + +static void test_nomac_register(void) +{ + msg_t done; + char src[] = TEST_STRING64; + size_t src_len = UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN; + char dest[] = TEST_STRING64; + size_t dest_len = UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN; + char data[] = TEST_STRING8; +#if UNITTESTS_NETDEV_DUMMY_MAX_PACKET < 8 + size_t data_len = UNITTESTS_NETDEV_DUMMY_MAX_PACKET; +#else + size_t data_len = 8; +#endif + int res; + + TEST_ASSERT(nomac_receiver != KERNEL_PID_UNDEF); + TEST_ASSERT_EQUAL_INT(0, netapi_register(nomac_pid, nomac_receiver, 0)); + res = netapi_fire_receive_event(nomac_pid, src, src_len, dest, dest_len, data, data_len); + TEST_ASSERT_EQUAL_INT(0, res); + + msg_receive(&done); + + TEST_ASSERT_EQUAL_INT(UNITTEST_DONE, done.type); + TEST_ASSERT_EQUAL_INT(src_len, received_src_len); + TEST_ASSERT_EQUAL_INT(0, memcmp(received_src, src, src_len)); + TEST_ASSERT_EQUAL_INT(dest_len, received_dst_len); + TEST_ASSERT_EQUAL_INT(0, memcmp(received_dst, dest, dest_len)); + TEST_ASSERT_EQUAL_INT(data_len, received_data_len); + TEST_ASSERT_EQUAL_INT(0, memcmp(received_data, data, data_len)); +} + +/********************************************* + * NETAPI_CMD_GET tests * + *********************************************/ + +static void test_nomac_get_option_null_data(void) +{ + size_t value_len = sizeof(unsigned int); + + TEST_ASSERT_EQUAL_INT(-EFAULT, netapi_get_option(nomac_pid, + RANDOM_GET_OPTION, NULL, value_len)); +} + +static void test_nomac_get_option_overflow(void) +{ + unsigned int value = TEST_UINT32; + + TEST_ASSERT_EQUAL_INT(-EOVERFLOW, netapi_get_option(nomac_pid, + RANDOM_GET_OPTION, &value, 0)); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, value); +} + +static void test_nomac_get_option_not_supported(void) +{ + unsigned int value = TEST_UINT32; + size_t value_len = sizeof(unsigned int); + TEST_ASSERT_EQUAL_INT(-ENOTSUP, netapi_get_option(nomac_pid, + (netapi_conf_type_t)UINT32_MAX, &value, + value_len)); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, value); +} + +static void test_nomac_get_option_get_protocol(void) +{ + netdev_proto_t value = TEST_UINT8 % 9; + TEST_ASSERT_EQUAL_INT(sizeof(netdev_proto_t), + netapi_get_option(nomac_pid, + NOMAC_PROTO, &value, + sizeof(netdev_proto_t))); + TEST_ASSERT_EQUAL_INT(NETDEV_PROTO_UNKNOWN, value); +} + +static void test_nomac_get_option_get_channel(void) +{ + unsigned int value = TEST_UINT32; + TEST_ASSERT_EQUAL_INT(sizeof(unsigned int), + netapi_get_option(nomac_pid, + NOMAC_CHANNEL, &value, + sizeof(unsigned int))); + TEST_ASSERT_EQUAL_INT(0, value); +} + +static void test_nomac_get_option_get_nid(void) +{ + unsigned int value = TEST_UINT32; + TEST_ASSERT_EQUAL_INT(sizeof(unsigned int), + netapi_get_option(nomac_pid, + NOMAC_NID, &value, + sizeof(unsigned int))); + TEST_ASSERT_EQUAL_INT(0, value); +} + +static void test_nomac_get_option_get_address(void) +{ + uint8_t value[UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN]; + TEST_ASSERT_EQUAL_INT(UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN, + netapi_get_option(nomac_pid, + NOMAC_ADDRESS, &value, + UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN)); + + for (int i = 0; i < UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN; i++) { + TEST_ASSERT_EQUAL_INT(0, value[i]); + } +} + +static void test_nomac_get_option_get_long_address(void) +{ + uint8_t value[UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN]; + TEST_ASSERT_EQUAL_INT(UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN, + netapi_get_option(nomac_pid, + NOMAC_ADDRESS2, &value, + UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN)); + + for (int i = 0; i < UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN; i++) { + TEST_ASSERT_EQUAL_INT(0, value[i]); + } +} + +/********************************************* + * NETAPI_CMD_SET tests * + *********************************************/ + +static void test_nomac_set_option_null_data(void) +{ + size_t value_len = sizeof(unsigned int); + + TEST_ASSERT_EQUAL_INT(-EFAULT, netapi_set_option(nomac_pid, + RANDOM_SET_OPTION, NULL, value_len)); +} + +static void test_nomac_set_option_inval(void) +{ + unsigned int value = TEST_UINT32; + size_t value_len = 0; + + TEST_ASSERT_EQUAL_INT(-EINVAL, netapi_set_option(nomac_pid, + RANDOM_SET_OPTION, &value, value_len)); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, value); +} + +static void test_nomac_set_option_overflow(void) +{ + unsigned int value = TEST_UINT32; + size_t value_len = UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN + TEST_UINT16; + + TEST_ASSERT_EQUAL_INT(-EOVERFLOW, netapi_set_option(nomac_pid, + RANDOM_SET_OPTION, &value, value_len)); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, value); +} + +static void test_nomac_set_option_not_supported(void) +{ + unsigned int value = TEST_UINT32; + size_t value_len = sizeof(unsigned int); + TEST_ASSERT_EQUAL_INT(-ENOTSUP, netapi_set_option(nomac_pid, + (netapi_conf_type_t)UINT32_MAX, &value, + value_len)); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, value); +} + +static void test_nomac_set_get_channel(void) +{ + unsigned int value = TEST_UINT32; + size_t value_len = sizeof(unsigned int); + TEST_ASSERT_EQUAL_INT(0, netapi_set_option(nomac_pid, + NOMAC_CHANNEL, &value, value_len)); + value = 0; + TEST_ASSERT_EQUAL_INT(sizeof(unsigned int), + netapi_get_option(nomac_pid, NOMAC_CHANNEL, + &value, value_len)); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, value); + TEST_ASSERT_EQUAL_INT(sizeof(unsigned int), value_len); +} + +static void test_nomac_set_get_address(void) +{ + char value[UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN]; + size_t value_len = UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN; +#if UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN < 12 + strncpy(value, TEST_STRING12, UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN); +#else + strncpy(value, TEST_STRING12, 12); +#endif + TEST_ASSERT_EQUAL_INT(0, netapi_set_option(nomac_pid, + NOMAC_ADDRESS, value, + UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN)); +#if UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN < 12 + memset(value, 0, UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN); +#else + memset(value, 0, 12); +#endif + TEST_ASSERT_EQUAL_INT(UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN, + netapi_get_option(nomac_pid, + NOMAC_ADDRESS, value, + value_len)); +#if UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN < 12 + TEST_ASSERT(strncmp(value, TEST_STRING12, + UNITTESTS_NETDEV_DUMMY_MAX_ADDR_LEN) == 0); +#else + TEST_ASSERT(strncmp(value, TEST_STRING12, 12) == 0); +#endif +} + +static void test_nomac_set_get_nid(void) +{ + unsigned int value = TEST_UINT32; + size_t value_len = sizeof(unsigned int); + TEST_ASSERT_EQUAL_INT(0, netapi_set_option(nomac_pid, + NOMAC_NID, &value, value_len)); + value = 0; + TEST_ASSERT_EQUAL_INT(sizeof(unsigned int), + netapi_get_option(nomac_pid, NOMAC_NID, + &value, value_len)); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, value); + TEST_ASSERT_EQUAL_INT(sizeof(unsigned int), value_len); +} + +static void test_nomac_set_get_long_address(void) +{ + char value[UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN]; + size_t value_len = UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN; +#if UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN < 12 + strncpy(value, TEST_STRING12, UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN); +#else + strncpy(value, TEST_STRING12, 12); +#endif + TEST_ASSERT_EQUAL_INT(0, netapi_set_option(nomac_pid, + NOMAC_ADDRESS2, value, + UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN)); +#if UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN < 12 + memset(value, 0, UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN); +#else + memset(value, 0, 12); +#endif + TEST_ASSERT_EQUAL_INT(UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN, + netapi_get_option(nomac_pid, + NOMAC_ADDRESS2, value, + value_len)); +#if UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN < 12 + TEST_ASSERT(strncmp(value, TEST_STRING12, + UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN) == 0); +#else + TEST_ASSERT(strncmp(value, TEST_STRING12, 12) == 0); +#endif + TEST_ASSERT_EQUAL_INT(UNITTESTS_NETDEV_DUMMY_MAX_LONG_ADDR_LEN, value_len); +} + +/**************************** + * ISR event tests * + ****************************/ +static void test_nomac_event_value(void) +{ + msg_t m; + m.type = NETDEV_MSG_EVENT_TYPE; + m.content.value = TEST_UINT32; + msg_send(&m, nomac_pid); + vtimer_usleep(1000); + TEST_ASSERT_EQUAL_INT(TEST_UINT32, unittest_netdev_dummy_get_last_event(dev)); +} + +Test *tests_nomac_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + /* thread tests */ + new_TestFixture(test_nomac_thread), + /* NETAPI_CMD_SND tests */ + new_TestFixture(test_nomac_send_data_dest_too_long), + new_TestFixture(test_nomac_send_data_data_too_long), + new_TestFixture(test_nomac_send_data_send), +#if UNITTESTS_NETDEV_DUMMY_MAX_PACKET > 4 + new_TestFixture(test_nomac_send_data_send2), +#endif + /* NETAPI_CMD_REG tests */ + new_TestFixture(test_nomac_reg_buffer_full), + /* NETAPI_CMD_GET tests */ + new_TestFixture(test_nomac_get_option_null_data), + new_TestFixture(test_nomac_get_option_overflow), + new_TestFixture(test_nomac_get_option_not_supported), + new_TestFixture(test_nomac_get_option_get_protocol), + new_TestFixture(test_nomac_get_option_get_channel), + new_TestFixture(test_nomac_get_option_get_address), + new_TestFixture(test_nomac_get_option_get_nid), + new_TestFixture(test_nomac_get_option_get_long_address), + /* NETAPI_CMD_SET tests */ + new_TestFixture(test_nomac_set_option_null_data), + new_TestFixture(test_nomac_set_option_inval), + new_TestFixture(test_nomac_set_option_overflow), + new_TestFixture(test_nomac_set_option_not_supported), + new_TestFixture(test_nomac_set_get_channel), + new_TestFixture(test_nomac_set_get_address), + new_TestFixture(test_nomac_set_get_nid), + new_TestFixture(test_nomac_set_get_long_address), + /* ISR event tests */ + new_TestFixture(test_nomac_event_value), + }; + + EMB_UNIT_TESTCALLER(nomac_tests, set_up, tear_down, + fixtures); + + return (Test *)&nomac_tests; +} + +Test *tests_nomac_threaded_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_nomac_register), + }; + + EMB_UNIT_TESTCALLER(nomac_tests, set_up_with_thread, tear_down, + fixtures); + + return (Test *)&nomac_tests; +} + +void tests_nomac(void) +{ + set_up(); + vtimer_init(); + + nomac_pid = nomac_init(unittests_nomac_stack, + UNITTESTS_NOMAC_STACKSIZE, + PRIORITY_MAIN - 1, UNITTESTS_NOMAC_NAME, + dev); + + TESTS_RUN(tests_nomac_tests()); + TESTS_RUN(tests_nomac_threaded_tests()); +} diff --git a/tests/unittests/tests-nomac/tests-nomac.h b/tests/unittests/tests-nomac/tests-nomac.h new file mode 100644 index 0000000000..a9960effac --- /dev/null +++ b/tests/unittests/tests-nomac/tests-nomac.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Martin 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. + */ + +/** + * @addtogroup unittests + * @{ + * + * @file tests-nomac.h + * @brief Unittests for the ``nomac`` module + * + * @author Martine Lenders + */ +#ifndef __TESTS_NOMAC_H_ +#define __TESTS_NOMAC_H_ + +#include "embUnit.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The entry point of this test suite. + */ +void tests_nomac(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __TESTS_NETDEV_DUMMY_H_ */ +/** @} */