|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 Embeint Inc |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/kernel.h> |
| 8 | +#include <zephyr/device.h> |
| 9 | +#include <zephyr/net_buf.h> |
| 10 | +#include <zephyr/logging/log.h> |
| 11 | +#include <zephyr/drivers/uart.h> |
| 12 | +#include <zephyr/random/random.h> |
| 13 | + |
| 14 | +/* change this to any other UART peripheral if desired */ |
| 15 | +#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart) |
| 16 | + |
| 17 | +/* Maximum number of packets to generate per iteration */ |
| 18 | +#define LOOP_ITER_MAX_TX 4 |
| 19 | +/* Maximum size of our TX packets */ |
| 20 | +#define MAX_TX_LEN 32 |
| 21 | +#define RX_CHUNK_LEN 32 |
| 22 | + |
| 23 | +/* Buffer pool for our TX payloads */ |
| 24 | +NET_BUF_POOL_DEFINE(tx_pool, LOOP_ITER_MAX_TX, MAX_TX_LEN, 0, NULL); |
| 25 | + |
| 26 | +struct k_fifo tx_queue; |
| 27 | +struct net_buf *tx_pending_buffer; |
| 28 | +uint8_t async_rx_buffer[2][RX_CHUNK_LEN]; |
| 29 | +volatile uint8_t async_rx_buffer_idx; |
| 30 | + |
| 31 | +static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE); |
| 32 | + |
| 33 | +LOG_MODULE_REGISTER(sample, LOG_LEVEL_INF); |
| 34 | + |
| 35 | +static void uart_callback(const struct device *dev, struct uart_event *evt, void *user_data) |
| 36 | +{ |
| 37 | + struct net_buf *buf; |
| 38 | + int rc; |
| 39 | + |
| 40 | + LOG_DBG("EVENT: %d", evt->type); |
| 41 | + |
| 42 | + switch (evt->type) { |
| 43 | + case UART_TX_DONE: |
| 44 | + LOG_DBG("TX complete %p", tx_pending_buffer); |
| 45 | + |
| 46 | + /* Free TX buffer */ |
| 47 | + net_buf_unref(tx_pending_buffer); |
| 48 | + tx_pending_buffer = NULL; |
| 49 | + |
| 50 | + /* Handle any queued buffers */ |
| 51 | + buf = k_fifo_get(&tx_queue, K_NO_WAIT); |
| 52 | + if (buf != NULL) { |
| 53 | + rc = uart_tx(dev, buf->data, buf->len, 0); |
| 54 | + if (rc != 0) { |
| 55 | + LOG_ERR("TX from ISR failed (%d)", rc); |
| 56 | + net_buf_unref(buf); |
| 57 | + } else { |
| 58 | + tx_pending_buffer = buf; |
| 59 | + } |
| 60 | + } |
| 61 | + break; |
| 62 | + case UART_RX_BUF_REQUEST: |
| 63 | + /* Return the next buffer index */ |
| 64 | + LOG_DBG("Providing buffer index %d", async_rx_buffer_idx); |
| 65 | + rc = uart_rx_buf_rsp(dev, async_rx_buffer[async_rx_buffer_idx], |
| 66 | + sizeof(async_rx_buffer[0])); |
| 67 | + __ASSERT_NO_MSG(rc == 0); |
| 68 | + async_rx_buffer_idx = async_rx_buffer_idx ? 0 : 1; |
| 69 | + break; |
| 70 | + case UART_RX_BUF_RELEASED: |
| 71 | + case UART_RX_DISABLED: |
| 72 | + break; |
| 73 | + case UART_RX_RDY: |
| 74 | + LOG_HEXDUMP_INF(evt->data.rx.buf + evt->data.rx.offset, |
| 75 | + evt->data.rx.len, "RX_RDY"); |
| 76 | + break; |
| 77 | + default: |
| 78 | + LOG_WRN("Unhandled event %d", evt->type); |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +int main(void) |
| 83 | +{ |
| 84 | + bool rx_enabled = false; |
| 85 | + struct net_buf *tx_buf; |
| 86 | + int loop_counter = 0; |
| 87 | + uint8_t num_tx; |
| 88 | + int tx_len; |
| 89 | + int rc; |
| 90 | + |
| 91 | + /* Register the async interrupt handler */ |
| 92 | + uart_callback_set(uart_dev, uart_callback, (void *)uart_dev); |
| 93 | + |
| 94 | + while (1) { |
| 95 | + /* Wait a while until the next burst transmission */ |
| 96 | + k_sleep(K_SECONDS(5)); |
| 97 | + |
| 98 | + /* Each loop, try to send a random number of packets */ |
| 99 | + num_tx = (sys_rand32_get() % LOOP_ITER_MAX_TX) + 1; |
| 100 | + LOG_INF("Loop %d: Sending %d packets", loop_counter, num_tx); |
| 101 | + for (int i = 0; i < num_tx; i++) { |
| 102 | + /* Allocate the data packet */ |
| 103 | + tx_buf = net_buf_alloc(&tx_pool, K_FOREVER); |
| 104 | + /* Populate it with data */ |
| 105 | + tx_len = snprintk(tx_buf->data, net_buf_tailroom(tx_buf), |
| 106 | + "Loop %d: Packet: %d\r\n", loop_counter, i); |
| 107 | + net_buf_add(tx_buf, tx_len); |
| 108 | + |
| 109 | + /* Queue packet for transmission */ |
| 110 | + rc = uart_tx(uart_dev, tx_buf->data, tx_buf->len, SYS_FOREVER_US); |
| 111 | + if (rc == 0) { |
| 112 | + /* Store the pending buffer */ |
| 113 | + tx_pending_buffer = tx_buf; |
| 114 | + } else if (rc == -EBUSY) { |
| 115 | + /* Transmission is already in progress */ |
| 116 | + LOG_DBG("Queuing buffer %p", tx_buf); |
| 117 | + k_fifo_put(&tx_queue, tx_buf); |
| 118 | + } else { |
| 119 | + LOG_ERR("Unknown error (%d)", rc); |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + /* Toggle the RX state */ |
| 124 | + if (rx_enabled) { |
| 125 | + uart_rx_disable(uart_dev); |
| 126 | + } else { |
| 127 | + async_rx_buffer_idx = 1; |
| 128 | + uart_rx_enable(uart_dev, async_rx_buffer[0], RX_CHUNK_LEN, 100); |
| 129 | + } |
| 130 | + rx_enabled = !rx_enabled; |
| 131 | + LOG_INF("RX is now %s", rx_enabled ? "enabled" : "disabled"); |
| 132 | + |
| 133 | + loop_counter += 1; |
| 134 | + } |
| 135 | +} |
0 commit comments