diff --git a/tests/socket_zep/Makefile b/tests/socket_zep/Makefile new file mode 100644 index 0000000000..db55c1d71e --- /dev/null +++ b/tests/socket_zep/Makefile @@ -0,0 +1,18 @@ +APPLICATION = socket_zep +include ../Makefile.tests_common + +BOARD_WHITELIST = native # socket_zep is only available on native + +DISABLE_MODULE += auto_init + +USEMODULE += od +USEMODULE += socket_zep + +CFLAGS += -DDEVELHELP + +TERMFLAGS ?= -z [::1]:17754 + +include $(RIOTBASE)/Makefile.include + +test: + ./tests/01-run.py diff --git a/tests/socket_zep/main.c b/tests/socket_zep/main.c new file mode 100644 index 0000000000..faac4e172e --- /dev/null +++ b/tests/socket_zep/main.c @@ -0,0 +1,179 @@ +/* + * 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. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for socket_zep network device driver + * + * @author Martine Lenders + * + * @} + */ + +#include +#include +#include +#include + +#include "byteorder.h" +#include "net/ieee802154.h" +#include "sched.h" +#include "socket_zep.h" +#include "socket_zep_params.h" +#include "msg.h" +#include "od.h" + +#define MSG_QUEUE_SIZE (8) +#define MSG_TYPE_ISR (0x3456) +#define RECVBUF_SIZE (IEEE802154_FRAME_LEN_MAX) + +static uint8_t _recvbuf[RECVBUF_SIZE]; +static msg_t _msg_queue[MSG_QUEUE_SIZE]; +static socket_zep_t _dev; +static kernel_pid_t _main_pid; + +static void _event_cb(netdev_t *dev, netdev_event_t event); +static void _print_info(netdev_t *netdev); + +static void test_init(void) +{ + const socket_zep_params_t *p = &socket_zep_params[0]; + netdev_t *netdev = (netdev_t *)(&_dev); + + printf("Initializing socket ZEP with (local: [%s]:%s, remote: [%s]:%s)\n", + p->local_addr, p->local_port, p->remote_addr, p->remote_port); + socket_zep_setup(&_dev, p); + netdev->event_callback = _event_cb; + assert(netdev->driver->init(netdev) >= 0); + _print_info(netdev); +} + +static void test_send__vector_NULL__count_0(void) +{ + netdev_t *netdev = (netdev_t *)(&_dev); + int res; + + puts("Send zero-length packet"); + res = netdev->driver->send(netdev, NULL, 0); + assert((res < 0) || (res == 0)); + if ((res < 0) && (errno == ECONNREFUSED)) { + puts("No remote socket exists (use scripts in `tests/` to have proper tests)"); + } +} + +static void test_send__vector_not_NULL__count_2(void) +{ + struct iovec vector[] = { { .iov_base = "Hello", .iov_len = sizeof("Hello") }, + { .iov_base = "World", .iov_len = sizeof("World") } }; + netdev_t *netdev = (netdev_t *)(&_dev); + int res; + + puts("Send 'Hello\\0World\\0'"); + res = netdev->driver->send(netdev, vector, + sizeof(vector) / sizeof(struct iovec)); + assert((res < 0) || (res == (sizeof("Hello")) + sizeof("World"))); + if ((res < 0) && (errno == ECONNREFUSED)) { + puts("No remote socket exists (use scripts in `tests/` to have proper tests)"); + } +} + +static void test_recv(void) +{ + puts("Waiting for an incoming message (use `make test`)"); + while (1) { + netdev_t *netdev = (netdev_t *)(&_dev); + msg_t msg; + + msg_receive(&msg); + if (msg.type == MSG_TYPE_ISR) { + netdev->driver->isr(netdev); + } + else { + puts("unexpected message type"); + } + } +} + +int main(void) +{ + puts("Socket ZEP device driver test"); + msg_init_queue(_msg_queue, MSG_QUEUE_SIZE); + _main_pid = sched_active_pid; + + test_init(); + test_send__vector_NULL__count_0(); + test_send__vector_not_NULL__count_2(); + test_recv(); /* does not return */ + puts("ALL TESTS SUCCESSFUL"); + return 0; +} + +static void _recv(netdev_t *dev) +{ + netdev_ieee802154_rx_info_t rx_info; + const int exp_len = dev->driver->recv(dev, NULL, 0, NULL); + int data_len; + + assert(exp_len >= 0); + assert(((unsigned)exp_len) <= sizeof(_recvbuf)); + data_len = dev->driver->recv(dev, _recvbuf, sizeof(_recvbuf), &rx_info); + if (data_len < 0) { + puts("Received invalid packet"); + } + else { + assert(data_len <= exp_len); + printf("RSSI: %u, LQI: %u, Data:\n", rx_info.rssi, rx_info.lqi); + if (data_len > 0) { + od_hex_dump(_recvbuf, data_len, OD_WIDTH_DEFAULT); + } + } +} + +static void _event_cb(netdev_t *dev, netdev_event_t event) +{ + if (event == NETDEV_EVENT_ISR) { + msg_t msg; + + msg.type = MSG_TYPE_ISR; + msg.content.ptr = dev; + + if (msg_send(&msg, _main_pid) <= 0) { + puts("possibly lost interrupt."); + } + } + else { + switch (event) { + case NETDEV_EVENT_RX_COMPLETE: + { + _recv(dev); + break; + } + default: + break; + } + } +} + +static void _print_info(netdev_t *netdev) +{ + uint64_t long_addr; + uint16_t short_addr; + + assert(netdev->driver->get(netdev, NETOPT_ADDRESS, &short_addr, + sizeof(short_addr)) == sizeof(uint16_t)); + assert(netdev->driver->get(netdev, NETOPT_ADDRESS_LONG, &long_addr, + sizeof(long_addr)) == sizeof(uint64_t)); + + /* we are on native, so using PRIu* is okay */ + printf("(Hwaddrs: %04" PRIx16 ", %016" PRIx64 ")\n", + byteorder_htons(short_addr).u16, + byteorder_htonll(long_addr).u64); +} diff --git a/tests/socket_zep/tests/01-run.py b/tests/socket_zep/tests/01-run.py new file mode 100755 index 0000000000..bcbfedd1bf --- /dev/null +++ b/tests/socket_zep/tests/01-run.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +# 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. + +import os +import sys + +import socket + +IEEE802154_FRAME_LEN_MAX = 127 +ZEP_DATA_HEADER_SIZE = 32 +FCS_LEN = 2 +RCVBUF_LEN = IEEE802154_FRAME_LEN_MAX + ZEP_DATA_HEADER_SIZE + FCS_LEN +zep_params = { + "local_addr": "::", + "local_port": 12345, + "remote_addr": "::1", + "remote_port": 17754, + } +s = None + + +def testfunc(child): + child.expect_exact("Socket ZEP device driver test") + child.expect(r"Initializing socket ZEP with " + + r"\(local: \[(?P[:0-9a-f]+)\]:(?P\d+), " + + r"remote: \[(?P[:0-9a-f]+)\]:(?P\d+)\)") + assert(child.match.group('local_addr') == zep_params['local_addr']) + assert(int(child.match.group('local_port')) == zep_params['local_port']) + assert(child.match.group('remote_addr') == zep_params['remote_addr']) + assert(int(child.match.group('remote_port')) == zep_params['remote_port']) + child.expect(r"\(Hwaddrs: (?P[0-9a-f]{4}), (?P[0-9a-f]{16})\)") + child.expect_exact("Send zero-length packet") + data, addr = s.recvfrom(RCVBUF_LEN) + assert(len(data) == (ZEP_DATA_HEADER_SIZE + FCS_LEN)) + child.expect_exact("Send 'Hello\\0World\\0'") + data, addr = s.recvfrom(RCVBUF_LEN) + assert(len(data) == (ZEP_DATA_HEADER_SIZE + len("Hello\0World\0") + FCS_LEN)) + assert(b"Hello\0World\0" == data[ZEP_DATA_HEADER_SIZE:-2]) + child.expect_exact("Waiting for an incoming message (use `make test`)") + s.sendto(b"\x45\x58\x02\x01\x1a\x44\xe0\x01\xff\xdb\xde\xa6\x1a\x00\x8b" + + b"\xfd\xae\x60\xd3\x21\xf1\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x22\x41\xdc\x02\x23\x00\x38\x30\x00\x0a\x50\x45\x5a\x00" + + b"\x5b\x45\x00\x0a\x50\x45\x5a\x00Hello World\x3a\xf2", + ("::1", zep_params['local_port'])) + child.expect(r"RSSI: \d+, LQI: \d+, Data:") + child.expect_exact(r"00000000 41 DC 02 23 00 38 30 00 0A 50 45 5A 00 5B 45 00") + child.expect_exact(r"00000010 0A 50 45 5A 00 48 65 6C 6C 6F 20 57 6F 72 6C 64") + + +if __name__ == "__main__": + sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner')) + import testrunner + + os.environ['TERMFLAGS'] = "-z [%s]:%d,[%s]:%d" % ( + zep_params['local_addr'], zep_params['local_port'], + zep_params['remote_addr'], zep_params['remote_port']) + s = socket.socket(family=socket.AF_INET6, type=socket.SOCK_DGRAM) + s.bind(("::", zep_params['remote_port'])) + res = testrunner.run(testfunc, timeout=1, echo=True, traceback=True) + s.close() + if (res == 0): + print("Run tests successful") + else: + print("Run tests failed") + sys.exit(res)