From 3095afafd2eb049d577e478c316d95b1c28e735a Mon Sep 17 00:00:00 2001 From: MrKevinWeiss Date: Mon, 21 Mar 2022 14:29:11 +0100 Subject: [PATCH] sys/test_utils: add netdev ieee802154 minimal processing --- sys/Makefile | 3 + sys/Makefile.include | 4 + .../test_utils/netdev_ieee802154_minimal.h | 116 +++++++ sys/test_utils/Makefile.dep | 3 + .../netdev_ieee802154_minimal/Makefile | 3 + .../netdev_ieee802154_minimal/Makefile.dep | 7 + .../netdev_ieee802154_minimal.c | 243 +++++++++++++++ .../netdev_ieee802154_minimal_internal.h | 47 +++ .../shell_commands.c | 284 ++++++++++++++++++ 9 files changed, 710 insertions(+) create mode 100644 sys/include/test_utils/netdev_ieee802154_minimal.h create mode 100644 sys/test_utils/netdev_ieee802154_minimal/Makefile create mode 100644 sys/test_utils/netdev_ieee802154_minimal/Makefile.dep create mode 100644 sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal.c create mode 100644 sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal_internal.h create mode 100644 sys/test_utils/netdev_ieee802154_minimal/shell_commands.c diff --git a/sys/Makefile b/sys/Makefile index 8ba54ef260..aa7e941897 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -194,6 +194,9 @@ endif ifneq (,$(filter test_utils_netdev_eth_minimal,$(USEMODULE))) DIRS += test_utils/netdev_eth_minimal endif +ifneq (,$(filter test_utils_netdev_ieee802154_minimal,$(USEMODULE))) + DIRS += test_utils/netdev_ieee802154_minimal +endif ifneq (,$(filter test_utils_print_stack_usage,$(USEMODULE))) DIRS += test_utils/print_stack_usage endif diff --git a/sys/Makefile.include b/sys/Makefile.include index 4e90267c10..91b24e55fc 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -139,6 +139,10 @@ ifneq (,$(filter test_utils_result_output,$(USEMODULE))) include $(RIOTBASE)/sys/test_utils/result_output/Makefile.include endif +ifneq (,$(filter test_utils_netdev_ieee802154_minimal,$(USEMODULE))) + CFLAGS += -DCONFIG_NETDEV_REGISTER_SIGNAL +endif + ifneq (,$(filter ztimer,$(USEMODULE))) include $(RIOTBASE)/sys/ztimer/Makefile.include endif diff --git a/sys/include/test_utils/netdev_ieee802154_minimal.h b/sys/include/test_utils/netdev_ieee802154_minimal.h new file mode 100644 index 0000000000..fcc7fce631 --- /dev/null +++ b/sys/include/test_utils/netdev_ieee802154_minimal.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 HAW Hamburg + * + * 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 test_utils_netdev_ieee802154_minimal Minimal netdev IEEE 802.15.4 device processing + * @ingroup sys + * + * @{ + * @file + * @brief Provides basic functionalities to interact with an + * IEEE 802.15.4 networking device which implements the + * @ref drivers_netdev_api. + * + * To use the functionalities, include the module + * `USEMODULE += test_utils_netdev_ieee802154_minimal`. + * The test application should provide: + * - device initialization, via the implementation of @ref netdev_ieee802154_minimal_init_devs + * - number of devices to test, via the definition of @ref NETDEV_IEEE802154_MINIMAL_NUMOF + * in `init_dev.h` + * + * @author Kevin Weiss + */ + +#ifndef TEST_UTILS_NETDEV_IEEE802154_MINIMAL_H +#define TEST_UTILS_NETDEV_IEEE802154_MINIMAL_H + +#include "net/netdev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef DOXYGEN +/** + * @brief Maximum number of devices to handle. + * @note Should be provided by the application via `init_dev.h`. + */ +#define NETDEV_IEEE802154_MINIMAL_NUMOF +#endif + +/** + * @brief Device-under-test initialization function. + * @note Should be implemented by the test application + * + * @param[in] cb Callback to be set to @ref netdev::event_callback + * + * @retval 0 on success + * @retval != 0 on error + */ +int netdev_ieee802154_minimal_init_devs(netdev_event_cb_t cb); + +/** + * @brief Initialize the module. + * + * @retval 0 on success + * @retval != 0 on error + */ +int netdev_ieee802154_minimal_init(void); + +/** + * @brief Send a IEEE 802.15.4 frame + * This is wrapper for the internal netdev send function, that ensures + * all netdev functions are called from the same thread. It is safe + * to call this function from anywhere. + * + * @param[in] dev Pointer to the netdev descriptor. + * @param[in] pkt Packet to be sent. + * + * @retval 0 on success + * @retval != 0 on error + */ +int netdev_ieee802154_minimal_send(struct netdev *dev, iolist_t *pkt); + +/** + * @brief Get an option from netdev minimal. + * This is wrapper for the internal netdev get function, that ensures + * all netdev functions are called from the same thread. It is safe + * to call this function from anywhere. + * + * @param[in] dev Pointer to the netdev descriptor. + * @param[in] opt The netopt option + * @param[out] data Buffer to store the option + * @param[in] max_len Maximum length of the buffer + * + * @retval 0 on success + * @retval != 0 on error + */ +int netdev_ieee802154_minimal_get(struct netdev *dev, netopt_t opt, void *data, size_t max_len); + +/** + * @brief Set an option to netdev minimal. + * This is wrapper for the internal netdev set function, that ensures + * all netdev functions are called from the same thread. It is safe + * to call this function from anywhere. + * + * @param[in] dev Pointer to the netdev descriptor. + * @param[in] opt The netopt option + * @param[in] data Pointer to the data to be set + * @param[in] len Length of the data + * + * @retval 0 on success + * @retval != 0 on error + */ +int netdev_ieee802154_minimal_set(struct netdev *dev, netopt_t opt, void *data, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_UTILS_NETDEV_IEEE802154_MINIMAL_H */ +/** @} */ diff --git a/sys/test_utils/Makefile.dep b/sys/test_utils/Makefile.dep index ad9c48b3c9..e3fd404169 100644 --- a/sys/test_utils/Makefile.dep +++ b/sys/test_utils/Makefile.dep @@ -1,6 +1,9 @@ ifneq (,$(filter test_utils_result_output,$(USEMODULE))) include $(RIOTBASE)/sys/test_utils/result_output/Makefile.dep endif +ifneq (,$(filter test_utils_netdev_ieee802154_minimal,$(USEMODULE))) + include $(RIOTBASE)/sys/test_utils/netdev_ieee802154_minimal/Makefile.dep +endif ifneq (,$(filter test_utils_interactive_sync,$(USEMODULE))) USEMODULE += stdin endif diff --git a/sys/test_utils/netdev_ieee802154_minimal/Makefile b/sys/test_utils/netdev_ieee802154_minimal/Makefile new file mode 100644 index 0000000000..f67f2bcde7 --- /dev/null +++ b/sys/test_utils/netdev_ieee802154_minimal/Makefile @@ -0,0 +1,3 @@ +MODULE = test_utils_netdev_ieee802154_minimal + +include $(RIOTBASE)/Makefile.base diff --git a/sys/test_utils/netdev_ieee802154_minimal/Makefile.dep b/sys/test_utils/netdev_ieee802154_minimal/Makefile.dep new file mode 100644 index 0000000000..41a448eb5a --- /dev/null +++ b/sys/test_utils/netdev_ieee802154_minimal/Makefile.dep @@ -0,0 +1,7 @@ +USEMODULE += event +USEMODULE += event_thread +USEMODULE += l2util +USEMODULE += od +USEMODULE += od_string +USEMODULE += shell +USEMODULE += netdev diff --git a/sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal.c b/sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal.c new file mode 100644 index 0000000000..f4e80509c8 --- /dev/null +++ b/sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2022 HAW Hamburg + * + * 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 test_utils_netdev_ieee802154_minimal + * @{ + * + * @file + * @brief Implementation of netdev IEEE 802.15.4 minimal test utility + * module + * + * @author Leandro Lanzieri + */ +#include + +#include "event.h" +#include "event/thread.h" +#include "od.h" +#include "net/ieee802154.h" +#include "net/l2util.h" +#include "net/netdev.h" +#include "net/netdev/ieee802154.h" +#include "test_utils/netdev_ieee802154_minimal.h" +#include "netdev_ieee802154_minimal_internal.h" + +/* provided by the test application */ +#include "init_dev.h" + +device_reg_entry_t _devices[NETDEV_IEEE802154_MINIMAL_NUMOF]; +static uint8_t _buffer[IEEE802154_FRAME_LEN_MAX]; +static char _addr_str[IEEE802154_LONG_ADDRESS_LEN * 3]; + +struct event_pkt_desc { + event_t event; + struct netdev *dev; + iolist_t *pkt; + int res; +}; + +struct event_getset_desc { + event_t event; + struct netdev *dev; + netopt_t opt; + void *data; + size_t len; + int res; +}; + +static void _post_send_event(event_t *event) +{ + struct event_pkt_desc *desc = (struct event_pkt_desc*) event; + struct netdev *dev = desc->dev; + + int res = dev->driver->send(dev, desc->pkt); + desc->res = res; +} + +static void _post_get_event(event_t *event) +{ + struct event_getset_desc *desc = (struct event_getset_desc*) event; + struct netdev *dev = desc->dev; + netopt_t opt = desc->opt; + void *data = desc->data; + size_t max_len = desc->len; + + int res = dev->driver->get(dev, opt, data, max_len); + desc->res = res; +} + +static void _post_set_event(event_t *event) +{ + struct event_getset_desc *desc = (struct event_getset_desc*) event; + struct netdev *dev = desc->dev; + netopt_t opt = desc->opt; + void *data = desc->data; + size_t len = desc->len; + + int res = dev->driver->set(dev, opt, data, len); + desc->res = res; +} + +void _recv(netdev_t *dev) +{ + uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN]; + int data_len, src_len, dst_len; + size_t mhr_len; + netdev_ieee802154_rx_info_t rx_info; + le_uint16_t src_pan, dst_pan; + + putchar('\n'); + /* receive the frame */ + data_len = dev->driver->recv(dev, _buffer, sizeof(_buffer), &rx_info); + mhr_len = ieee802154_get_frame_hdr_len(_buffer); + if (mhr_len == 0) { + puts("Unexpected MHR for incoming packet"); + return; + } + + /* get and print addresses */ + dst_len = ieee802154_get_dst(_buffer, dst, &dst_pan); + src_len = ieee802154_get_src(_buffer, src, &src_pan); + + l2util_addr_to_str(dst, dst_len, _addr_str); + printf("Dest. PAN: 0x%04x\n", byteorder_ltohs(dst_pan)); + printf("Dest. addr.: %s\n", _addr_str); + + l2util_addr_to_str(src, src_len, _addr_str); + printf("Src. PAN: 0x%04x\n", byteorder_ltohs(src_pan)); + printf("Src. addr.: %s\n", _addr_str); + + /* check frame type */ + switch (_buffer[0] & IEEE802154_FCF_TYPE_MASK) { + case IEEE802154_FCF_TYPE_BEACON: + puts("BEACON"); + break; + case IEEE802154_FCF_TYPE_DATA: + puts("DATA"); + break; + case IEEE802154_FCF_TYPE_ACK: + puts("ACK"); + break; + case IEEE802154_FCF_TYPE_MACCMD: + puts("MACCMD"); + break; + default: + puts("UNKNOWN"); + break; + } + + /* print flag information */ + printf("\nSecurity: %s", _buffer[0] & IEEE802154_FCF_SECURITY_EN ? "1, " : "0, "); + + printf("Frame pend.: %s", _buffer[0] & IEEE802154_FCF_FRAME_PEND ? "1, " : "0, "); + + printf("ACK req.: %s", _buffer[0] & IEEE802154_FCF_ACK_REQ ? "1, " : "0, "); + + printf("PAN comp.:%s", _buffer[0] & IEEE802154_FCF_PAN_COMP ? "1, " : "0, "); + + printf("Version: "); + printf("%u, ", (unsigned)((_buffer[1] & IEEE802154_FCF_VERS_MASK) >> 4)); + + printf("Seq.: %u\n", (unsigned)ieee802154_get_seq(_buffer)); + + printf("RSSI: %i, LQI: %u\n\n", rx_info.rssi, rx_info.lqi); + + /* dump the payload */ + od_hex_dump(_buffer + mhr_len, data_len - mhr_len, 0); +} + +static void _isr_event_handler(event_t *event) +{ + /* recover the netdev from the event */ + device_reg_entry_t *netdev_event = container_of(event, device_reg_entry_t, event); + netdev_t *netdev = netdev_event->dev; + netdev->driver->isr(netdev); +} + +static void _event_cb(netdev_t *dev, netdev_event_t event) +{ + device_reg_entry_t *device = dev->context; + + switch (event) { + case NETDEV_EVENT_ISR: + event_post(EVENT_PRIO_HIGHEST, &device->event); + break; + + case NETDEV_EVENT_RX_COMPLETE: + _recv(dev); + break; + + case NETDEV_EVENT_TX_COMPLETE: + puts("Tx complete"); + break; + + case NETDEV_EVENT_TX_COMPLETE_DATA_PENDING: + puts("Tx complete (with pending data)"); + break; + + case NETDEV_EVENT_TX_MEDIUM_BUSY: + puts("Medium busy"); + break; + + case NETDEV_EVENT_TX_NOACK: + puts("No ACK"); + break; + + default: + printf("Event: %d\n", event); + break; + } +} + +/* Implement netdev_register_signal hook to associate registered devices to specific event + * structures. + */ +void netdev_register_signal(struct netdev *dev, netdev_type_t type, uint8_t index) +{ + (void) type; + + if (index > NETDEV_IEEE802154_MINIMAL_NUMOF) { + return; + } + printf("Device %d registered (type: %d)\n", index, type); + dev->context = &_devices[index]; + _devices[index].dev = dev; + _devices[index].event.handler = _isr_event_handler; +} + +int netdev_ieee802154_minimal_init(void) +{ + return netdev_ieee802154_minimal_init_devs(_event_cb); +} + +int netdev_ieee802154_minimal_send(struct netdev *dev, iolist_t *pkt) +{ + struct event_pkt_desc desc = {.event.handler=_post_send_event, .pkt = pkt, + .dev = dev}; + event_post(EVENT_PRIO_HIGHEST, (event_t*) &desc); + return desc.res; +} + +int netdev_ieee802154_minimal_get(struct netdev *dev, netopt_t opt, void *data, size_t max_len) +{ + struct event_getset_desc desc = {.event.handler = _post_get_event, .opt = opt, + .data = data, .len = max_len, .dev = dev}; + event_post(EVENT_PRIO_HIGHEST, (event_t*) &desc); + return desc.res; +} + +int netdev_ieee802154_minimal_set(struct netdev *dev, netopt_t opt, void *data, size_t len) +{ + struct event_getset_desc desc = {.event.handler = _post_set_event, .opt = opt, + .data = data, .len = len, .dev = dev}; + event_post(EVENT_PRIO_HIGHEST, (event_t*) &desc); + return desc.res; +} + +/** @} */ diff --git a/sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal_internal.h b/sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal_internal.h new file mode 100644 index 0000000000..7d53508e39 --- /dev/null +++ b/sys/test_utils/netdev_ieee802154_minimal/netdev_ieee802154_minimal_internal.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 HAW Hamburg + * + * 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 test_utils_netdev_ieee802154_minimal + * + * @{ + * @file + * @brief Internal definitions for the netdev_ieee802154_minimal module + * + * @author Leandro Lanzieri + */ + +#ifndef NETDEV_IEEE802154_MINIMAL_INTERNAL_H +#define NETDEV_IEEE802154_MINIMAL_INTERNAL_H + +#include "net/netdev.h" +#include "event.h" +#include "init_dev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN + +typedef struct { + event_t event; /**< event to serve ISR */ + netdev_t *dev; /**< pointer to the device */ +} device_reg_entry_t; + +extern device_reg_entry_t _devices[NETDEV_IEEE802154_MINIMAL_NUMOF]; + +#endif /* DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* NETDEV_IEEE802154_MINIMAL_INTERNAL_H */ + +/** @} */ diff --git a/sys/test_utils/netdev_ieee802154_minimal/shell_commands.c b/sys/test_utils/netdev_ieee802154_minimal/shell_commands.c new file mode 100644 index 0000000000..f155b1def5 --- /dev/null +++ b/sys/test_utils/netdev_ieee802154_minimal/shell_commands.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2022 HAW Hamburg + * + * 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 test_utils_netdev_ieee802154_minimal + * @{ + * + * @file + * @brief Shell commands for netdev Eth minimal test utility module + * + * @author Leandro Lanzieri + */ + +#include +#include +#include +#include + +#include "iolist.h" +#include "kernel_defines.h" +#include "net/netdev/ieee802154.h" +#include "net/ieee802154.h" +#include "net/l2util.h" +#include "od.h" +#include "shell.h" + +#include "netdev_ieee802154_minimal_internal.h" +#include "test_utils/netdev_ieee802154_minimal.h" +#include "init_dev.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +static char _addr_str[IEEE802154_LONG_ADDRESS_LEN * 3]; + +static int send(int iface, le_uint16_t dst_pan, uint8_t *dst_addr, + size_t dst_len, char *data); + +int ifconfig_list(int idx) +{ + int res; + uint8_t tmp[IEEE802154_LONG_ADDRESS_LEN]; + netdev_t *netdev = _devices[idx].dev; + netdev_ieee802154_t *dev = container_of(netdev, netdev_ieee802154_t, netdev); + + netopt_enable_t enable_val; + uint16_t u16_val; + + printf("Iface %3d HWaddr: ", idx); + res = netdev_ieee802154_minimal_get(netdev, NETOPT_ADDRESS, tmp, IEEE802154_SHORT_ADDRESS_LEN); + l2util_addr_to_str(tmp, IEEE802154_SHORT_ADDRESS_LEN, _addr_str); + printf("%s", _addr_str); + + printf(", Long HWaddr: "); + res = netdev_ieee802154_minimal_get(netdev, NETOPT_ADDRESS_LONG, tmp, IEEE802154_LONG_ADDRESS_LEN); + l2util_addr_to_str(tmp, IEEE802154_LONG_ADDRESS_LEN, _addr_str); + printf("%s", _addr_str); + + printf(", PAN: 0x%04x", dev->pan); + + res = netdev_ieee802154_minimal_get(netdev, NETOPT_ADDR_LEN, &u16_val, sizeof(u16_val)); + if (res == -ENOTSUP) { + puts("\n Address length: ENOTSUP"); + } + else if (res < 0) { + printf("\n Address length: %i", (int)res); + return 1; + } + else { + printf("\n Address length: %u", (unsigned)u16_val); + } + + res = netdev_ieee802154_minimal_get(netdev, NETOPT_SRC_LEN, &u16_val, sizeof(u16_val)); + if (res == -ENOTSUP) { + puts(", Source address length: ENOTSUP"); + } + else if (res < 0) { + printf(", Source address length: %i", (int)res); + return 1; + } + else { + printf(", Source address length: %u", (unsigned)u16_val); + } + + res = netdev_ieee802154_minimal_get(netdev, NETOPT_MAX_PDU_SIZE, &u16_val, sizeof(u16_val)); + if (res == -ENOTSUP) { + puts(", Max.Payload: ENOTSUP"); + } + else if (res < 0) { + printf(", Max.Payload: %i", (int)res); + return 1; + } + else { + printf(", Max.Payload: %u", (unsigned)u16_val); + } + printf("\n Channel: %u", dev->chan); + + res = netdev_ieee802154_minimal_get(netdev, NETOPT_CHANNEL_PAGE, &u16_val, sizeof(u16_val)); + if (res == -ENOTSUP) { + puts(", Ch.page: ENOTSUP"); + } + else if (res < 0) { + printf(", Ch.page: %i", (int)res); + return 1; + } + else { + printf(", Ch.page: %u", (unsigned)u16_val); + } + + res = netdev_ieee802154_minimal_get(netdev, NETOPT_TX_POWER, &u16_val, sizeof(u16_val)); + if (res == -ENOTSUP) { + puts(", TXPower: ENOTSUP"); + } + else if (res < 0) { + printf(", TXPower: %i", (int)res); + return 1; + } + else { + printf(", TXPower: %u", (unsigned)u16_val); + } + res = netdev_ieee802154_minimal_get(netdev, NETOPT_IS_WIRED, &u16_val, sizeof(u16_val)); + if (res < 0) { + puts(", wireless"); + } + else { + puts(", wired"); + } + + printf(" "); + res = netdev_ieee802154_minimal_get(netdev, NETOPT_PRELOADING, &enable_val, + sizeof(netopt_enable_t)); + if ((res > 0) && (enable_val == NETOPT_ENABLE)) { + printf(" PRELOAD"); + } + res = netdev_ieee802154_minimal_get(netdev, NETOPT_AUTOACK, &enable_val, + sizeof(netopt_enable_t)); + if ((res > 0) && (enable_val == NETOPT_ENABLE)) { + printf(" AUTOACK"); + } + res = netdev_ieee802154_minimal_get(netdev, NETOPT_RAWMODE, &enable_val, + sizeof(netopt_enable_t)); + if ((res > 0) && (enable_val == NETOPT_ENABLE)) { + printf(" RAW"); + } + res = netdev_ieee802154_minimal_get(netdev, NETOPT_AUTOCCA, &enable_val, + sizeof(netopt_enable_t)); + if ((res > 0) && (enable_val == NETOPT_ENABLE)) { + printf(" AUTOCCA"); + } + res = netdev_ieee802154_minimal_get(netdev, NETOPT_CSMA, &enable_val, + sizeof(netopt_enable_t)); + if ((res > 0) && (enable_val == NETOPT_ENABLE)) { + printf(" CSMA"); + } + puts(""); + + return 0; +} + +int cmd_ifconfig(int argc, char **argv) +{ + (void)argc; + (void)argv; + for (unsigned int i = 0; i < NETDEV_IEEE802154_MINIMAL_NUMOF; i++) { + ifconfig_list(i); + } + return 0; +} + +static void txtsnd_usage(char *cmd_name) +{ + printf("usage: %s [] \n", cmd_name); +} + +static int cmd_txtsnd(int argc, char **argv) +{ + char *text; + uint8_t addr[IEEE802154_LONG_ADDRESS_LEN]; + int iface, idx = 2; + size_t res; + le_uint16_t pan = { 0 }; + + switch (argc) { + case 4: + break; + case 5: + res = l2util_addr_from_str(argv[idx++], pan.u8); + if ((res == 0) || (res > sizeof(pan))) { + txtsnd_usage(argv[0]); + return 1; + } + pan.u16 = byteorder_swaps(pan.u16); + break; + default: + txtsnd_usage(argv[0]); + return 1; + } + + iface = atoi(argv[1]); + res = l2util_addr_from_str(argv[idx++], addr); + if (res == 0) { + txtsnd_usage(argv[0]); + return 1; + } + text = argv[idx++]; + return send(iface, pan, addr, res, text); +} + +static int send(int iface, le_uint16_t dst_pan, uint8_t *dst, size_t dst_len, + char *data) +{ + int res; + netdev_ieee802154_t *dev; + uint8_t *src; + size_t src_len; + uint8_t mhr[IEEE802154_MAX_HDR_LEN]; + uint8_t flags; + le_uint16_t src_pan; + + if (((unsigned)iface) > (NETDEV_IEEE802154_MINIMAL_NUMOF - 1)) { + printf("txtsnd: %d is not an interface\n", iface); + return 1; + } + + iolist_t iol_data = { + .iol_base = data, + .iol_len = strlen(data) + }; + + dev = container_of(_devices[iface].dev, netdev_ieee802154_t, netdev); + flags = (uint8_t)(dev->flags & NETDEV_IEEE802154_SEND_MASK); + flags |= IEEE802154_FCF_TYPE_DATA; + src_pan = byteorder_btols(byteorder_htons(dev->pan)); + if (dst_pan.u16 == 0) { + dst_pan = src_pan; + } + if (dev->flags & NETDEV_IEEE802154_SRC_MODE_LONG) { + src_len = 8; + src = dev->long_addr; + } + else { + src_len = 2; + src = dev->short_addr; + } + /* fill MAC header, seq should be set by device */ + if ((res = ieee802154_set_frame_hdr(mhr, src, src_len, + dst, dst_len, + src_pan, dst_pan, + flags, dev->seq++)) < 0) { + puts("txtsnd: Error preperaring frame"); + return 1; + } + + iolist_t iol_hdr = { + .iol_next = &iol_data, + .iol_base = mhr, + .iol_len = (size_t)res + }; + + be_uint16_t _dst_pan = byteorder_ltobs(dst_pan); + l2util_addr_to_str(dst, dst_len, _addr_str); + printf("txtsnd: sending %u bytes to %s", (unsigned)iol_data.iol_len, _addr_str); + l2util_addr_to_str((uint8_t*) &_dst_pan, sizeof(dst_pan), _addr_str); + printf(" (PAN: %s)\n", _addr_str); + + res = netdev_ieee802154_minimal_send(&dev->netdev, &iol_hdr); + + if (res < 0) { + puts("txtsnd: Error on sending"); + return 1; + } + return 0; +} + +/* declare shell commands */ +SHELL_COMMAND(ifconfig, "Configure the device", cmd_ifconfig); +SHELL_COMMAND(txtsnd, "Send an IEEE 802.15.4 packet", cmd_txtsnd); + +/** @} */