modem: backend: uart_async: Use single ring buffer

Use single ring buffer and protect it with a spinlock as it is
shared between backend and UART thread (ISR). This is simpler
than the double ring buffer setup.

The receive idle timeout has also been made configurable
instead of being a hardcoded value.

Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
This commit is contained in:
Bjarki Arge Andreasen 2023-11-13 19:15:30 +01:00 committed by Carles Cufí
parent 7cf2b0fc9d
commit 6f1d49e7b3
3 changed files with 28 additions and 56 deletions

View File

@ -31,7 +31,8 @@ struct modem_backend_uart_isr {
struct modem_backend_uart_async {
uint8_t *receive_bufs[2];
uint32_t receive_buf_size;
struct ring_buf receive_rdb[2];
struct ring_buf receive_rb;
struct k_spinlock receive_rb_lock;
uint8_t *transmit_buf;
uint32_t transmit_buf_size;
struct k_work rx_disabled_work;

View File

@ -28,6 +28,10 @@ config MODEM_BACKEND_UART_ASYNC_TRANSMIT_TIMEOUT_MS
int "Modem UART async transmit timeout in milliseconds"
default 100
config MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS
int "Modem UART async receive idle timeout in milliseconds"
default 30
endif
endif # MODEM_BACKEND_UART

View File

@ -16,7 +16,6 @@ LOG_MODULE_DECLARE(modem_backend_uart);
#define MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT (1)
#define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT (2)
#define MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT (3)
#define MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT (4)
static void modem_backend_uart_async_flush(struct modem_backend_uart *backend)
{
@ -43,31 +42,11 @@ static bool modem_backend_uart_async_is_closed(struct modem_backend_uart *backen
return false;
}
static uint8_t modem_backend_uart_async_rx_rbuf_used_index(struct modem_backend_uart *backend)
{
return atomic_test_bit(&backend->async.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT);
}
static void modem_backend_uart_async_rx_rbuf_used_swap(struct modem_backend_uart *backend)
{
uint8_t rx_rbuf_index = modem_backend_uart_async_rx_rbuf_used_index(backend);
if (rx_rbuf_index) {
atomic_clear_bit(&backend->async.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT);
} else {
atomic_set_bit(&backend->async.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_RBUF_USED_INDEX_BIT);
}
}
static void modem_backend_uart_async_event_handler(const struct device *dev,
struct uart_event *evt, void *user_data)
{
struct modem_backend_uart *backend = (struct modem_backend_uart *) user_data;
uint8_t receive_rb_used_index;
k_spinlock_key_t key;
uint32_t received;
switch (evt->type) {
@ -123,18 +102,19 @@ static void modem_backend_uart_async_event_handler(const struct device *dev,
break;
case UART_RX_RDY:
receive_rb_used_index = modem_backend_uart_async_rx_rbuf_used_index(backend);
received = ring_buf_put(&backend->async.receive_rdb[receive_rb_used_index],
&evt->data.rx.buf[evt->data.rx.offset],
evt->data.rx.len);
key = k_spin_lock(&backend->async.receive_rb_lock);
received = ring_buf_put(&backend->async.receive_rb,
&evt->data.rx.buf[evt->data.rx.offset],
evt->data.rx.len);
if (received < evt->data.rx.len) {
ring_buf_reset(&backend->async.receive_rdb[receive_rb_used_index]);
ring_buf_reset(&backend->async.receive_rb);
k_spin_unlock(&backend->async.receive_rb_lock, key);
LOG_WRN("Receive buffer overrun");
break;
}
k_spin_unlock(&backend->async.receive_rb_lock, key);
k_work_submit(&backend->receive_ready_work);
break;
@ -163,8 +143,7 @@ static int modem_backend_uart_async_open(void *data)
atomic_set(&backend->async.state, 0);
modem_backend_uart_async_flush(backend);
ring_buf_reset(&backend->async.receive_rdb[0]);
ring_buf_reset(&backend->async.receive_rdb[1]);
ring_buf_reset(&backend->async.receive_rb);
/* Reserve receive buffer 0 */
atomic_set_bit(&backend->async.state,
@ -175,7 +154,8 @@ static int modem_backend_uart_async_open(void *data)
* used to store received data.
*/
ret = uart_rx_enable(backend->uart, backend->async.receive_bufs[0],
backend->async.receive_buf_size, 3000);
backend->async.receive_buf_size,
CONFIG_MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS * 1000L);
if (ret < 0) {
return ret;
@ -224,29 +204,19 @@ static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, siz
static int modem_backend_uart_async_receive(void *data, uint8_t *buf, size_t size)
{
struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
k_spinlock_key_t key;
uint32_t received;
uint8_t receive_rdb_unused;
bool empty;
received = 0;
receive_rdb_unused = modem_backend_uart_async_rx_rbuf_used_index(backend) ? 0 : 1;
key = k_spin_lock(&backend->async.receive_rb_lock);
received = ring_buf_get(&backend->async.receive_rb, buf, size);
empty = ring_buf_is_empty(&backend->async.receive_rb);
k_spin_unlock(&backend->async.receive_rb_lock, key);
/* Read data from unused ring double buffer first */
received += ring_buf_get(&backend->async.receive_rdb[receive_rdb_unused], buf, size);
if (ring_buf_is_empty(&backend->async.receive_rdb[receive_rdb_unused]) == false) {
return (int)received;
if (!empty) {
k_work_submit(&backend->receive_ready_work);
}
/* Swap receive ring double buffer */
modem_backend_uart_async_rx_rbuf_used_swap(backend);
/* Read data from previously used buffer */
receive_rdb_unused = modem_backend_uart_async_rx_rbuf_used_index(backend) ? 0 : 1;
received += ring_buf_get(&backend->async.receive_rdb[receive_rdb_unused],
&buf[received], (size - received));
return (int)received;
}
@ -288,18 +258,15 @@ void modem_backend_uart_async_init(struct modem_backend_uart *backend,
{
uint32_t receive_buf_size_quarter = config->receive_buf_size / 4;
/* Split receive buffer into 4 buffers, use 2 parts for UART receive double buffer */
/* Use half the receive buffer for UART receive buffers */
backend->async.receive_buf_size = receive_buf_size_quarter;
backend->async.receive_bufs[0] = &config->receive_buf[0];
backend->async.receive_bufs[1] = &config->receive_buf[receive_buf_size_quarter];
/* Use remaining 2 parts for receive double ring buffer */
ring_buf_init(&backend->async.receive_rdb[0], receive_buf_size_quarter,
/* Use half the receive buffer for the received data ring buffer */
ring_buf_init(&backend->async.receive_rb, (receive_buf_size_quarter * 2),
&config->receive_buf[receive_buf_size_quarter * 2]);
ring_buf_init(&backend->async.receive_rdb[1], receive_buf_size_quarter,
&config->receive_buf[receive_buf_size_quarter * 3]);
backend->async.transmit_buf = config->transmit_buf;
backend->async.transmit_buf_size = config->transmit_buf_size;
k_work_init(&backend->async.rx_disabled_work, modem_backend_uart_async_notify_closed);