Files
buzzer/firmware/src/uart.c
2026-03-07 08:51:50 +01:00

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;
}