| /* |
| * Copyright (c) 2019 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "test_uart.h" |
| |
| K_SEM_DEFINE(tx_done, 0, 1); |
| K_SEM_DEFINE(tx_aborted, 0, 1); |
| K_SEM_DEFINE(rx_rdy, 0, 1); |
| K_SEM_DEFINE(rx_buf_coherency, 0, 255); |
| K_SEM_DEFINE(rx_buf_released, 0, 1); |
| K_SEM_DEFINE(rx_disabled, 0, 1); |
| |
| ZTEST_BMEM volatile bool failed_in_isr; |
| static ZTEST_BMEM const struct device *const uart_dev = |
| DEVICE_DT_GET(UART_NODE); |
| |
| static void read_abort_timeout(struct k_timer *timer); |
| K_TIMER_DEFINE(read_abort_timer, read_abort_timeout, NULL); |
| |
| |
| static void init_test(void) |
| { |
| __ASSERT_NO_MSG(device_is_ready(uart_dev)); |
| uart_rx_disable(uart_dev); |
| uart_tx_abort(uart_dev); |
| k_sem_reset(&tx_done); |
| k_sem_reset(&tx_aborted); |
| k_sem_reset(&rx_rdy); |
| k_sem_reset(&rx_buf_released); |
| k_sem_reset(&rx_disabled); |
| } |
| |
| #ifdef CONFIG_USERSPACE |
| static void set_permissions(void) |
| { |
| k_thread_access_grant(k_current_get(), &tx_done, &tx_aborted, |
| &rx_rdy, &rx_buf_coherency, &rx_buf_released, |
| &rx_disabled, uart_dev, &read_abort_timer); |
| } |
| #endif |
| |
| static void uart_async_test_init(void) |
| { |
| static bool initialized; |
| |
| __ASSERT_NO_MSG(device_is_ready(uart_dev)); |
| uart_rx_disable(uart_dev); |
| uart_tx_abort(uart_dev); |
| k_sem_reset(&tx_done); |
| k_sem_reset(&tx_aborted); |
| k_sem_reset(&rx_rdy); |
| k_sem_reset(&rx_buf_coherency); |
| k_sem_reset(&rx_buf_released); |
| k_sem_reset(&rx_disabled); |
| |
| #ifdef CONFIG_UART_WIDE_DATA |
| const struct uart_config uart_cfg = { |
| .baudrate = 115200, |
| .parity = UART_CFG_PARITY_NONE, |
| .stop_bits = UART_CFG_STOP_BITS_1, |
| .data_bits = UART_CFG_DATA_BITS_9, |
| .flow_ctrl = UART_CFG_FLOW_CTRL_NONE |
| }; |
| __ASSERT_NO_MSG(uart_configure(uart_dev, &uart_cfg) == 0); |
| #endif |
| |
| if (!initialized) { |
| init_test(); |
| initialized = true; |
| #ifdef CONFIG_USERSPACE |
| set_permissions(); |
| #endif |
| } |
| |
| } |
| |
| struct test_data { |
| volatile uint32_t tx_aborted_count; |
| uint8_t rx_first_buffer[10]; |
| uint32_t recv_bytes_first_buffer; |
| uint8_t rx_second_buffer[5]; |
| uint32_t recv_bytes_second_buffer; |
| bool supply_second_buffer; |
| }; |
| |
| ZTEST_BMEM struct test_data tdata; |
| |
| static void test_single_read_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| ARG_UNUSED(dev); |
| struct test_data *data = (struct test_data *)user_data; |
| |
| switch (evt->type) { |
| case UART_TX_DONE: |
| k_sem_give(&tx_done); |
| break; |
| case UART_TX_ABORTED: |
| data->tx_aborted_count++; |
| break; |
| case UART_RX_RDY: |
| if ((uintptr_t)evt->data.rx.buf < (uintptr_t)tdata.rx_second_buffer) { |
| data->recv_bytes_first_buffer += evt->data.rx.len; |
| } else { |
| data->recv_bytes_second_buffer += evt->data.rx.len; |
| } |
| k_sem_give(&rx_rdy); |
| break; |
| case UART_RX_BUF_RELEASED: |
| k_sem_give(&rx_buf_released); |
| break; |
| case UART_RX_BUF_REQUEST: |
| if (data->supply_second_buffer) { |
| /* Reply to one buffer request. */ |
| uart_rx_buf_rsp(dev, data->rx_second_buffer, |
| sizeof(data->rx_second_buffer)); |
| data->supply_second_buffer = false; |
| } |
| break; |
| case UART_RX_DISABLED: |
| k_sem_give(&rx_disabled); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| ZTEST_BMEM volatile uint32_t tx_aborted_count; |
| |
| static void *single_read_setup(void) |
| { |
| uart_async_test_init(); |
| |
| memset(&tdata, 0, sizeof(tdata)); |
| tdata.supply_second_buffer = true; |
| uart_callback_set(uart_dev, |
| test_single_read_callback, |
| (void *) &tdata); |
| |
| return NULL; |
| } |
| |
| static void tdata_check_recv_buffers(const uint8_t *tx_buf, uint32_t sent_bytes) |
| { |
| uint32_t recv_bytes_total; |
| |
| recv_bytes_total = tdata.recv_bytes_first_buffer + tdata.recv_bytes_second_buffer; |
| zassert_equal(recv_bytes_total, sent_bytes, "Incorrect number of bytes received"); |
| |
| zassert_equal(memcmp(tx_buf, tdata.rx_first_buffer, tdata.recv_bytes_first_buffer), 0, |
| "Invalid data received in first buffer"); |
| zassert_equal(memcmp(tx_buf + tdata.recv_bytes_first_buffer, tdata.rx_second_buffer, |
| tdata.recv_bytes_second_buffer), |
| 0, "Invalid data received in second buffer"); |
| |
| /* check that the remaining bytes in the buffers are zero */ |
| for (int i = tdata.recv_bytes_first_buffer; i < sizeof(tdata.rx_first_buffer); i++) { |
| zassert_equal(tdata.rx_first_buffer[i], 0, |
| "Received extra data to the first buffer"); |
| } |
| |
| for (int i = tdata.recv_bytes_second_buffer; i < sizeof(tdata.rx_second_buffer); i++) { |
| zassert_equal(tdata.rx_second_buffer[i], 0, |
| "Received extra data to the second buffer"); |
| } |
| } |
| |
| ZTEST_USER(uart_async_single_read, test_single_read) |
| { |
| /* Check also if sending from read only memory (e.g. flash) works. */ |
| static const uint8_t tx_buf[] = "0123456789"; |
| uint32_t sent_bytes = 0; |
| |
| zassert_not_equal(memcmp(tx_buf, tdata.rx_first_buffer, 5), 0, |
| "Initial buffer check failed"); |
| |
| uart_rx_enable(uart_dev, tdata.rx_first_buffer, 10, 50 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "RX_RDY not expected at this point"); |
| |
| uart_tx(uart_dev, tx_buf, 5, 100 * USEC_PER_MSEC); |
| sent_bytes += 5; |
| |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "Extra RX_RDY received"); |
| |
| tdata_check_recv_buffers(tx_buf, sent_bytes); |
| |
| uart_tx(uart_dev, tx_buf + sent_bytes, 5, 100 * USEC_PER_MSEC); |
| sent_bytes += 5; |
| |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), |
| 0, |
| "RX_BUF_RELEASED timeout"); |
| uart_rx_disable(uart_dev); |
| |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(1000)), 0, |
| "RX_DISABLED timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "Extra RX_RDY received"); |
| |
| tdata_check_recv_buffers(tx_buf, sent_bytes); |
| |
| zassert_equal(tdata.tx_aborted_count, 0, "TX aborted triggered"); |
| } |
| |
| static void *multiple_rx_enable_setup(void) |
| { |
| uart_async_test_init(); |
| |
| memset(&tdata, 0, sizeof(tdata)); |
| /* Reuse the callback from the single_read test case, as this test case |
| * does not need anything extra in this regard. |
| */ |
| uart_callback_set(uart_dev, |
| test_single_read_callback, |
| (void *)&tdata); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_multi_rx, test_multiple_rx_enable) |
| { |
| /* Check also if sending from read only memory (e.g. flash) works. */ |
| static const uint8_t tx_buf[] = "test"; |
| const uint32_t rx_buf_size = sizeof(tx_buf); |
| int ret; |
| |
| BUILD_ASSERT(sizeof(tx_buf) <= sizeof(tdata.rx_first_buffer), "Invalid buf size"); |
| |
| /* Enable RX without a timeout. */ |
| ret = uart_rx_enable(uart_dev, tdata.rx_first_buffer, rx_buf_size, SYS_FOREVER_US); |
| zassert_equal(ret, 0, "uart_rx_enable failed"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "RX_RDY not expected at this point"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), -EAGAIN, |
| "RX_DISABLED not expected at this point"); |
| |
| /* Disable RX before any data has been received. */ |
| ret = uart_rx_disable(uart_dev); |
| zassert_equal(ret, 0, "uart_rx_disable failed"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "RX_RDY not expected at this point"); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), 0, |
| "RX_BUF_RELEASED timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| |
| k_sem_reset(&rx_buf_released); |
| k_sem_reset(&rx_disabled); |
| |
| /* Check that RX can be reenabled after "manual" disabling. */ |
| ret = uart_rx_enable(uart_dev, tdata.rx_first_buffer, rx_buf_size, |
| 50 * USEC_PER_MSEC); |
| zassert_equal(ret, 0, "uart_rx_enable failed"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "RX_RDY not expected at this point"); |
| |
| /* Send enough data to completely fill RX buffer, so that RX ends. */ |
| ret = uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); |
| zassert_equal(ret, 0, "uart_tx failed"); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "Extra RX_RDY received"); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), 0, |
| "RX_BUF_RELEASED timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| zassert_equal(tx_aborted_count, 0, "Unexpected TX abort"); |
| |
| tdata_check_recv_buffers(tx_buf, sizeof(tx_buf)); |
| |
| k_sem_reset(&rx_rdy); |
| k_sem_reset(&rx_buf_released); |
| k_sem_reset(&rx_disabled); |
| k_sem_reset(&tx_done); |
| |
| memset(&tdata, 0, sizeof(tdata)); |
| |
| /* Check that RX can be reenabled after automatic disabling. */ |
| ret = uart_rx_enable(uart_dev, tdata.rx_first_buffer, rx_buf_size, |
| 50 * USEC_PER_MSEC); |
| zassert_equal(ret, 0, "uart_rx_enable failed"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "RX_RDY not expected at this point"); |
| |
| /* Fill RX buffer again to confirm that RX still works properly. */ |
| ret = uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); |
| zassert_equal(ret, 0, "uart_tx failed"); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), -EAGAIN, |
| "Extra RX_RDY received"); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), 0, |
| "RX_BUF_RELEASED timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| zassert_equal(tx_aborted_count, 0, "Unexpected TX abort"); |
| |
| tdata_check_recv_buffers(tx_buf, sizeof(tx_buf)); |
| } |
| |
| ZTEST_BMEM uint8_t chained_read_buf[2][8]; |
| ZTEST_BMEM uint8_t chained_cpy_buf[10]; |
| ZTEST_BMEM volatile uint8_t rx_data_idx; |
| ZTEST_BMEM uint8_t rx_buf_idx; |
| |
| ZTEST_BMEM uint8_t *read_ptr; |
| |
| static void test_chained_read_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| int err; |
| |
| switch (evt->type) { |
| case UART_TX_DONE: |
| k_sem_give(&tx_done); |
| break; |
| case UART_RX_RDY: |
| zassert_true(rx_data_idx + evt->data.rx.len <= sizeof(chained_cpy_buf)); |
| memcpy(&chained_cpy_buf[rx_data_idx], |
| &evt->data.rx.buf[evt->data.rx.offset], |
| evt->data.rx.len); |
| rx_data_idx += evt->data.rx.len; |
| break; |
| case UART_RX_BUF_REQUEST: |
| err = uart_rx_buf_rsp(dev, |
| chained_read_buf[rx_buf_idx], |
| sizeof(chained_read_buf[0])); |
| zassert_equal(err, 0); |
| rx_buf_idx = !rx_buf_idx ? 1 : 0; |
| break; |
| case UART_RX_DISABLED: |
| k_sem_give(&rx_disabled); |
| break; |
| default: |
| break; |
| } |
| |
| } |
| |
| static void *chained_read_setup(void) |
| { |
| uart_async_test_init(); |
| |
| uart_callback_set(uart_dev, test_chained_read_callback, NULL); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_chain_read, test_chained_read) |
| { |
| uint8_t tx_buf[10]; |
| int iter = 6; |
| uint32_t rx_timeout_ms = 50; |
| int err; |
| |
| err = uart_rx_enable(uart_dev, |
| chained_read_buf[rx_buf_idx++], |
| sizeof(chained_read_buf[0]), |
| rx_timeout_ms * USEC_PER_MSEC); |
| zassert_equal(err, 0); |
| |
| for (int i = 0; i < iter; i++) { |
| zassert_not_equal(k_sem_take(&rx_disabled, K_MSEC(10)), |
| 0, |
| "RX_DISABLED occurred"); |
| snprintf(tx_buf, sizeof(tx_buf), "Message %d", i); |
| uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, |
| "TX_DONE timeout"); |
| k_msleep(rx_timeout_ms + 10); |
| zassert_equal(rx_data_idx, sizeof(tx_buf), |
| "Unexpected amount of data received %d exp:%d", |
| rx_data_idx, sizeof(tx_buf)); |
| zassert_equal(memcmp(tx_buf, chained_cpy_buf, sizeof(tx_buf)), 0, |
| "Buffers not equal"); |
| rx_data_idx = 0; |
| } |
| uart_rx_disable(uart_dev); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| } |
| |
| ZTEST_BMEM uint8_t double_buffer[2][12]; |
| ZTEST_DMEM uint8_t *next_buf = double_buffer[1]; |
| |
| static void test_double_buffer_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| switch (evt->type) { |
| case UART_TX_DONE: |
| k_sem_give(&tx_done); |
| break; |
| case UART_RX_RDY: |
| read_ptr = evt->data.rx.buf + evt->data.rx.offset; |
| k_sem_give(&rx_rdy); |
| break; |
| case UART_RX_BUF_REQUEST: |
| uart_rx_buf_rsp(dev, next_buf, sizeof(double_buffer[0])); |
| break; |
| case UART_RX_BUF_RELEASED: |
| next_buf = evt->data.rx_buf.buf; |
| k_sem_give(&rx_buf_released); |
| break; |
| case UART_RX_DISABLED: |
| k_sem_give(&rx_disabled); |
| break; |
| default: |
| break; |
| } |
| |
| } |
| |
| static void *double_buffer_setup(void) |
| { |
| uart_async_test_init(); |
| |
| uart_callback_set(uart_dev, test_double_buffer_callback, NULL); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_double_buf, test_double_buffer) |
| { |
| uint8_t tx_buf[4]; |
| |
| zassert_equal(uart_rx_enable(uart_dev, |
| double_buffer[0], |
| sizeof(double_buffer[0]), |
| 50 * USEC_PER_MSEC), |
| 0, |
| "Failed to enable receiving"); |
| |
| for (int i = 0; i < 100; i++) { |
| snprintf(tx_buf, sizeof(tx_buf), "%03d", i); |
| uart_tx(uart_dev, tx_buf, sizeof(tx_buf), 100 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, |
| "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, |
| "RX_RDY timeout"); |
| zassert_equal(memcmp(tx_buf, read_ptr, sizeof(tx_buf)), |
| 0, |
| "Buffers not equal"); |
| } |
| uart_rx_disable(uart_dev); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| } |
| |
| ZTEST_BMEM uint8_t test_read_abort_rx_buf[2][100]; |
| ZTEST_BMEM uint8_t test_read_abort_read_buf[100]; |
| ZTEST_BMEM int test_read_abort_rx_cnt; |
| |
| static void test_read_abort_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| int err; |
| |
| ARG_UNUSED(dev); |
| |
| switch (evt->type) { |
| case UART_TX_DONE: |
| k_sem_give(&tx_done); |
| break; |
| case UART_RX_BUF_REQUEST: |
| { |
| static bool once; |
| |
| if (!once) { |
| k_sem_give(&rx_buf_coherency); |
| uart_rx_buf_rsp(dev, |
| test_read_abort_rx_buf[1], |
| sizeof(test_read_abort_rx_buf[1])); |
| once = true; |
| } |
| break; |
| } |
| case UART_RX_RDY: |
| memcpy(&test_read_abort_read_buf[test_read_abort_rx_cnt], |
| &evt->data.rx.buf[evt->data.rx.offset], |
| evt->data.rx.len); |
| test_read_abort_rx_cnt += evt->data.rx.len; |
| k_sem_give(&rx_rdy); |
| break; |
| case UART_RX_BUF_RELEASED: |
| k_sem_give(&rx_buf_released); |
| err = k_sem_take(&rx_buf_coherency, K_NO_WAIT); |
| failed_in_isr |= (err < 0); |
| break; |
| case UART_RX_DISABLED: |
| err = k_sem_take(&rx_buf_released, K_NO_WAIT); |
| failed_in_isr |= (err < 0); |
| k_sem_give(&rx_disabled); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void read_abort_timeout(struct k_timer *timer) |
| { |
| int err; |
| |
| err = uart_rx_disable(uart_dev); |
| zassert_equal(err, 0, "Unexpected err:%d", err); |
| } |
| |
| static void *read_abort_setup(void) |
| { |
| uart_async_test_init(); |
| |
| failed_in_isr = false; |
| uart_callback_set(uart_dev, test_read_abort_callback, NULL); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_read_abort, test_read_abort) |
| { |
| uint8_t rx_buf[100]; |
| uint8_t tx_buf[100]; |
| |
| memset(rx_buf, 0, sizeof(rx_buf)); |
| memset(tx_buf, 1, sizeof(tx_buf)); |
| |
| uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), 50 * USEC_PER_MSEC); |
| k_sem_give(&rx_buf_coherency); |
| |
| uart_tx(uart_dev, tx_buf, 5, 100 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| zassert_equal(memcmp(tx_buf, rx_buf, 5), 0, "Buffers not equal"); |
| |
| uart_tx(uart_dev, tx_buf, 95, 100 * USEC_PER_MSEC); |
| |
| k_timer_start(&read_abort_timer, K_USEC(300), K_NO_WAIT); |
| |
| /* RX will be aborted from k_timer timeout */ |
| |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| zassert_false(failed_in_isr, "Unexpected order of uart events"); |
| zassert_not_equal(memcmp(tx_buf, test_read_abort_read_buf, 100), 0, "Buffers equal"); |
| |
| /* Read out possible other RX bytes |
| * that may affect following test on RX |
| */ |
| uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), 50 * USEC_PER_MSEC); |
| while (k_sem_take(&rx_rdy, K_MSEC(1000)) != -EAGAIN) { |
| ; |
| } |
| uart_rx_disable(uart_dev); |
| k_msleep(10); |
| zassert_not_equal(k_sem_take(&rx_buf_coherency, K_NO_WAIT), 0, |
| "All provided buffers are released"); |
| |
| } |
| |
| ZTEST_BMEM volatile size_t sent; |
| ZTEST_BMEM volatile size_t received; |
| ZTEST_BMEM uint8_t test_rx_buf[2][100]; |
| |
| static void test_write_abort_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| ARG_UNUSED(dev); |
| |
| switch (evt->type) { |
| case UART_TX_DONE: |
| k_sem_give(&tx_done); |
| break; |
| case UART_TX_ABORTED: |
| sent = evt->data.tx.len; |
| k_sem_give(&tx_aborted); |
| break; |
| case UART_RX_RDY: |
| received = evt->data.rx.len; |
| k_sem_give(&rx_rdy); |
| break; |
| case UART_RX_BUF_REQUEST: |
| uart_rx_buf_rsp(dev, test_rx_buf[1], sizeof(test_rx_buf[1])); |
| break; |
| case UART_RX_BUF_RELEASED: |
| k_sem_give(&rx_buf_released); |
| break; |
| case UART_RX_DISABLED: |
| k_sem_give(&rx_disabled); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void *write_abort_setup(void) |
| { |
| uart_async_test_init(); |
| |
| uart_callback_set(uart_dev, test_write_abort_callback, NULL); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_write_abort, test_write_abort) |
| { |
| uint8_t tx_buf[100]; |
| |
| memset(test_rx_buf, 0, sizeof(test_rx_buf)); |
| memset(tx_buf, 1, sizeof(tx_buf)); |
| |
| uart_rx_enable(uart_dev, test_rx_buf[0], sizeof(test_rx_buf[0]), 50 * USEC_PER_MSEC); |
| |
| uart_tx(uart_dev, tx_buf, 5, 100 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| zassert_equal(memcmp(tx_buf, test_rx_buf, 5), 0, "Buffers not equal"); |
| |
| uart_tx(uart_dev, tx_buf, 95, 100 * USEC_PER_MSEC); |
| uart_tx_abort(uart_dev); |
| zassert_equal(k_sem_take(&tx_aborted, K_MSEC(100)), 0, |
| "TX_ABORTED timeout"); |
| if (sent != 0) { |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, |
| "RX_RDY timeout"); |
| zassert_equal(sent, received, "Sent is not equal to received."); |
| } |
| uart_rx_disable(uart_dev); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), |
| 0, |
| "RX_BUF_RELEASED timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| } |
| |
| |
| static void test_forever_timeout_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| ARG_UNUSED(dev); |
| |
| switch (evt->type) { |
| case UART_TX_DONE: |
| k_sem_give(&tx_done); |
| break; |
| case UART_TX_ABORTED: |
| sent = evt->data.tx.len; |
| k_sem_give(&tx_aborted); |
| break; |
| case UART_RX_RDY: |
| received = evt->data.rx.len; |
| k_sem_give(&rx_rdy); |
| break; |
| case UART_RX_BUF_RELEASED: |
| k_sem_give(&rx_buf_released); |
| break; |
| case UART_RX_DISABLED: |
| k_sem_give(&rx_disabled); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void *forever_timeout_setup(void) |
| { |
| uart_async_test_init(); |
| |
| uart_callback_set(uart_dev, test_forever_timeout_callback, NULL); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_timeout, test_forever_timeout) |
| { |
| uint8_t rx_buf[100]; |
| uint8_t tx_buf[100]; |
| |
| memset(rx_buf, 0, sizeof(rx_buf)); |
| memset(tx_buf, 1, sizeof(tx_buf)); |
| |
| uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), SYS_FOREVER_US); |
| |
| uart_tx(uart_dev, tx_buf, 5, SYS_FOREVER_US); |
| zassert_not_equal(k_sem_take(&tx_aborted, K_MSEC(1000)), 0, |
| "TX_ABORTED timeout"); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_not_equal(k_sem_take(&rx_rdy, K_MSEC(1000)), 0, |
| "RX_RDY timeout"); |
| |
| uart_tx(uart_dev, tx_buf, 95, SYS_FOREVER_US); |
| |
| zassert_not_equal(k_sem_take(&tx_aborted, K_MSEC(1000)), 0, |
| "TX_ABORTED timeout"); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| |
| |
| zassert_equal(memcmp(tx_buf, rx_buf, 100), 0, "Buffers not equal"); |
| |
| uart_rx_disable(uart_dev); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), |
| 0, |
| "RX_BUF_RELEASED timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| } |
| |
| |
| ZTEST_DMEM uint8_t chained_write_tx_bufs[2][10] = {"Message 1", "Message 2"}; |
| ZTEST_DMEM bool chained_write_next_buf = true; |
| ZTEST_BMEM volatile uint8_t tx_sent; |
| |
| static void test_chained_write_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| switch (evt->type) { |
| case UART_TX_DONE: |
| if (chained_write_next_buf) { |
| uart_tx(dev, chained_write_tx_bufs[1], 10, 100 * USEC_PER_MSEC); |
| chained_write_next_buf = false; |
| } |
| tx_sent = 1; |
| k_sem_give(&tx_done); |
| break; |
| case UART_TX_ABORTED: |
| sent = evt->data.tx.len; |
| k_sem_give(&tx_aborted); |
| break; |
| case UART_RX_RDY: |
| received = evt->data.rx.len; |
| k_sem_give(&rx_rdy); |
| break; |
| case UART_RX_BUF_RELEASED: |
| k_sem_give(&rx_buf_released); |
| break; |
| case UART_RX_DISABLED: |
| k_sem_give(&rx_disabled); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void *chained_write_setup(void) |
| { |
| uart_async_test_init(); |
| |
| uart_callback_set(uart_dev, test_chained_write_callback, NULL); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_chain_write, test_chained_write) |
| { |
| uint8_t rx_buf[20]; |
| |
| memset(rx_buf, 0, sizeof(rx_buf)); |
| |
| uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), 50 * USEC_PER_MSEC); |
| |
| uart_tx(uart_dev, chained_write_tx_bufs[0], 10, 100 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(100)), 0, "TX_DONE timeout"); |
| zassert_equal(chained_write_next_buf, false, "Sent no message"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(100)), 0, "RX_RDY timeout"); |
| zassert_equal(memcmp(chained_write_tx_bufs[0], rx_buf, 10), |
| 0, |
| "Buffers not equal"); |
| zassert_equal(memcmp(chained_write_tx_bufs[1], rx_buf + 10, 10), |
| 0, |
| "Buffers not equal"); |
| |
| uart_rx_disable(uart_dev); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), |
| 0, |
| "RX_BUF_RELEASED timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| } |
| |
| ZTEST_BMEM uint8_t long_rx_buf[1024]; |
| ZTEST_BMEM uint8_t long_rx_buf2[1024]; |
| ZTEST_BMEM uint8_t long_tx_buf[1000]; |
| ZTEST_BMEM volatile uint8_t evt_num; |
| ZTEST_BMEM size_t long_received[2]; |
| |
| static void test_long_buffers_callback(const struct device *dev, |
| struct uart_event *evt, void *user_data) |
| { |
| static uint8_t *next_buffer = long_rx_buf2; |
| |
| switch (evt->type) { |
| case UART_TX_DONE: |
| k_sem_give(&tx_done); |
| break; |
| case UART_TX_ABORTED: |
| sent = evt->data.tx.len; |
| k_sem_give(&tx_aborted); |
| break; |
| case UART_RX_RDY: |
| long_received[evt_num] = evt->data.rx.len; |
| evt_num++; |
| k_sem_give(&rx_rdy); |
| break; |
| case UART_RX_BUF_RELEASED: |
| k_sem_give(&rx_buf_released); |
| break; |
| case UART_RX_DISABLED: |
| k_sem_give(&rx_disabled); |
| break; |
| case UART_RX_BUF_REQUEST: |
| uart_rx_buf_rsp(dev, next_buffer, 1024); |
| next_buffer = (next_buffer == long_rx_buf2) ? long_rx_buf : long_rx_buf2; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void *long_buffers_setup(void) |
| { |
| uart_async_test_init(); |
| |
| uart_callback_set(uart_dev, test_long_buffers_callback, NULL); |
| |
| return NULL; |
| } |
| |
| ZTEST_USER(uart_async_long_buf, test_long_buffers) |
| { |
| memset(long_rx_buf, 0, sizeof(long_rx_buf)); |
| memset(long_tx_buf, 1, sizeof(long_tx_buf)); |
| |
| uart_rx_enable(uart_dev, long_rx_buf, sizeof(long_rx_buf), 10 * USEC_PER_MSEC); |
| |
| uart_tx(uart_dev, long_tx_buf, 500, 200 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(200)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(200)), 0, "RX_RDY timeout"); |
| zassert_equal(long_received[0], 500, "Wrong number of bytes received."); |
| zassert_equal(memcmp(long_tx_buf, long_rx_buf, 500), |
| 0, |
| "Buffers not equal"); |
| k_msleep(10); |
| /* Check if instance is releasing a buffer after the timeout. */ |
| bool release_on_timeout = k_sem_take(&rx_buf_released, K_NO_WAIT) == 0; |
| |
| evt_num = 0; |
| uart_tx(uart_dev, long_tx_buf, 1000, 200 * USEC_PER_MSEC); |
| zassert_equal(k_sem_take(&tx_done, K_MSEC(200)), 0, "TX_DONE timeout"); |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(200)), 0, "RX_RDY timeout"); |
| |
| if (release_on_timeout) { |
| zassert_equal(long_received[0], 1000, "Wrong number of bytes received."); |
| zassert_equal(memcmp(long_tx_buf, long_rx_buf2, long_received[0]), 0, |
| "Buffers not equal"); |
| } else { |
| zassert_equal(k_sem_take(&rx_rdy, K_MSEC(200)), 0, "RX_RDY timeout"); |
| zassert_equal(long_received[0], 524, "Wrong number of bytes received."); |
| zassert_equal(long_received[1], 476, "Wrong number of bytes received."); |
| zassert_equal(memcmp(long_tx_buf, long_rx_buf + 500, long_received[0]), 0, |
| "Buffers not equal"); |
| zassert_equal(memcmp(long_tx_buf, long_rx_buf2, long_received[1]), 0, |
| "Buffers not equal"); |
| } |
| |
| uart_rx_disable(uart_dev); |
| zassert_equal(k_sem_take(&rx_buf_released, K_MSEC(100)), |
| 0, |
| "RX_BUF_RELEASED timeout"); |
| zassert_equal(k_sem_take(&rx_disabled, K_MSEC(100)), 0, |
| "RX_DISABLED timeout"); |
| } |
| |
| ZTEST_SUITE(uart_async_single_read, NULL, single_read_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_multi_rx, NULL, multiple_rx_enable_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_chain_read, NULL, chained_read_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_double_buf, NULL, double_buffer_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_read_abort, NULL, read_abort_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_chain_write, NULL, chained_write_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_long_buf, NULL, long_buffers_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_write_abort, NULL, write_abort_setup, |
| NULL, NULL, NULL); |
| |
| ZTEST_SUITE(uart_async_timeout, NULL, forever_timeout_setup, |
| NULL, NULL, NULL); |