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
uart_callback(const struct device * dev,struct uart_event * evt,void * user_data)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
main(void)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 }
136