-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
USB Device next cdc acm can get in a deadlock when the host doesn't pull the endpoint data #78160
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(passthrough) | ||
|
||
include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) | ||
target_sources(app PRIVATE src/main.c) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright (c) 2023 Nordic Semiconductor ASA | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
# Source common USB sample options used to initialize new experimental USB | ||
# device stack. The scope of these options is limited to USB samples in project | ||
# tree, you cannot use them in your own application. | ||
source "samples/subsys/usb/common/Kconfig.sample_usbd" | ||
|
||
source "Kconfig.zephyr" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
.. zephyr:code-sample:: passthrough_irq_usb | ||
:name: USB-UART Passthrough | ||
:relevant-api: uart_interface | ||
|
||
Pass data directly between the console and another UART interface. | ||
|
||
Overview | ||
******** | ||
|
||
This sample will connect a physical UART interfaces to a USB uart, as if Zephyr | ||
and the processor were not present. Data read from the console is transmitted | ||
to the "*other*" interface, and data read from the "*other*" interface is | ||
relayed to the console. | ||
|
||
The source code for this sample application can be found at: | ||
:zephyr_file:`samples/subsys/usb/passthrough_irq_usb`. | ||
|
||
Requirements | ||
************ | ||
|
||
#. One USB UART interface, identified as Zephyr's first usb acm interface. | ||
#. A second UART connected to something interesting (e.g: GPS), identified as | ||
the chosen ``uart,passthrough`` device - the pins and baudrate will need to | ||
be configured correctly. | ||
|
||
Building and Running | ||
******************** | ||
|
||
Build and flash the sample as follows, changing ``nucleo_l476rg`` for your | ||
board: | ||
|
||
.. zephyr-app-commands:: | ||
:zephyr-app: samples/drivers/uart/passthrough | ||
:board: nucleo_l476rg | ||
:goals: build flash | ||
:compact: | ||
|
||
Sample Output | ||
============= | ||
|
||
.. code-block:: console | ||
|
||
*** Booting Zephyr OS build zephyr-v3.5.0-2988-gb84bab36b941 *** | ||
Console Device: 0x8003940 | ||
Other Device: 0x800392c | ||
$GNGSA,A,3,31,29,25,26,,,,,,,,,11.15,10.66,3.29,1*06 | ||
$GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,2*0F | ||
$GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,3*0E | ||
$GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,4*09 | ||
$GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,5*08 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* | ||
* Copyright (c) 2021 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
&zephyr_udc0 { | ||
cdc_acm_uart0 { | ||
compatible = "zephyr,cdc-acm-uart"; | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
CONFIG_SERIAL=y | ||
CONFIG_RING_BUFFER=y | ||
CONFIG_UART_INTERRUPT_DRIVEN=y | ||
|
||
CONFIG_USB_DEVICE_STACK_NEXT=y | ||
CONFIG_USBD_CDC_ACM_CLASS=y | ||
|
||
CONFIG_SAMPLE_USBD_PID=0x0001 | ||
CONFIG_SAMPLE_USBD_PRODUCT="USBD CDC ACM sample" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
sample: | ||
name: USB-UART Passthrough | ||
tests: | ||
sample.drivers.uart: | ||
tags: | ||
- serial | ||
- uart | ||
- usb | ||
filter: CONFIG_SERIAL and | ||
CONFIG_UART_INTERRUPT_DRIVEN and | ||
dt_chosen_enabled("uart,passthrough") | ||
harness: keyboard |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
/* | ||
* Copyright (c) 2024 Argentum Systems Ltd. | ||
* Copyright (c) 2024 SynchronicIT BV | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/device.h> | ||
#include <zephyr/drivers/uart.h> | ||
#include <zephyr/sys/ring_buffer.h> | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
|
||
#include <zephyr/usb/usb_device.h> | ||
#include <zephyr/usb/usbd.h> | ||
#include <zephyr/logging/log.h> | ||
LOG_MODULE_REGISTER(passthrough, LOG_LEVEL_INF); | ||
|
||
|
||
Check notice on line 22 in samples/subsys/usb/passthrough_irq_usb/src/main.c GitHub Actions / Run compliance checks on patch series (PR)You may want to run clang-format on this change
|
||
const struct device *const usb_dev = DEVICE_DT_GET(DT_NODELABEL(cdc_acm_uart0)); | ||
const struct device *const uart_dev = DEVICE_DT_GET(DT_CHOSEN(uart_passthrough)); | ||
|
||
#define RING_BUF_SIZE 1024 | ||
|
||
uint8_t ring_buffer[2][RING_BUF_SIZE]; | ||
|
||
struct ring_buf usb_ringbuf; | ||
struct ring_buf uart_ringbuf; | ||
|
||
static inline void print_baudrate(const struct device *dev) | ||
{ | ||
uint32_t baudrate; | ||
int ret; | ||
|
||
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 %u", baudrate); | ||
} | ||
} | ||
|
||
#if defined(CONFIG_USB_DEVICE_STACK_NEXT) | ||
static struct usbd_context *sample_usbd; | ||
K_SEM_DEFINE(dtr_sem, 0, 1); | ||
|
||
static void sample_msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg) | ||
{ | ||
LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); | ||
|
||
if (usbd_can_detect_vbus(ctx)) { | ||
if (msg->type == USBD_MSG_VBUS_READY) { | ||
if (usbd_enable(ctx)) { | ||
LOG_ERR("Failed to enable device support"); | ||
} | ||
} | ||
|
||
if (msg->type == USBD_MSG_VBUS_REMOVED) { | ||
if (usbd_disable(ctx)) { | ||
LOG_ERR("Failed to disable device support"); | ||
} | ||
} | ||
} | ||
|
||
if (msg->type == USBD_MSG_CDC_ACM_CONTROL_LINE_STATE) { | ||
uint32_t dtr = 0U; | ||
|
||
uart_line_ctrl_get(msg->dev, UART_LINE_CTRL_DTR, &dtr); | ||
if (dtr) { | ||
k_sem_give(&dtr_sem); | ||
} | ||
} | ||
|
||
if (msg->type == USBD_MSG_CDC_ACM_LINE_CODING) { | ||
print_baudrate(msg->dev); | ||
} | ||
} | ||
|
||
static int enable_usb_device_next(void) | ||
{ | ||
int err; | ||
|
||
sample_usbd = sample_usbd_init_device(sample_msg_cb); | ||
if (sample_usbd == NULL) { | ||
LOG_ERR("Failed to initialize USB device"); | ||
return -ENODEV; | ||
} | ||
|
||
if (!usbd_can_detect_vbus(sample_usbd)) { | ||
err = usbd_enable(sample_usbd); | ||
if (err) { | ||
LOG_ERR("Failed to enable device support"); | ||
return err; | ||
} | ||
} | ||
|
||
LOG_INF("USB device support enabled"); | ||
|
||
return 0; | ||
} | ||
#endif /* defined(CONFIG_USB_DEVICE_STACK_NEXT) */ | ||
|
||
|
||
static void interrupt_handler(const struct device *dev, void *user_data) | ||
{ | ||
|
||
struct ring_buf *ringbuf_rx; | ||
struct ring_buf *ringbuf_tx; | ||
const struct device *peer = user_data; | ||
|
||
if(dev == usb_dev) { | ||
ringbuf_rx = &uart_ringbuf; | ||
Check notice on line 115 in samples/subsys/usb/passthrough_irq_usb/src/main.c GitHub Actions / Run compliance checks on patch series (PR)You may want to run clang-format on this change
|
||
ringbuf_tx = &usb_ringbuf; | ||
|
||
} else { | ||
ringbuf_rx = &usb_ringbuf; | ||
ringbuf_tx = &uart_ringbuf; | ||
} | ||
|
||
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_rx), sizeof(buffer)); | ||
|
||
if (len == 0) { | ||
ring_buf_get(ringbuf_rx, NULL, buffer); | ||
len = MIN(ring_buf_space_get(ringbuf_rx), 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_rx, 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(peer); | ||
} | ||
} | ||
|
||
if (uart_irq_tx_ready(dev)) { | ||
uint8_t buffer[64]; | ||
int rb_len, send_len; | ||
|
||
rb_len = ring_buf_get(ringbuf_tx, 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) | ||
{ | ||
int ret; | ||
|
||
if (!device_is_ready(uart_dev)) { | ||
LOG_ERR("UART device not ready"); | ||
return 0; | ||
} | ||
|
||
if (!device_is_ready(usb_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 | ||
Check notice on line 190 in samples/subsys/usb/passthrough_irq_usb/src/main.c GitHub Actions / Run compliance checks on patch series (PR)You may want to run clang-format on this change
|
||
|
||
if (ret != 0) { | ||
LOG_ERR("Failed to enable USB"); | ||
return 0; | ||
} | ||
|
||
ring_buf_init(&uart_ringbuf, sizeof(ring_buffer[0]), ring_buffer[0]); | ||
ring_buf_init(&usb_ringbuf, sizeof(ring_buffer[1]), ring_buffer[1]); | ||
|
||
printk("UART Device: %p\n", uart_dev); | ||
printk("USB Device: %p\n", usb_dev); | ||
|
||
uart_irq_callback_user_data_set(uart_dev, interrupt_handler, usb_dev); | ||
uart_irq_callback_user_data_set(usb_dev, interrupt_handler, uart_dev); | ||
|
||
/* Enable rx interrupts */ | ||
uart_irq_rx_enable(uart_dev); | ||
uart_irq_rx_enable(usb_dev); | ||
|
||
for (;;) { | ||
k_msleep(1000); | ||
} | ||
|
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, but we do not need another CDC ACM sample.