1 /*
2 * Copyright (c) 2019 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/uart.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/ring_buffer.h>
13
14 #include <zephyr/usb/usb_device.h>
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(cdc_acm_echo, LOG_LEVEL_INF);
17
18 const struct device *const uart_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
19
20 #define RING_BUF_SIZE 1024
21 uint8_t ring_buffer[RING_BUF_SIZE];
22
23 struct ring_buf ringbuf;
24
25 static bool rx_throttled;
26
print_baudrate(const struct device * dev)27 static inline void print_baudrate(const struct device *dev)
28 {
29 uint32_t baudrate;
30 int ret;
31
32 ret = uart_line_ctrl_get(dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
33 if (ret) {
34 LOG_WRN("Failed to get baudrate, ret code %d", ret);
35 } else {
36 LOG_INF("Baudrate %u", baudrate);
37 }
38 }
39
interrupt_handler(const struct device * dev,void * user_data)40 static void interrupt_handler(const struct device *dev, void *user_data)
41 {
42 ARG_UNUSED(user_data);
43
44 while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
45 if (!rx_throttled && uart_irq_rx_ready(dev)) {
46 int recv_len, rb_len;
47 uint8_t buffer[64];
48 size_t len = MIN(ring_buf_space_get(&ringbuf),
49 sizeof(buffer));
50
51 if (len == 0) {
52 /* Throttle because ring buffer is full */
53 uart_irq_rx_disable(dev);
54 rx_throttled = true;
55 continue;
56 }
57
58 recv_len = uart_fifo_read(dev, buffer, len);
59 if (recv_len < 0) {
60 LOG_ERR("Failed to read UART FIFO");
61 recv_len = 0;
62 };
63
64 rb_len = ring_buf_put(&ringbuf, buffer, recv_len);
65 if (rb_len < recv_len) {
66 LOG_ERR("Drop %u bytes", recv_len - rb_len);
67 }
68
69 LOG_DBG("tty fifo -> ringbuf %d bytes", rb_len);
70 if (rb_len) {
71 uart_irq_tx_enable(dev);
72 }
73 }
74
75 if (uart_irq_tx_ready(dev)) {
76 uint8_t buffer[64];
77 int rb_len, send_len;
78
79 rb_len = ring_buf_get(&ringbuf, buffer, sizeof(buffer));
80 if (!rb_len) {
81 LOG_DBG("Ring buffer empty, disable TX IRQ");
82 uart_irq_tx_disable(dev);
83 continue;
84 }
85
86 if (rx_throttled) {
87 uart_irq_rx_enable(dev);
88 rx_throttled = false;
89 }
90
91 send_len = uart_fifo_fill(dev, buffer, rb_len);
92 if (send_len < rb_len) {
93 LOG_ERR("Drop %d bytes", rb_len - send_len);
94 }
95
96 LOG_DBG("ringbuf -> tty fifo %d bytes", send_len);
97 }
98 }
99 }
100
main(void)101 int main(void)
102 {
103 int ret;
104
105 if (!device_is_ready(uart_dev)) {
106 LOG_ERR("CDC ACM device not ready");
107 return 0;
108 }
109
110 ret = usb_enable(NULL);
111 if (ret != 0) {
112 LOG_ERR("Failed to enable USB");
113 return 0;
114 }
115
116 ring_buf_init(&ringbuf, sizeof(ring_buffer), ring_buffer);
117
118 LOG_INF("Wait for DTR");
119
120 while (true) {
121 uint32_t dtr = 0U;
122
123 uart_line_ctrl_get(uart_dev, UART_LINE_CTRL_DTR, &dtr);
124 if (dtr) {
125 break;
126 }
127
128 k_sleep(K_MSEC(100));
129 }
130
131 LOG_INF("DTR set");
132
133 /* They are optional, we use them to test the interrupt endpoint */
134 ret = uart_line_ctrl_set(uart_dev, UART_LINE_CTRL_DCD, 1);
135 if (ret) {
136 LOG_WRN("Failed to set DCD, ret code %d", ret);
137 }
138
139 ret = uart_line_ctrl_set(uart_dev, UART_LINE_CTRL_DSR, 1);
140 if (ret) {
141 LOG_WRN("Failed to set DSR, ret code %d", ret);
142 }
143
144 /* Wait 100ms for the host to do all settings */
145 k_msleep(100);
146
147 print_baudrate(uart_dev);
148
149 uart_irq_callback_set(uart_dev, interrupt_handler);
150 /* Enable rx interrupts */
151 uart_irq_rx_enable(uart_dev);
152
153 return 0;
154 }
155