doc: usb: describe CDC ACM virtual UART IRQ API behavior

In general, it mirrors what is described in Interrupt-driven API
documentation, but here a little more explicitly and with a simplified
example, so that we can finally chisel it into the stone.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
Johann Fischer 2024-07-04 12:47:06 +02:00 committed by Fabio Baltieri
parent 64ee885950
commit 1867e71df2

View file

@ -223,3 +223,62 @@ instance (``n``) and is used as an argument to the :c:func:`usbd_register_class`
+-----------------------------------+-------------------------+-------------------------+
| Bluetooth HCI USB transport layer | :ref:`bt_hci_raw` | :samp:`bt_hci_{n}` |
+-----------------------------------+-------------------------+-------------------------+
CDC ACM UART
============
CDC ACM implements a virtual UART controller and provides Interrupt-driven UART
API and Polling UART API.
Interrupt-driven UART API
-------------------------
Internally the implementation uses two ringbuffers, these take over the
function of the TX/RX FIFOs (TX/RX buffers) from the :ref:`uart_interrupt_api`.
As described in the :ref:`uart_interrupt_api`, the functions
:c:func:`uart_irq_update()`, :c:func:`uart_irq_is_pending`,
:c:func:`uart_irq_rx_ready()`, :c:func:`uart_irq_tx_ready()`
:c:func:`uart_fifo_read()`, and :c:func:`uart_fifo_fill()`
should be called from the interrupt handler, see
:c:func:`uart_irq_callback_user_data_set()`. To prevent undefined behaviour,
the implementation of these functions checks in what context they are called
and fails if it is not an interrupt handler.
Also, as described in the UART API, :c:func:`uart_irq_is_pending`
:c:func:`uart_irq_rx_ready()`, and :c:func:`uart_irq_tx_ready()`
can only be called after :c:func:`uart_irq_update()`.
Simplified, the interrupt handler should look something like:
.. code-block:: c
static void interrupt_handler(const struct device *dev, void *user_data)
{
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
if (uart_irq_rx_ready(dev)) {
int len;
int n;
/* ... */
n = uart_fifo_read(dev, buffer, len);
/* ... */
}
if (uart_irq_tx_ready(dev)) {
int len;
int n;
/* ... */
n = uart_fifo_fill(dev, buffer, len);
/* ... */
}
}
All these functions are not directly dependent on the status of the USB device.
Filling the TX FIFO does not mean that data is being sent to the host. And
successfully reading the RX FIFO does not mean that the device is still
connected to the host. If there is space in the TX FIFO, and the TX interrupt
is enabled, :c:func:`uart_irq_tx_ready()` will succeed. If there is data in the
RX FIFO, and the RX interrupt is enabled, :c:func:`uart_irq_rx_ready()` will
succeed. Function :c:func:`uart_irq_tx_complete()` is not implemented yet.