diff --git a/tests/ieee802154_submac/Makefile b/tests/ieee802154_submac/Makefile index b0e6ee2faa..198d60d39e 100644 --- a/tests/ieee802154_submac/Makefile +++ b/tests/ieee802154_submac/Makefile @@ -18,11 +18,18 @@ BOARD_WHITELIST := \ # USEMODULE += od USEMODULE += shell +USEMODULE += shell_commands USEMODULE += ps -USEMODULE += event_thread_highest -USEMODULE += netdev_ieee802154_submac +USEMODULE += event_thread USEMODULE += netdev_default +USEMODULE += luid +USEMODULE += l2util +USEMODULE += eui_provider +USEMODULE += ieee802154 +USEMODULE += ieee802154_submac +USEMODULE += ztimer_usec -CFLAGS += -DEVENT_THREAD_HIGHEST_STACKSIZE=1024 +CFLAGS += -DEVENT_THREAD_MEDIUM_STACKSIZE=1024 include $(RIOTBASE)/Makefile.include +include $(RIOTMAKE)/default-radio-settings.inc.mk diff --git a/tests/ieee802154_submac/main.c b/tests/ieee802154_submac/main.c index 09a568ff24..0e25a04279 100644 --- a/tests/ieee802154_submac/main.c +++ b/tests/ieee802154_submac/main.c @@ -32,56 +32,171 @@ #include "net/ieee802154/submac.h" #include "net/ieee802154.h" #include "net/netdev/ieee802154_submac.h" +#include "net/l2util.h" +#include "ztimer.h" #include "common.h" #define MAX_LINE (80) +ieee802154_submac_t submac; /**< IEEE 802.15.4 SubMAC descriptor */ +mutex_t lock; /**< lock used to synchronize SubMAC operation */ +ztimer_t ack_timer; /**< required for the ACK timer */ +eui64_t long_addr; /**< SubMAC extended address */ +network_uint16_t short_addr; /**< SubMAC short address */ -netdev_ieee802154_submac_t netdev_submac; -mutex_t lock; +static void _ev_tx_done_handler(event_t *event); /**< TX Done event handler */ +static void _ev_rx_done_handler(event_t *event); /**< RX Done event handler */ +static void _ev_crc_error_handler(event_t *event); /**< CRC Error event handler */ +static void _ev_bh_request_handler(event_t *event); /**< BH Request event handler */ +static void _ev_ack_timeout_handler(event_t *event); /**< ACK Timeout event handler */ +static void _ev_set_rx_handler(event_t *event); /**< Set RX event handler */ -struct send_ctx { - event_t ev; - iolist_t pkt; +static event_t ev_tx_done = { .handler = _ev_tx_done_handler }; /**< TX Done descriptor */ +static event_t ev_rx_done = { .handler = _ev_rx_done_handler }; /**< RX Done descriptor */ +static event_t ev_crc_error = { .handler = _ev_crc_error_handler }; /**< CRC Error descriptor */ +static event_t ev_bh_request = { .handler = _ev_bh_request_handler }; /**< BH Request descriptor */ +static event_t ev_ack_timeout = { .handler = _ev_ack_timeout_handler }; /**< ACK TO descriptor */ +static event_t ev_set_rx = { .handler = _ev_set_rx_handler }; /**< Set RX descriptor */ + +uint8_t buffer[IEEE802154_FRAME_LEN_MAX]; /* buffer to store IEEE 802.15.4 frames */ +uint8_t seq; /* sequence number of IEEE 802.15.4 frame */ + +struct _reg_container { + int count; /* device index */ }; -static void _send_handler(event_t *ev) -{ - struct send_ctx *ctx = (struct send_ctx*) ev; - netdev_t *dev = &netdev_submac.dev.netdev; +static void submac_rx_done(ieee802154_submac_t *submac); +static void submac_tx_done(ieee802154_submac_t *submac, int status, + ieee802154_tx_info_t *info); - dev->driver->send(dev, &ctx->pkt); -} +static const ieee802154_submac_cb_t _cb = { + .rx_done = submac_rx_done, + .tx_done = submac_tx_done, +}; -void _ack_timeout(void *arg); +static const uint8_t payload[] = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ornare" \ + "lacinia mi elementum interdum ligula."; -uint8_t buffer[IEEE802154_FRAME_LEN_MAX]; -uint8_t seq; +static int print_addr(int argc, char **argv); +static int txtsnd(int argc, char **argv); +static const shell_command_t shell_commands[] = { + { "print_addr", "Print IEEE802.15.4 addresses", print_addr }, + { "txtsnd", "Send IEEE 802.15.4 packet", txtsnd }, + { NULL, NULL, NULL } +}; -static int print_addr(int argc, char **argv) -{ - (void)argc; - (void)argv; - uint8_t *_p = (uint8_t *)&netdev_submac.submac.ext_addr; +/****** SubMAC South Bond API Implementation ******/ - for (int i = 0; i < 8; i++) { - printf("%02x", *_p++); - } - printf("\n"); - return 0; -} - -extern const netdev_driver_t netdev_submac_driver; - -static void _netdev_isr_handler(event_t *event) +static void _ev_tx_done_handler(event_t *event) { (void)event; - netdev_t *netdev = &netdev_submac.dev.netdev; - - netdev->driver->isr(netdev); + mutex_lock(&lock); + ieee802154_submac_tx_done_cb(&submac); + mutex_unlock(&lock); } +static void _ev_rx_done_handler(event_t *event) +{ + (void)event; + mutex_lock(&lock); + ieee802154_submac_rx_done_cb(&submac); + mutex_unlock(&lock); +} + +static void _ev_crc_error_handler(event_t *event) +{ + (void)event; + mutex_lock(&lock); + ieee802154_submac_crc_error_cb(&submac); + mutex_unlock(&lock); +} + +static void _ev_bh_request_handler(event_t *event) +{ + (void)event; + mutex_lock(&lock); + ieee802154_submac_bh_process(&submac); + mutex_unlock(&lock); +} + +static void _ev_ack_timeout_handler(event_t *event) +{ + (void)event; + mutex_lock(&lock); + ieee802154_submac_ack_timeout_fired(&submac); + mutex_unlock(&lock); +} + +void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac, uint16_t us) +{ + (void)submac; + ztimer_set(ZTIMER_USEC, &ack_timer, us); +} + +void ieee802154_submac_ack_timer_cancel(ieee802154_submac_t *submac) +{ + (void)submac; + ztimer_remove(ZTIMER_USEC, &ack_timer); +} + +static void _ack_timeout(void *arg) +{ + (void)arg; + event_post(EVENT_PRIO_HIGHEST, &ev_ack_timeout); +} + +static void _hal_radio_cb(ieee802154_dev_t *dev, ieee802154_trx_ev_t status) +{ + (void)dev; + switch (status) { + case IEEE802154_RADIO_CONFIRM_TX_DONE: + event_post(EVENT_PRIO_HIGHEST, &ev_tx_done); + break; + case IEEE802154_RADIO_INDICATION_RX_DONE: + event_post(EVENT_PRIO_HIGHEST, &ev_rx_done); + break; + case IEEE802154_RADIO_INDICATION_CRC_ERROR: + event_post(EVENT_PRIO_HIGHEST, &ev_crc_error); + break; + default: + break; + } +} + +void ieee802154_submac_bh_request(ieee802154_submac_t *submac) +{ + (void)submac; + event_post(EVENT_PRIO_HIGHEST, &ev_bh_request); +} + +static ieee802154_dev_t *_reg_callback(ieee802154_dev_type_t type, void *opaque) +{ + struct _reg_container *reg = opaque; + + printf("Trying to register "); + switch (type) { + case IEEE802154_DEV_TYPE_CC2538_RF: + printf("cc2538_rf"); + break; + case IEEE802154_DEV_TYPE_NRF802154: + printf("nrf52840"); + break; + } + + puts("."); + if (reg->count > 0) { + puts("For the moment this test only supports one radio"); + return NULL; + } + + puts("Success"); + return &submac.dev; +} + +/****** Helpers ******/ + void _print_addr(uint8_t *addr, size_t addr_len) { for (size_t i = 0; i < addr_len; i++) { @@ -91,18 +206,66 @@ void _print_addr(uint8_t *addr, size_t addr_len) printf("%02x", (unsigned)addr[i]); } } -static event_t _netdev_ev = { .handler = _netdev_isr_handler }; -void recv(netdev_t *dev) +/****** Upper layer implementation ******/ +#define IEEE802154_LONG_ADDRESS_LEN_STR_MAX \ + (sizeof("00:00:00:00:00:00:00:00")) + +static int print_addr(int argc, char **argv) +{ + (void)argc; + (void)argv; + char addr_str[IEEE802154_LONG_ADDRESS_LEN_STR_MAX]; + printf("%s\n", l2util_addr_to_str( + long_addr.uint8, IEEE802154_LONG_ADDRESS_LEN, addr_str)); + return 0; +} + +static void _ev_set_rx_handler(event_t *event) +{ + (void)event; + mutex_lock(&lock); + ieee802154_set_rx(&submac); + mutex_unlock(&lock); +} + +static void submac_tx_done(ieee802154_submac_t *submac, int status, + ieee802154_tx_info_t *info) +{ + (void)info; + (void)submac; + switch (status) { + case TX_STATUS_SUCCESS: + puts("Tx complete"); + break; + case TX_STATUS_FRAME_PENDING: + puts("Tx complete with pending data"); + break; + case TX_STATUS_MEDIUM_BUSY: + puts("Medium Busy"); + break; + case TX_STATUS_NO_ACK: + puts("No ACK"); + break; + default: + break; + } + + /* Schedule the state change. Calling this function directly in the callback + * will return error */ + event_post(EVENT_PRIO_HIGHEST, &ev_set_rx); +} + +static void submac_rx_done(ieee802154_submac_t *submac) { uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN]; int data_len; size_t mhr_len, src_len, dst_len; - netdev_ieee802154_rx_info_t rx_info; le_uint16_t src_pan, dst_pan; + ieee802154_rx_info_t rx_info; putchar('\n'); - data_len = dev->driver->recv(dev, buffer, sizeof(buffer), &rx_info); + data_len = ieee802154_read_frame(submac, buffer, sizeof(buffer), &rx_info); if (data_len < 0) { puts("Couldn't read frame"); return; @@ -184,83 +347,11 @@ void recv(netdev_t *dev) } printf("\n"); printf("RSSI: %i, LQI: %u\n\n", rx_info.rssi, rx_info.lqi); + + /* Schedule the state change. Calling this function directly in the callback + * will return error */ + event_post(EVENT_PRIO_HIGHEST, &ev_set_rx); } -static void _event_cb(netdev_t *dev, netdev_event_t event) -{ - (void)dev; - if (event == NETDEV_EVENT_ISR) { - event_post(EVENT_PRIO_HIGHEST, &_netdev_ev); - } - else { - switch (event) { - case NETDEV_EVENT_RX_COMPLETE: - { - recv(dev); - return; - } - 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: - assert(false); - } - mutex_unlock(&lock); - } -} - -struct _reg_container { - int count; -}; - -static ieee802154_dev_t *_reg_callback(ieee802154_dev_type_t type, void *opaque) -{ - struct _reg_container *reg = opaque; - printf("Trying to register "); - switch(type) { - case IEEE802154_DEV_TYPE_CC2538_RF: - printf("cc2538_rf"); - break; - case IEEE802154_DEV_TYPE_NRF802154: - printf("nrf52840"); - break; - } - - puts("."); - if (reg->count > 0) { - puts("For the moment this test only supports one radio"); - return NULL; - } - - puts("Success"); - return &netdev_submac.submac.dev; -} - -static int _init(void) -{ - netdev_t *dev = &netdev_submac.dev.netdev; - - mutex_init(&lock); - mutex_lock(&lock); - dev->event_callback = _event_cb; - struct _reg_container reg = {0}; - netdev_ieee802154_submac_init(&netdev_submac); - ieee802154_hal_test_init_devs(_reg_callback, ®); - - dev->driver->init(dev); - return 0; -} - -uint8_t payload[] = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ornare lacinia mi elementum interdum ligula."; static int send(uint8_t *dst, size_t dst_len, size_t len) @@ -268,20 +359,20 @@ static int send(uint8_t *dst, size_t dst_len, uint8_t flags; uint8_t mhr[IEEE802154_MAX_HDR_LEN]; int mhr_len; - struct send_ctx ctx = {0}; le_uint16_t src_pan, dst_pan; iolist_t iol_data = { - .iol_base = payload, + .iol_base = (void *)payload, .iol_len = len, .iol_next = NULL, }; - flags = IEEE802154_FCF_TYPE_DATA | 0x20; - src_pan = byteorder_btols(byteorder_htons(0x23)); - dst_pan = byteorder_btols(byteorder_htons(0x23)); - uint8_t src_len = 8; - void *src = &netdev_submac.submac.ext_addr; + flags = IEEE802154_FCF_TYPE_DATA | IEEE802154_FCF_ACK_REQ; + src_pan = byteorder_btols(byteorder_htons(CONFIG_IEEE802154_DEFAULT_PANID)); + dst_pan = byteorder_btols(byteorder_htons(CONFIG_IEEE802154_DEFAULT_PANID)); + + uint8_t src_len = IEEE802154_LONG_ADDRESS_LEN; + void *src = &submac.ext_addr; /* fill MAC header, seq should be set by device */ if ((mhr_len = ieee802154_set_frame_hdr(mhr, src, src_len, @@ -292,85 +383,23 @@ static int send(uint8_t *dst, size_t dst_len, return 1; } - ctx.ev.handler = _send_handler; - ctx.pkt.iol_next = &iol_data; - ctx.pkt.iol_base = mhr; - ctx.pkt.iol_len = mhr_len; + iolist_t pkt; + pkt.iol_next = &iol_data; + pkt.iol_base = mhr; + pkt.iol_len = mhr_len; - event_post(EVENT_PRIO_HIGHEST, &ctx.ev); mutex_lock(&lock); + int res = ieee802154_send(&submac, &pkt); + mutex_unlock(&lock); + if (res < 0) { + puts("Error: Frame couldn't be sent"); + } return 0; } -static inline int _dehex(char c, int default_) +static int txtsnd(int argc, char **argv) { - if ('0' <= c && c <= '9') { - return c - '0'; - } - else if ('A' <= c && c <= 'F') { - return c - 'A' + 10; - } - else if ('a' <= c && c <= 'f') { - return c - 'a' + 10; - } - else { - return default_; - } -} - -static size_t _parse_addr(uint8_t *out, size_t out_len, const char *in) -{ - const char *end_str = in; - uint8_t *out_end = out; - size_t count = 0; - int assert_cell = 1; - - if (!in || !*in) { - return 0; - } - while (end_str[1]) { - ++end_str; - } - - while (end_str >= in) { - int a = 0, b = _dehex(*end_str--, -1); - if (b < 0) { - if (assert_cell) { - return 0; - } - else { - assert_cell = 1; - continue; - } - } - assert_cell = 0; - - if (end_str >= in) { - a = _dehex(*end_str--, 0); - } - - if (++count > out_len) { - return 0; - } - *out_end++ = (a << 4) | b; - } - if (assert_cell) { - return 0; - } - /* out is reversed */ - - while (out < --out_end) { - uint8_t tmp = *out_end; - *out_end = *out; - *out++ = tmp; - } - - return count; -} - -int txtsnd(int argc, char **argv) -{ - uint8_t addr[8]; + uint8_t addr[IEEE802154_LONG_ADDRESS_LEN]; size_t len; size_t res; @@ -379,7 +408,7 @@ int txtsnd(int argc, char **argv) return 1; } - res = _parse_addr(addr, sizeof(addr), argv[1]); + res = l2util_addr_from_str(argv[1], addr); if (res == 0) { puts("Usage: txtsnd "); return 1; @@ -388,11 +417,34 @@ int txtsnd(int argc, char **argv) return send(addr, res, len); } -static const shell_command_t shell_commands[] = { - { "print_addr", "Print IEEE802.15.4 addresses", print_addr }, - { "txtsnd", "Send IEEE 802.15.4 packet", txtsnd }, - { NULL, NULL, NULL } -}; +static int _init(void) +{ + mutex_init(&lock); + + submac.cb = &_cb; + + /* Set the Event Notification */ + submac.dev.cb = _hal_radio_cb; + + ack_timer.callback = _ack_timeout; + ack_timer.arg = NULL; + + luid_base(&long_addr, sizeof(long_addr)); + eui64_set_local(&long_addr); + eui64_clear_group(&long_addr); + eui_short_from_eui64(&long_addr, &short_addr); + + struct _reg_container reg = { 0 }; + ieee802154_hal_test_init_devs(_reg_callback, ®); + + int res = ieee802154_submac_init(&submac, &short_addr, &long_addr); + + if (res < 0) { + return res; + } + + return 0; +} int main(void) {