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