tests: modem: backends: uart: Add UART backend test suite

The UART backend test suite performs 9 iterations of:

1. Open UART backend pipe
2. Transmit 8192 bytes of pseudo random data
3. Receive and validate bytes
4. close UART backend pipe

The test is run on real hardware, with the TX/RX pins
connected to each other to provide loopback functionality.

The test suite has been run on a STM32 and an nRF5340 board.
The test suite tests both the UART interrupt driven and
async APIs.

Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
This commit is contained in:
Bjarki Arge Andreasen 2023-11-14 20:48:23 +01:00 committed by Carles Cufí
parent 8128a726a4
commit d3f100355f
6 changed files with 320 additions and 0 deletions

View file

@ -0,0 +1,8 @@
# Copyright (c) 2023 Trackunit Corporation
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(modem_backend_uart_test)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1,34 @@
/*
* Pins 2 and 3 must be connected to each other on the STMOD+1 connector to
* loopback RX/TX.
*/
/ {
aliases {
test-uart = &usart2;
};
};
&gpioh {
misc_fixed_usart2 {
gpio-hog;
gpios = <13 GPIO_ACTIVE_HIGH>;
output-high;
};
};
&gpdma1 {
status = "okay";
};
&usart2 {
pinctrl-0 = <&usart2_tx_pa2 &usart2_rx_pa3 &usart2_rts_pa1 &usart2_cts_pa0>;
pinctrl-names = "default";
current-speed = <115200>;
dmas = <&gpdma1 0 27 STM32_DMA_PERIPH_TX
&gpdma1 1 26 STM32_DMA_PERIPH_RX>;
dma-names = "tx", "rx";
status = "okay";
};

View file

@ -0,0 +1,37 @@
/*
* Pins P1.10 and P1.11 must be connected to each other to loopback RX/TX.
*/
/ {
aliases {
test-uart = &uart1;
};
};
&uart1 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&uart1_default>;
pinctrl-1 = <&uart1_sleep>;
hw-flow-control;
pinctrl-names = "default", "sleep";
};
&pinctrl {
uart1_default: uart1_default {
group1 {
psels = <NRF_PSEL(UART_TX, 1, 11)>;
};
group2 {
psels = <NRF_PSEL(UART_RX, 1, 10)>;
};
};
uart1_sleep: uart1_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 1, 10)>,
<NRF_PSEL(UART_RX, 1, 11)>;
low-power-enable;
};
};
};

View file

@ -0,0 +1,10 @@
# Copyright (c) 2023 Trackunit Corporation
# SPDX-License-Identifier: Apache-2.0
CONFIG_MODEM_MODULES=y
CONFIG_MODEM_BACKEND_UART=y
CONFIG_SERIAL=y
CONFIG_ZTEST=y
CONFIG_LOG=y
CONFIG_ZTEST_SHUFFLE=y
CONFIG_ZTEST_SHUFFLE_TEST_REPEAT_COUNT=3

View file

@ -0,0 +1,210 @@
/*
* Copyright (c) 2023 Trackunit Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This test suite sets up a modem_backend_uart instance connected to a UART which has its
* RX and TX pins wired together to provide loopback functionality. A large number of bytes
* containing a sequence of pseudo random numbers are then transmitted, received, and validated.
*
* The test suite repeats three times, opening and clsoing the modem_pipe attached to the
* modem_backend_uart instance before and after the tests respectively.
*/
/*************************************************************************************************/
/* Dependencies */
/*************************************************************************************************/
#include <zephyr/ztest.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/modem/backend/uart.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*************************************************************************************************/
/* Mock pipe */
/*************************************************************************************************/
static const struct device *uart = DEVICE_DT_GET(DT_ALIAS(test_uart));
static struct modem_backend_uart uart_backend;
static struct modem_pipe *pipe;
K_SEM_DEFINE(receive_ready_sem, 0, 1);
/*************************************************************************************************/
/* Buffers */
/*************************************************************************************************/
static uint8_t backend_receive_buffer[4096];
static uint8_t backend_transmit_buffer[4096];
RING_BUF_DECLARE(transmit_ring_buf, 4096);
static uint8_t receive_buffer[4096];
/*************************************************************************************************/
/* Modem pipe callback */
/*************************************************************************************************/
static void modem_pipe_callback_handler(struct modem_pipe *pipe, enum modem_pipe_event event,
void *user_data)
{
switch (event) {
case MODEM_PIPE_EVENT_RECEIVE_READY:
k_sem_give(&receive_ready_sem);
break;
default:
break;
}
}
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
static uint32_t transmit_prng_state = 1234;
static uint32_t receive_prng_state = 1234;
static uint32_t transmit_size_prng_state;
static uint8_t transmit_prng_random(void)
{
transmit_prng_state = ((1103515245 * transmit_prng_state) + 12345) % (1U << 31);
return (uint8_t)(transmit_prng_state & 0xFF);
}
static uint8_t receive_prng_random(void)
{
receive_prng_state = ((1103515245 * receive_prng_state) + 12345) % (1U << 31);
return (uint8_t)(receive_prng_state & 0xFF);
}
static void prng_reset(void)
{
transmit_prng_state = 1234;
receive_prng_state = 1234;
transmit_size_prng_state = 0;
}
static void fill_transmit_ring_buf(void)
{
uint32_t space = ring_buf_space_get(&transmit_ring_buf);
uint8_t data;
for (uint32_t i = 0; i < space; i++) {
data = transmit_prng_random();
ring_buf_put(&transmit_ring_buf, &data, 1);
}
}
static uint32_t transmit_size_prng_random(void)
{
uint32_t size = 1;
for (uint8_t i = 0; i < transmit_size_prng_state; i++) {
size = size * 2;
}
transmit_size_prng_state = transmit_size_prng_state == 11
? 0
: transmit_size_prng_state + 1;
return size;
}
static int transmit_prng(uint32_t remaining)
{
uint8_t *reserved;
uint32_t reserved_size;
uint32_t transmit_size;
int ret;
fill_transmit_ring_buf();
reserved_size = ring_buf_get_claim(&transmit_ring_buf, &reserved, UINT32_MAX);
transmit_size = MIN(transmit_size_prng_random(), reserved_size);
transmit_size = MIN(remaining, transmit_size);
ret = modem_pipe_transmit(pipe, reserved, transmit_size);
if (ret < 0) {
return ret;
}
printk("TX: %u,%u\n", transmit_size, (uint32_t)ret);
__ASSERT(ret <= remaining, "Impossible number of bytes sent %u", (uint32_t)ret);
ring_buf_get_finish(&transmit_ring_buf, ret);
return ret;
}
static int receive_prng(void)
{
int ret = 0;
if (k_sem_take(&receive_ready_sem, K_NO_WAIT) == 0) {
ret = modem_pipe_receive(pipe, receive_buffer, sizeof(receive_buffer));
if (ret < 0) {
return -EFAULT;
}
for (uint32_t i = 0; i < (uint32_t)ret; i++) {
if (receive_prng_random() != receive_buffer[i]) {
return -EFAULT;
}
}
printk("RX: %u\n", (uint32_t)ret);
}
return ret;
}
/*************************************************************************************************/
/* Test setup */
/*************************************************************************************************/
static void *test_modem_backend_uart_setup(void)
{
const struct modem_backend_uart_config config = {
.uart = uart,
.receive_buf = backend_receive_buffer,
.receive_buf_size = 1024,
.transmit_buf = backend_transmit_buffer,
.transmit_buf_size = 1024,
};
pipe = modem_backend_uart_init(&uart_backend, &config);
modem_pipe_attach(pipe, modem_pipe_callback_handler, NULL);
return NULL;
}
static void test_modem_backend_uart_before(void *f)
{
prng_reset();
ring_buf_reset(&transmit_ring_buf);
k_sem_reset(&receive_ready_sem);
__ASSERT_NO_MSG(modem_pipe_open(pipe) == 0);
}
static void test_modem_backend_uart_after(void *f)
{
__ASSERT_NO_MSG(modem_pipe_close(pipe) == 0);
}
/*************************************************************************************************/
/* Tests */
/*************************************************************************************************/
ZTEST(modem_backend_uart_suite, test_transmit_receive)
{
int32_t remaining = 8192;
uint32_t received = 0;
uint32_t transmitted = 0;
int ret;
while ((remaining != 0) || (received < 8192)) {
ret = transmit_prng(remaining);
zassert(ret > -1, "Failed to transmit data");
remaining -= (uint32_t)ret;
transmitted += (uint32_t)ret;
printk("TX ACC: %u\n", transmitted);
while (received < transmitted) {
ret = receive_prng();
zassert(ret > -1, "Received data is corrupted");
received += (uint32_t)ret;
k_yield();
}
}
}
ZTEST_SUITE(modem_backend_uart_suite, NULL, test_modem_backend_uart_setup,
test_modem_backend_uart_before, test_modem_backend_uart_after, NULL);

View file

@ -0,0 +1,21 @@
# Copyright (c) 2023 Trackunit Corporation
# SPDX-License-Identifier: Apache-2.0
tests:
modem.backends.uart.async:
tags: modem_backend
harness: ztest
platform_allow:
- b_u585i_iot02a
- nrf5340dk_nrf5340_cpuapp
extra_configs:
- CONFIG_UART_ASYNC_API=y
modem.backends.uart.isr:
tags: modem_backend
harness: ztest
platform_allow:
- b_u585i_iot02a
- nrf5340dk_nrf5340_cpuapp
extra_configs:
- CONFIG_UART_INTERRUPT_DRIVEN=y