blob: 4276bb2a12e39869eda5287837a8b6f710b15202 [file] [log] [blame]
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Sample echo app for CDC ACM class
*
* 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/kernel.h>
#include <zephyr/sys/ring_buffer.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/usb/usbd.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(cdc_acm_echo, LOG_LEVEL_INF);
#define RING_BUF_SIZE 1024
uint8_t ring_buffer[RING_BUF_SIZE];
struct ring_buf ringbuf;
#if defined(CONFIG_USB_DEVICE_STACK_NEXT)
USBD_CONFIGURATION_DEFINE(config_1,
USB_SCD_SELF_POWERED,
200);
USBD_DESC_LANG_DEFINE(sample_lang);
USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, "ZEPHYR");
USBD_DESC_PRODUCT_DEFINE(sample_product, "Zephyr USBD CDC ACM");
USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF");
USBD_DEVICE_DEFINE(sample_usbd,
DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)),
0x2fe3, 0x0001);
static int enable_usb_device_next(void)
{
int err;
err = usbd_add_descriptor(&sample_usbd, &sample_lang);
if (err) {
LOG_ERR("Failed to initialize language descriptor (%d)", err);
return err;
}
err = usbd_add_descriptor(&sample_usbd, &sample_mfr);
if (err) {
LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err);
return err;
}
err = usbd_add_descriptor(&sample_usbd, &sample_product);
if (err) {
LOG_ERR("Failed to initialize product descriptor (%d)", err);
return err;
}
err = usbd_add_descriptor(&sample_usbd, &sample_sn);
if (err) {
LOG_ERR("Failed to initialize SN descriptor (%d)", err);
return err;
}
err = usbd_add_configuration(&sample_usbd, &config_1);
if (err) {
LOG_ERR("Failed to add configuration (%d)", err);
return err;
}
err = usbd_register_class(&sample_usbd, "cdc_acm_0", 1);
if (err) {
LOG_ERR("Failed to register CDC ACM class (%d)", err);
return err;
}
err = usbd_init(&sample_usbd);
if (err) {
LOG_ERR("Failed to initialize device support");
return err;
}
err = usbd_enable(&sample_usbd);
if (err) {
LOG_ERR("Failed to enable device support");
return err;
}
LOG_DBG("USB device support enabled");
return 0;
}
#endif /* IS_ENABLED(CONFIG_USB_DEVICE_STACK_NEXT) */
static void interrupt_handler(const struct device *dev, void *user_data)
{
ARG_UNUSED(user_data);
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
if (uart_irq_rx_ready(dev)) {
int recv_len, rb_len;
uint8_t buffer[64];
size_t len = MIN(ring_buf_space_get(&ringbuf),
sizeof(buffer));
recv_len = uart_fifo_read(dev, buffer, len);
if (recv_len < 0) {
LOG_ERR("Failed to read UART FIFO");
recv_len = 0;
};
rb_len = ring_buf_put(&ringbuf, buffer, recv_len);
if (rb_len < recv_len) {
LOG_ERR("Drop %u bytes", recv_len - rb_len);
}
LOG_DBG("tty fifo -> ringbuf %d bytes", rb_len);
if (rb_len) {
uart_irq_tx_enable(dev);
}
}
if (uart_irq_tx_ready(dev)) {
uint8_t buffer[64];
int rb_len, send_len;
rb_len = ring_buf_get(&ringbuf, buffer, sizeof(buffer));
if (!rb_len) {
LOG_DBG("Ring buffer empty, disable TX IRQ");
uart_irq_tx_disable(dev);
continue;
}
send_len = uart_fifo_fill(dev, buffer, rb_len);
if (send_len < rb_len) {
LOG_ERR("Drop %d bytes", rb_len - send_len);
}
LOG_DBG("ringbuf -> tty fifo %d bytes", send_len);
}
}
}
int main(void)
{
const struct device *dev;
uint32_t baudrate, dtr = 0U;
int ret;
dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
if (!device_is_ready(dev)) {
LOG_ERR("CDC ACM device not ready");
return 0;
}
#if defined(CONFIG_USB_DEVICE_STACK_NEXT)
ret = enable_usb_device_next();
#else
ret = usb_enable(NULL);
#endif
if (ret != 0) {
LOG_ERR("Failed to enable USB");
return 0;
}
ring_buf_init(&ringbuf, sizeof(ring_buffer), ring_buffer);
LOG_INF("Wait for DTR");
while (true) {
uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
if (dtr) {
break;
} else {
/* Give CPU resources to low priority threads. */
k_sleep(K_MSEC(100));
}
}
LOG_INF("DTR set");
/* 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_WRN("Failed to set DCD, ret code %d", ret);
}
ret = uart_line_ctrl_set(dev, UART_LINE_CTRL_DSR, 1);
if (ret) {
LOG_WRN("Failed to set DSR, ret code %d", ret);
}
/* Wait 100ms for the host to do all settings */
k_msleep(100);
ret = uart_line_ctrl_get(dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
if (ret) {
LOG_WRN("Failed to get baudrate, ret code %d", ret);
} else {
LOG_INF("Baudrate detected: %d", baudrate);
}
uart_irq_callback_set(dev, interrupt_handler);
/* Enable rx interrupts */
uart_irq_rx_enable(dev);
return 0;
}