zephyr/drivers/serial/uart_pipe.c

106 lines
2 KiB
C
Raw Permalink Normal View History

/** @file
* @brief Pipe UART driver
*
* A pipe UART driver allowing application to handle all aspects of received
* protocol data.
*/
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(uart_pipe);
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/uart_pipe.h>
#include <zephyr/sys/printk.h>
static const struct device *const uart_pipe_dev =
DEVICE_DT_GET(DT_CHOSEN(zephyr_uart_pipe));
static uint8_t *recv_buf;
static size_t recv_buf_len;
static uart_pipe_recv_cb app_cb;
static size_t recv_off;
static void uart_pipe_rx(const struct device *dev)
{
/* As per the API, the interrupt may be an edge so keep
* reading from the FIFO until it's empty.
*/
for (;;) {
int avail = recv_buf_len - recv_off;
int got;
got = uart_fifo_read(uart_pipe_dev, recv_buf + recv_off, avail);
if (got <= 0) {
break;
}
LOG_HEXDUMP_DBG(recv_buf + recv_off, got, "RX");
/*
* Call application callback with received data. Application
* may provide new buffer or alter data offset.
*/
recv_off += got;
recv_buf = app_cb(recv_buf, &recv_off);
}
}
static void uart_pipe_isr(const struct device *dev, void *user_data)
{
ARG_UNUSED(user_data);
uart_irq_update(dev);
if (uart_irq_rx_ready(dev)) {
uart_pipe_rx(dev);
}
}
int uart_pipe_send(const uint8_t *data, int len)
{
LOG_HEXDUMP_DBG(data, len, "TX");
while (len--) {
uart_poll_out(uart_pipe_dev, *data++);
}
return 0;
}
static void uart_pipe_setup(const struct device *uart)
{
uint8_t c;
uart_irq_rx_disable(uart);
uart_irq_tx_disable(uart);
/* Drain the fifo */
while (uart_fifo_read(uart, &c, 1)) {
continue;
}
uart: add ISR callback mechanism for UART drivers The peripherals utilizing UART were required to register their own ISR rountines. This means that all those peripherals drivers need to know which IRQ line is attached to a UART controller, and all the other config values required to register a ISR. This causes scalibility issue as every board and peripherals have to define those values. Another reason for this patch is to support virtual serial ports. Virtual serial ports do not have physical interrupt lines to attach, and thus would not work. This patch adds a simple callback mechanism, which calls a function when UART interrupts are triggered. The low level plumbing still needs to be done by the peripheral drivers, as these drivers may need to access low level capability of UART to function correctly. This simply moves the interrupt setup into the UART drivers themselves. By doing this, the peripheral drivers do not need to know all the config values to properly setup the interrupts and attaching the ISR. One drawback is that this adds to the interrupt latency. Note that this patch breaks backward compatibility in terms of setting up interrupt for UART controller. How to use UART is still the same. This also addresses the following issues: () UART driver for Atmel SAM3 currently does not support interrupts. So remove the code from vector table. This will be updated when there is interrupt support for the driver. () Corrected some config options for Stellaris UART driver. This was tested with samples/shell on Arduino 101, and on QEMU (Cortex-M3 and x86). Origin: original code Change-Id: Ib4593d8ccd711f4e97d388c7293205d213be1aec Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2016-03-03 19:14:50 +01:00
uart_irq_callback_set(uart, uart_pipe_isr);
uart_irq_rx_enable(uart);
}
void uart_pipe_register(uint8_t *buf, size_t len, uart_pipe_recv_cb cb)
{
recv_buf = buf;
recv_buf_len = len;
app_cb = cb;
if (device_is_ready(uart_pipe_dev)) {
uart_pipe_setup(uart_pipe_dev);
}
}