Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions include/zephyr/modem/backend/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,42 @@ struct modem_backend_uart_isr {
uint32_t transmit_buf_put_limit;
};

struct modem_backend_uart_async_common {
uint8_t *transmit_buf;
uint32_t transmit_buf_size;
struct k_work rx_disabled_work;
atomic_t state;
};

#ifdef CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC

struct rx_queue_event {
uint8_t *buf;
size_t len;
};

struct modem_backend_uart_async {
struct modem_backend_uart_async_common common;
struct k_mem_slab rx_slab;
struct k_msgq rx_queue;
struct rx_queue_event rx_event;
struct rx_queue_event rx_queue_buf[CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC_BUFFER_COUNT];
uint32_t rx_buf_size;
uint8_t rx_buf_count;
};

#else

struct modem_backend_uart_async {
struct modem_backend_uart_async_common common;
uint8_t *receive_bufs[2];
uint32_t receive_buf_size;
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;
atomic_t state;
};

#endif /* CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC */

struct modem_backend_uart {
const struct device *uart;
struct modem_pipe pipe;
Expand All @@ -60,7 +85,7 @@ struct modem_backend_uart {

struct modem_backend_uart_config {
const struct device *uart;
uint8_t *receive_buf;
uint8_t *receive_buf __aligned(sizeof(uint32_t));
uint32_t receive_buf_size;
uint8_t *transmit_buf;
uint32_t transmit_buf_size;
Expand Down
5 changes: 4 additions & 1 deletion subsys/modem/backends/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ zephyr_library()
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_TTY modem_backend_tty.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART modem_backend_uart.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART_ISR modem_backend_uart_isr.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART_ASYNC modem_backend_uart_async.c)
if(CONFIG_MODEM_BACKEND_UART_ASYNC)
zephyr_library_sources_ifdef(CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC modem_backend_uart_async_hwfc.c)
zephyr_library_sources_ifndef(CONFIG_MODEM_BACKEND_UART_ASYNC_HWFC modem_backend_uart_async.c)
endif()
15 changes: 14 additions & 1 deletion subsys/modem/backends/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ config MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS
int "Modem async UART receive idle timeout in milliseconds"
default 30

endif
config MODEM_BACKEND_UART_ASYNC_HWFC
bool "Hardware flow control (HWFC) for the modem async UART backend"
select EXPERIMENTAL

if MODEM_BACKEND_UART_ASYNC_HWFC

config MODEM_BACKEND_UART_ASYNC_HWFC_BUFFER_COUNT
int "Modem async UART HWFC buffer count"
range 2 4
default 3

endif # MODEM_BACKEND_UART_ASYNC_HWFC

endif # MODEM_BACKEND_UART_ASYNC

endif # MODEM_BACKEND_UART
4 changes: 3 additions & 1 deletion subsys/modem/backends/modem_backend_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ struct modem_pipe *modem_backend_uart_init(struct modem_backend_uart *backend,

#ifdef CONFIG_MODEM_BACKEND_UART_ASYNC
if (modem_backend_uart_async_is_supported(backend)) {
modem_backend_uart_async_init(backend, config);
if (modem_backend_uart_async_init(backend, config)) {
return NULL;
}
return &backend->pipe;
}
#endif /* CONFIG_MODEM_BACKEND_UART_ASYNC */
Expand Down
65 changes: 36 additions & 29 deletions subsys/modem/backends/modem_backend_uart_async.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@

static bool modem_backend_uart_async_is_uart_stopped(struct modem_backend_uart *backend)
{
if (!atomic_test_bit(&backend->async.state,
if (!atomic_test_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT) &&
!atomic_test_bit(&backend->async.state,
!atomic_test_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT) &&
!atomic_test_bit(&backend->async.state,
!atomic_test_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT) &&
!atomic_test_bit(&backend->async.state,
!atomic_test_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) {
return true;

Check notice on line 33 in subsys/modem/backends/modem_backend_uart_async.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/modem/backends/modem_backend_uart_async.c:33 - MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT) && + MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT) && !atomic_test_bit(&backend->async.common.state, - MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT) && + MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT) && !atomic_test_bit(&backend->async.common.state, - MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT) && + MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT) && !atomic_test_bit(&backend->async.common.state, - MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) { + MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) {
}

return false;
Expand All @@ -38,7 +38,7 @@

static bool modem_backend_uart_async_is_open(struct modem_backend_uart *backend)
{
return atomic_test_bit(&backend->async.state,
return atomic_test_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
}

Expand All @@ -56,7 +56,7 @@

switch (evt->type) {
case UART_TX_DONE:
atomic_clear_bit(&backend->async.state,
atomic_clear_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
k_work_submit(&backend->transmit_idle_work);
break;
Expand All @@ -65,22 +65,22 @@
if (modem_backend_uart_async_is_open(backend)) {
LOG_WRN("Transmit aborted (%zu sent)", evt->data.tx.len);
}
atomic_clear_bit(&backend->async.state,
atomic_clear_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
k_work_submit(&backend->transmit_idle_work);

break;

case UART_RX_BUF_REQUEST:
if (!atomic_test_and_set_bit(&backend->async.state,
if (!atomic_test_and_set_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT)) {
uart_rx_buf_rsp(backend->uart, backend->async.receive_bufs[0],
backend->async.receive_buf_size);

break;
}

if (!atomic_test_and_set_bit(&backend->async.state,
if (!atomic_test_and_set_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT)) {
uart_rx_buf_rsp(backend->uart, backend->async.receive_bufs[1],
backend->async.receive_buf_size);
Expand All @@ -93,14 +93,14 @@

case UART_RX_BUF_RELEASED:
if (evt->data.rx_buf.buf == backend->async.receive_bufs[0]) {
atomic_clear_bit(&backend->async.state,
atomic_clear_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);

break;
}

if (evt->data.rx_buf.buf == backend->async.receive_bufs[1]) {
atomic_clear_bit(&backend->async.state,
atomic_clear_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF1_USED_BIT);

break;
Expand Down Expand Up @@ -131,7 +131,7 @@
break;

case UART_RX_DISABLED:
atomic_clear_bit(&backend->async.state,
atomic_clear_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
break;

Expand All @@ -144,7 +144,7 @@
}

if (modem_backend_uart_async_is_uart_stopped(backend)) {
k_work_submit(&backend->async.rx_disabled_work);
k_work_submit(&backend->async.common.rx_disabled_work);
}
}

Expand All @@ -153,12 +153,13 @@
struct modem_backend_uart *backend = (struct modem_backend_uart *)data;
int ret;

atomic_clear(&backend->async.state);
atomic_clear(&backend->async.common.state);
ring_buf_reset(&backend->async.receive_rb);

atomic_set_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);
atomic_set_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
atomic_set_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
atomic_set_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_RX_BUF0_USED_BIT);
atomic_set_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_RECEIVING_BIT);
atomic_set_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);

/* Receive buffers are used internally by UART, receive ring buffer is
* used to store received data.
Expand All @@ -167,7 +168,7 @@
backend->async.receive_buf_size,
CONFIG_MODEM_BACKEND_UART_ASYNC_RECEIVE_IDLE_TIMEOUT_MS * 1000L);
if (ret < 0) {
atomic_clear(&backend->async.state);
atomic_clear(&backend->async.common.state);
return ret;
}

Expand Down Expand Up @@ -197,7 +198,7 @@

static uint32_t get_transmit_buf_size(struct modem_backend_uart *backend)
{
return backend->async.transmit_buf_size;
return backend->async.common.transmit_buf_size;
}

static int modem_backend_uart_async_transmit(void *data, const uint8_t *buf, size_t size)
Expand All @@ -207,7 +208,7 @@
uint32_t bytes_to_transmit;
int ret;

transmitting = atomic_test_and_set_bit(&backend->async.state,
transmitting = atomic_test_and_set_bit(&backend->async.common.state,
MODEM_BACKEND_UART_ASYNC_STATE_TRANSMITTING_BIT);
if (transmitting) {
return 0;
Expand All @@ -217,9 +218,9 @@
bytes_to_transmit = MIN(size, get_transmit_buf_size(backend));

/* Copy buf to transmit buffer which is passed to UART */
memcpy(backend->async.transmit_buf, buf, bytes_to_transmit);
memcpy(backend->async.common.transmit_buf, buf, bytes_to_transmit);

ret = uart_tx(backend->uart, backend->async.transmit_buf, bytes_to_transmit,
ret = uart_tx(backend->uart, backend->async.common.transmit_buf, bytes_to_transmit,
CONFIG_MODEM_BACKEND_UART_ASYNC_TRANSMIT_TIMEOUT_MS * 1000L);

#if CONFIG_MODEM_STATS
Expand Down Expand Up @@ -263,7 +264,7 @@
{
struct modem_backend_uart *backend = (struct modem_backend_uart *)data;

atomic_clear_bit(&backend->async.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
atomic_clear_bit(&backend->async.common.state, MODEM_BACKEND_UART_ASYNC_STATE_OPEN_BIT);
uart_tx_abort(backend->uart);
uart_rx_disable(backend->uart);
return 0;
Expand All @@ -284,8 +285,11 @@

static void modem_backend_uart_async_notify_closed(struct k_work *item)
{
struct modem_backend_uart_async_common *common =
CONTAINER_OF(item, struct modem_backend_uart_async_common, rx_disabled_work);

struct modem_backend_uart_async *async =
CONTAINER_OF(item, struct modem_backend_uart_async, rx_disabled_work);
CONTAINER_OF(common, struct modem_backend_uart_async, common);

struct modem_backend_uart *backend =
CONTAINER_OF(async, struct modem_backend_uart, async);
Expand All @@ -310,8 +314,8 @@
}
#endif

void modem_backend_uart_async_init(struct modem_backend_uart *backend,
const struct modem_backend_uart_config *config)
int modem_backend_uart_async_init(struct modem_backend_uart *backend,
const struct modem_backend_uart_config *config)
{
uint32_t receive_buf_size_quarter = config->receive_buf_size / 4;

Expand All @@ -324,12 +328,15 @@
ring_buf_init(&backend->async.receive_rb, (receive_buf_size_quarter * 2),
&config->receive_buf[receive_buf_size_quarter * 2]);

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);
backend->async.common.transmit_buf = config->transmit_buf;
backend->async.common.transmit_buf_size = config->transmit_buf_size;
k_work_init(&backend->async.common.rx_disabled_work,
modem_backend_uart_async_notify_closed);
modem_pipe_init(&backend->pipe, backend, &modem_backend_uart_async_api);

#if CONFIG_MODEM_STATS
init_stats(backend);
#endif

return 0;
}
4 changes: 2 additions & 2 deletions subsys/modem/backends/modem_backend_uart_async.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ extern "C" {

bool modem_backend_uart_async_is_supported(struct modem_backend_uart *backend);

void modem_backend_uart_async_init(struct modem_backend_uart *backend,
const struct modem_backend_uart_config *config);
int modem_backend_uart_async_init(struct modem_backend_uart *backend,
const struct modem_backend_uart_config *config);

#ifdef __cplusplus
}
Expand Down
Loading
Loading