135 lines
3.3 KiB
C
135 lines
3.3 KiB
C
// uart.c
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/drivers/uart.h>
|
|
#include <zephyr/sys/ring_buffer.h>
|
|
|
|
LOG_MODULE_REGISTER(uart, LOG_LEVEL_INF);
|
|
|
|
#define RX_RING_BUF_SIZE 1024
|
|
#define TX_RING_BUF_SIZE 1024
|
|
|
|
const struct device *const uart_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
|
|
|
|
RING_BUF_ITEM_DECLARE(rx_ringbuf, RX_RING_BUF_SIZE);
|
|
RING_BUF_ITEM_DECLARE(tx_ringbuf, TX_RING_BUF_SIZE);
|
|
K_SEM_DEFINE(tx_done_sem, 0, 1);
|
|
K_SEM_DEFINE(rx_ready_sem, 0, 1);
|
|
|
|
static void uart_isr(const struct device *dev, void *user_data)
|
|
{
|
|
ARG_UNUSED(user_data);
|
|
|
|
if (!uart_irq_update(dev))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (uart_irq_rx_ready(dev))
|
|
{
|
|
uint8_t *data_ptr;
|
|
uint32_t claimed_len;
|
|
int recv_len;
|
|
|
|
claimed_len = ring_buf_put_claim(&rx_ringbuf, &data_ptr, RX_RING_BUF_SIZE);
|
|
|
|
if (claimed_len > 0)
|
|
{
|
|
recv_len = uart_fifo_read(dev, data_ptr, claimed_len);
|
|
ring_buf_put_finish(&rx_ringbuf, recv_len);
|
|
if (recv_len > 0)
|
|
{
|
|
k_sem_give(&rx_ready_sem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uart_irq_rx_disable(dev);
|
|
}
|
|
}
|
|
if (uart_irq_tx_ready(dev))
|
|
{
|
|
uint8_t *data_ptr;
|
|
uint32_t claim_len;
|
|
int written;
|
|
|
|
claim_len = ring_buf_get_claim(&tx_ringbuf, &data_ptr, ring_buf_size_get(&tx_ringbuf));
|
|
|
|
if (claim_len > 0)
|
|
{
|
|
written = uart_fifo_fill(dev, data_ptr, claim_len);
|
|
ring_buf_get_finish(&tx_ringbuf, written);
|
|
}
|
|
else
|
|
{
|
|
uart_irq_tx_disable(dev);
|
|
}
|
|
k_sem_give(&tx_done_sem);
|
|
}
|
|
}
|
|
|
|
int uart_init(void)
|
|
{
|
|
if (!device_is_ready(uart_dev))
|
|
{
|
|
LOG_ERR("UART device not ready");
|
|
return -ENODEV;
|
|
}
|
|
|
|
uart_irq_callback_set(uart_dev, uart_isr);
|
|
uart_irq_rx_enable(uart_dev);
|
|
|
|
LOG_INF("UART device initialized");
|
|
return 0;
|
|
}
|
|
|
|
int uart_write(const uint8_t *data, size_t len, k_timeout_t timeout)
|
|
{
|
|
size_t written_total = 0;
|
|
k_sem_reset(&tx_done_sem);
|
|
|
|
while (written_total < len)
|
|
{
|
|
uint32_t written = ring_buf_put(&tx_ringbuf, &data[written_total], len - written_total);
|
|
written_total += written;
|
|
|
|
if (written > 0)
|
|
{
|
|
uart_irq_tx_enable(uart_dev);
|
|
}
|
|
|
|
if (written_total < len)
|
|
{
|
|
int ret = k_sem_take(&tx_done_sem, timeout);
|
|
if (ret != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
return written_total;
|
|
}
|
|
|
|
int uart_write_string(const char *str, k_timeout_t timeout)
|
|
{
|
|
return uart_write((const uint8_t *)str, strlen(str), timeout);
|
|
}
|
|
|
|
int uart_read(uint8_t *data, size_t len, k_timeout_t timeout)
|
|
{
|
|
uint32_t read_len = ring_buf_get(&rx_ringbuf, data, len);
|
|
|
|
if (read_len == 0 && !K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
|
|
k_sem_reset(&rx_ready_sem);
|
|
if (ring_buf_is_empty(&rx_ringbuf)) {
|
|
if (k_sem_take(&rx_ready_sem, timeout) != 0) {
|
|
return -ETIMEDOUT;
|
|
}
|
|
}
|
|
read_len = ring_buf_get(&rx_ringbuf, data, len);
|
|
}
|
|
if (read_len > 0) {
|
|
uart_irq_rx_enable(uart_dev);
|
|
}
|
|
return read_len;
|
|
} |