blob: e2c118f840ec7f9b748c9f0f815585de7c4cac37 [file] [log] [blame]
/*
* 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 <stdio.h>
#include <string.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/zephyr.h>
#include <zephyr/sys/ring_buffer.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/logging/log.h>
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);
}
}
void 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;
}
}
ret = usb_enable(NULL);
if (ret != 0) {
LOG_ERR("Failed to enable USB");
return;
}
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);
}