1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Sample app for CDC ACM class driver
10  *
11  * Sample app for USB CDC ACM class driver. The received data is echoed back
12  * to the serial port.
13  */
14 
15 #include <stdio.h>
16 #include <string.h>
17 #include <zephyr/device.h>
18 #include <zephyr/drivers/uart.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/sys/ring_buffer.h>
21 
22 #include <zephyr/usb/usb_device.h>
23 #include <zephyr/logging/log.h>
24 LOG_MODULE_REGISTER(cdc_acm_composite, LOG_LEVEL_INF);
25 
26 #define RING_BUF_SIZE	(64 * 2)
27 
28 uint8_t buffer0[RING_BUF_SIZE];
29 uint8_t buffer1[RING_BUF_SIZE];
30 
31 struct serial_peer {
32 	const struct device *dev;
33 	struct serial_peer *data;
34 	struct ring_buf rb;
35 };
36 
37 #define DEFINE_SERIAL_PEER(node_id) { .dev = DEVICE_DT_GET(node_id), },
38 static struct serial_peer peers[] = {
39 	DT_FOREACH_STATUS_OKAY(zephyr_cdc_acm_uart, DEFINE_SERIAL_PEER)
40 };
41 
42 BUILD_ASSERT(ARRAY_SIZE(peers) >= 2, "Not enough CDC ACM instances");
43 
interrupt_handler(const struct device * dev,void * user_data)44 static void interrupt_handler(const struct device *dev, void *user_data)
45 {
46 	struct serial_peer *peer = user_data;
47 
48 	while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
49 		LOG_DBG("dev %p peer %p", dev, peer);
50 
51 		if (uart_irq_rx_ready(dev)) {
52 			uint8_t buf[64];
53 			int read;
54 			size_t wrote;
55 			struct ring_buf *rb = &peer->data->rb;
56 
57 			read = uart_fifo_read(dev, buf, sizeof(buf));
58 			if (read < 0) {
59 				LOG_ERR("Failed to read UART FIFO");
60 				read = 0;
61 			};
62 
63 			wrote = ring_buf_put(rb, buf, read);
64 			if (wrote < read) {
65 				LOG_ERR("Drop %zu bytes", read - wrote);
66 			}
67 
68 			LOG_DBG("dev %p -> dev %p send %zu bytes",
69 				dev, peer->dev, wrote);
70 			if (wrote) {
71 				uart_irq_tx_enable(peer->dev);
72 			}
73 		}
74 
75 		if (uart_irq_tx_ready(dev)) {
76 			uint8_t buf[64];
77 			size_t wrote, len;
78 
79 			len = ring_buf_get(&peer->rb, buf, sizeof(buf));
80 			if (!len) {
81 				LOG_DBG("dev %p TX buffer empty", dev);
82 				uart_irq_tx_disable(dev);
83 			} else {
84 				wrote = uart_fifo_fill(dev, buf, len);
85 				LOG_DBG("dev %p wrote len %zu", dev, wrote);
86 			}
87 		}
88 	}
89 }
90 
uart_line_set(const struct device * dev)91 static void uart_line_set(const struct device *dev)
92 {
93 	uint32_t baudrate;
94 	int ret;
95 
96 	/* They are optional, we use them to test the interrupt endpoint */
97 	ret = uart_line_ctrl_set(dev, UART_LINE_CTRL_DCD, 1);
98 	if (ret) {
99 		LOG_DBG("Failed to set DCD, ret code %d", ret);
100 	}
101 
102 	ret = uart_line_ctrl_set(dev, UART_LINE_CTRL_DSR, 1);
103 	if (ret) {
104 		LOG_DBG("Failed to set DSR, ret code %d", ret);
105 	}
106 
107 	/* Wait 1 sec for the host to do all settings */
108 	k_busy_wait(1000000);
109 
110 	ret = uart_line_ctrl_get(dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
111 	if (ret) {
112 		LOG_DBG("Failed to get baudrate, ret code %d", ret);
113 	} else {
114 		LOG_DBG("Baudrate detected: %d", baudrate);
115 	}
116 }
117 
main(void)118 int main(void)
119 {
120 	uint32_t dtr = 0U;
121 	int ret;
122 
123 	for (int idx = 0; idx < ARRAY_SIZE(peers); idx++) {
124 		if (!device_is_ready(peers[idx].dev)) {
125 			LOG_ERR("CDC ACM device %s is not ready",
126 				peers[idx].dev->name);
127 			return 0;
128 		}
129 	}
130 
131 	ret = usb_enable(NULL);
132 	if (ret != 0) {
133 		LOG_ERR("Failed to enable USB");
134 		return 0;
135 	}
136 
137 	LOG_INF("Wait for DTR");
138 
139 	while (1) {
140 		uart_line_ctrl_get(peers[0].dev, UART_LINE_CTRL_DTR, &dtr);
141 		if (dtr) {
142 			break;
143 		}
144 
145 		k_sleep(K_MSEC(100));
146 	}
147 
148 	while (1) {
149 		uart_line_ctrl_get(peers[1].dev, UART_LINE_CTRL_DTR, &dtr);
150 		if (dtr) {
151 			break;
152 		}
153 
154 		k_sleep(K_MSEC(100));
155 	}
156 
157 	LOG_INF("DTR set, start test");
158 
159 	uart_line_set(peers[0].dev);
160 	uart_line_set(peers[1].dev);
161 
162 	peers[0].data = &peers[1];
163 	peers[1].data = &peers[0];
164 
165 	ring_buf_init(&peers[0].rb, sizeof(buffer0), buffer0);
166 	ring_buf_init(&peers[1].rb, sizeof(buffer1), buffer1);
167 
168 	uart_irq_callback_user_data_set(peers[1].dev, interrupt_handler, &peers[0]);
169 	uart_irq_callback_user_data_set(peers[0].dev, interrupt_handler, &peers[1]);
170 
171 	/* Enable rx interrupts */
172 	uart_irq_rx_enable(peers[0].dev);
173 	uart_irq_rx_enable(peers[1].dev);
174 	return 0;
175 }
176