/* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Sample app for CDC ACM class driver * * Sample app for USB CDC ACM class driver. The received data is echoed back * to the serial port. */ #include #include #include #include #include #include #include #include LOG_MODULE_REGISTER(cdc_acm_composite, LOG_LEVEL_INF); #define RING_BUF_SIZE (64 * 2) uint8_t buffer0[RING_BUF_SIZE]; uint8_t buffer1[RING_BUF_SIZE]; struct serial_peer { const struct device *dev; struct serial_peer *data; struct ring_buf rb; }; #define DEFINE_SERIAL_PEER(node_id) { .dev = DEVICE_DT_GET(node_id), }, static struct serial_peer peers[] = { DT_FOREACH_STATUS_OKAY(zephyr_cdc_acm_uart, DEFINE_SERIAL_PEER) }; BUILD_ASSERT(ARRAY_SIZE(peers) >= 2, "Not enough CDC ACM instances"); static void interrupt_handler(const struct device *dev, void *user_data) { struct serial_peer *peer = user_data; while (uart_irq_update(dev) && uart_irq_is_pending(dev)) { LOG_DBG("dev %p peer %p", dev, peer); if (uart_irq_rx_ready(dev)) { uint8_t buf[64]; int read; size_t wrote; struct ring_buf *rb = &peer->data->rb; read = uart_fifo_read(dev, buf, sizeof(buf)); if (read < 0) { LOG_ERR("Failed to read UART FIFO"); read = 0; }; wrote = ring_buf_put(rb, buf, read); if (wrote < read) { LOG_ERR("Drop %zu bytes", read - wrote); } LOG_DBG("dev %p -> dev %p send %zu bytes", dev, peer->dev, wrote); if (wrote) { uart_irq_tx_enable(peer->dev); } } if (uart_irq_tx_ready(dev)) { uint8_t buf[64]; size_t wrote, len; len = ring_buf_get(&peer->rb, buf, sizeof(buf)); if (!len) { LOG_DBG("dev %p TX buffer empty", dev); uart_irq_tx_disable(dev); } else { wrote = uart_fifo_fill(dev, buf, len); LOG_DBG("dev %p wrote len %zu", dev, wrote); } } } } static void uart_line_set(const struct device *dev) { uint32_t baudrate; int ret; /* They are optional, we use them to test the interrupt endpoint */ ret = uart_line_ctrl_set(dev, UART_LINE_CTRL_DCD, 1); if (ret) { LOG_DBG("Failed to set DCD, ret code %d", ret); } ret = uart_line_ctrl_set(dev, UART_LINE_CTRL_DSR, 1); if (ret) { LOG_DBG("Failed to set DSR, ret code %d", ret); } /* Wait 1 sec for the host to do all settings */ k_busy_wait(1000000); ret = uart_line_ctrl_get(dev, UART_LINE_CTRL_BAUD_RATE, &baudrate); if (ret) { LOG_DBG("Failed to get baudrate, ret code %d", ret); } else { LOG_DBG("Baudrate detected: %d", baudrate); } } int main(void) { uint32_t dtr = 0U; int ret; for (int idx = 0; idx < ARRAY_SIZE(peers); idx++) { if (!device_is_ready(peers[idx].dev)) { LOG_ERR("CDC ACM device %s is not ready", peers[idx].dev->name); return 0; } } ret = usb_enable(NULL); if (ret != 0) { LOG_ERR("Failed to enable USB"); return 0; } LOG_INF("Wait for DTR"); while (1) { uart_line_ctrl_get(peers[0].dev, UART_LINE_CTRL_DTR, &dtr); if (dtr) { break; } k_sleep(K_MSEC(100)); } while (1) { uart_line_ctrl_get(peers[1].dev, UART_LINE_CTRL_DTR, &dtr); if (dtr) { break; } k_sleep(K_MSEC(100)); } LOG_INF("DTR set, start test"); uart_line_set(peers[0].dev); uart_line_set(peers[1].dev); peers[0].data = &peers[1]; peers[1].data = &peers[0]; ring_buf_init(&peers[0].rb, sizeof(buffer0), buffer0); ring_buf_init(&peers[1].rb, sizeof(buffer1), buffer1); uart_irq_callback_user_data_set(peers[1].dev, interrupt_handler, &peers[0]); uart_irq_callback_user_data_set(peers[0].dev, interrupt_handler, &peers[1]); /* Enable rx interrupts */ uart_irq_rx_enable(peers[0].dev); uart_irq_rx_enable(peers[1].dev); return 0; }