Skip to content

Commit

Permalink
apps/examples: add uart_loopback_test
Browse files Browse the repository at this point in the history
This is a test example where you can short-circuit the uart tx and rx boards to perform a loopback test.
This test sends "1234567890abcdefghijklmnopqrstuvwxyz" and recive same string

You can use CONIFG_UART_LOOPBACK_PORT to specify the port for the loopback test.

[TEST RESULT]

TASH>>uart_loopback start
TASH>>######################### UART loopback test START #########################
UART RX THREAD START
UART TX THREAD START
SEND UART(1): 1234567890abcdefghijklmnopqrstuvwxyz
RECEIVE(1): 1234567890abcdefghijklmnopqrstuvwxyz
RESULT(1): PASSED
SEND UART(2): 1234567890abcdefghijklmnopqrstuvwxyz
RECEIVE(2): 1234567890abcdefghijklmnopqrstuvwxyz
RESULT(2): PASSED
SEND UART(3): 1234567890abcdefghijklmnopqrstuvwxyz
RECEIVE(3): 1234567890abcdefghijklmnopqrstuvwxyz
RESULT(3): PASSED
  • Loading branch information
ewoodev committed Oct 28, 2024
1 parent adc9780 commit 89969db
Show file tree
Hide file tree
Showing 5 changed files with 371 additions and 0 deletions.
21 changes: 21 additions & 0 deletions apps/examples/uart_loopback/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#
# For a description of the syntax of this configuration file,
# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
#

config EXAMPLES_UART_LOOPBACK
bool "UART loopback test application"
default n
---help---
Enable UART loopback test application

if EXAMPLES_UART_LOOPBACK

config EXAMPLES_UART_LOOPBACK_PORT
int "UART loopback tty port "
default 2
---help---
The EXAMPLES_UART_LOOPBACK_PORT sets test UART ttyS* port
The default port is ttyS2

endif #EXAMPLES_UART_LOOPBACK
3 changes: 3 additions & 0 deletions apps/examples/uart_loopback/Kconfig_ENTRY
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
config ENTRY_UART_LOOPBACK
bool "uart loop back example"
depends on EXAMPLES_UART_LOOPBACK
21 changes: 21 additions & 0 deletions apps/examples/uart_loopback/Make.defs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
###########################################################################
#
# Copyright 2024 Samsung Electronics All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
# either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
#
###########################################################################

ifeq ($(CONFIG_EXAMPLES_UART_LOOPBACK),y)
CONFIGURED_APPS += examples/uart_loopback
endif
121 changes: 121 additions & 0 deletions apps/examples/uart_loopback/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
###########################################################################
#
# Copyright 2024 Samsung Electronics All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
# either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
#
###########################################################################
-include $(TOPDIR)/.config
-include $(TOPDIR)/Make.defs
include $(APPDIR)/Make.defs

APPNAME = uart_loopback
FUNCNAME = $(APPNAME)_main
THREADEXEC = TASH_EXECMD_ASYNC
PRIORITY = 100
STACKSIZE = 2048

ASRCS =
CSRCS =
MAINSRC = uart_loopback.c

AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
MAINOBJ = $(MAINSRC:.c=$(OBJEXT))

SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
OBJS = $(AOBJS) $(COBJS)

ifneq ($(CONFIG_BUILD_KERNEL),y)
OBJS += $(MAINOBJ)
endif

ifeq ($(CONFIG_WINDOWS_NATIVE),y)
BIN = $(APPDIR)\libapps$(LIBEXT)
else
ifeq ($(WINTOOL),y)
BIN = $(APPDIR)\\libapps$(LIBEXT)
else
BIN = $(APPDIR)/libapps$(LIBEXT)
endif
endif

ifeq ($(WINTOOL),y)
INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}"
else
INSTALL_DIR = $(BIN_DIR)
endif

CONFIG_EXAMPLES_TEST_PROGNAME ?= uart_loopback(EXEEXT)
PROGNAME = $(CONFIG_EXAMPLES_TEST_PROGNAME)

ROOTDEPPATH = --dep-path .

# Common build

VPATH =

all: .built
.PHONY: clean depend distclean

$(AOBJS): %$(OBJEXT): %.S
$(call ASSEMBLE, $<, $@)

$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c
$(call COMPILE, $<, $@)

.built: $(OBJS)
$(call ARCHIVE, $(BIN), $(OBJS))
@touch .built

ifeq ($(CONFIG_BUILD_KERNEL),y)
$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ)
@echo "LD: $(PROGNAME)"
$(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS)
$(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME)

install: $(BIN_DIR)$(DELIM)$(PROGNAME)

else
install:

endif


ifeq ($(CONFIG_BUILTIN_APPS)$(CONFIG_EXAMPLES_UART_LOOPBACK),yy)
$(BUILTIN_REGISTRY)$(DELIM)$(FUNCNAME).bdat: $(DEPCONFIG) Makefile
$(Q) $(call REGISTER,$(APPNAME),$(FUNCNAME),$(THREADEXEC),$(PRIORITY),$(STACKSIZE))
context: $(BUILTIN_REGISTRY)$(DELIM)$(FUNCNAME).bdat

else
context:

endif

.depend: Makefile $(SRCS)
@$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
@touch $@

depend: .depend

clean:
$(call DELFILE, .built)
$(call CLEAN)

distclean: clean
$(call DELFILE, Make.dep)
$(call DELFILE, .depend)

-include Make.dep
.PHONY: preconfig
preconfig:
205 changes: 205 additions & 0 deletions apps/examples/uart_loopback/uart_loopback.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/****************************************************************************
*
* Copyright 2024 Samsung Electronics All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/

/****************************************************************************
* Included Files
****************************************************************************/
#include <tinyara/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#ifndef CONFIG_DISABLE_POLL
#include <poll.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifndef CONFIG_EXAMPLES_UART_LOOPBACK_PORT
#define CONFIG_EXAMPLES_UART_LOOPBACK_PORT 2
#endif

#define UART_DEV_PATH "/dev/ttyS%d"

#define UART_POLL_TIMEOUT_MS 10000

#define TEST_STR "1234567890abcdefghijklmnopqrstuvwxyz"
#define TEST_STR_LEN 37

static int is_running;
static pthread_t g_tx_tid;
static pthread_t g_rx_tid;

static int uart_tx_loop(void)
{
printf("UART TX THREAD START\n");
int fd = 0;
int tx_test_count = 0;
char port[20] = {'\0'};
sprintf(port, UART_DEV_PATH, CONFIG_EXAMPLES_UART_LOOPBACK_PORT);
fd = open(port, O_RDWR | O_SYNC, 0666);
if (fd < 0) {
printf("ERROR: Failed to open Tx UART(%d):\n", get_errno());
return -1;
}

while (is_running) {
tx_test_count++;
usleep(200*1000);

char test_data[TEST_STR_LEN] = TEST_STR;
write(fd, (void *)test_data, TEST_STR_LEN);
printf("SEND UART(%d): %s\n", tx_test_count, TEST_STR, TEST_STR_LEN);
}

close(fd);
return 0;
}

static int uart_rx_loop(void)
{
int fd = 0;
char port[20] = {'\0'};
ssize_t ret_size;
int remain_size;
char *read_ptr;
int rx_test_count = 0;
char read_buf[TEST_STR_LEN];

printf("UART RX THREAD START\n");

sprintf(port, UART_DEV_PATH, CONFIG_EXAMPLES_UART_LOOPBACK_PORT);
fd = open(port, O_RDWR | O_SYNC, 0666);
if (fd < 0) {
printf("ERROR: Failed to open Rx UART(%d):\n", get_errno());
return -1;
}

while (is_running) {
rx_test_count++;
read_ptr = &read_buf;
remain_size = TEST_STR_LEN;

while (0 < remain_size) {

#ifndef CONFIG_DISABLE_POLL
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
if (poll(fds, 1, UART_POLL_TIMEOUT_MS) < 0) {
printf("Fail to poll(%d):\n", get_errno());
close(fd);
return -1;
}
if (!(fds[0].revents & POLLIN)) {
printf("RESULT(%d): FAILED (Timeout)\n");
continue;
}
#endif
ret_size = read(fd, (void *)read_ptr, remain_size);
remain_size -= ret_size;
read_ptr += ret_size;
}
printf("RECEIVE(%d): %s\n", rx_test_count, read_buf);
if (strncmp(read_buf, TEST_STR, TEST_STR_LEN) == 0) {
printf("RESULT(%d): PASSED\n", rx_test_count);
} else {
printf("RESULT(%d): FAILED (It does not match)\n", rx_test_count);
}
}

close(fd);
return 0;
}

static void help_func(void)
{
printf("usage: uart_loopback start/stop \n\n");
printf("This test is to check if the same data is read as it was written through uart.\n");
printf("For this test, you need to short-circuit the UART TX PIN and the UART RX PIN.\n");
printf("This default uart port is /dev/ttyS2, you can change CONFIG_EXAMPLES_UART_LOOPBACK_PORT.\n\n");
printf(" start\t\t Start uart loopback test\n");
printf(" stop\t\t stop uart loopback test\n");
}

/****************************************************************************
* Public functions
****************************************************************************/
#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int uart_loopback_main(int argc, char **argv)
#endif
{

if (argc != 2 || strncmp(argv[1], "help", 5) == 0) {
help_func();
return 0;
}

if (strncmp(argv[1], "start", 6) == 0) {

if (is_running) {
printf("uart_loopback is already running\n");
return 0;
}

printf("######################### UART loopback test START #########################\n");

is_running = 1;

if (pthread_create(&g_rx_tid, NULL, (pthread_startroutine_t)uart_rx_loop, NULL) < 0) {
printf("Failed to create rx pthread(%d):\n", get_errno());
return -1;
}
(void)pthread_setname_np(g_rx_tid, "uart_loopback_rx");

if (pthread_create(&g_tx_tid, NULL, (pthread_startroutine_t)uart_tx_loop, NULL) < 0) {
printf("Failed to create tx pthread(%d):\n", get_errno());
pthread_cancel(g_rx_tid);
return -1;
}
(void)pthread_setname_np(g_tx_tid, "uart_loopback_tx");

} else if (strncmp(argv[1], "stop", 5) == 0) {
if (!is_running) {
printf("uart_loopback was not running\n");
return 0;
}

is_running = 0;

if (pthread_join(g_rx_tid, NULL) < 0) {
printf("Fail to join rx thread(%d):\n", get_errno());
}
if (pthread_join(g_rx_tid, NULL) < 0) {
printf("Fail to join tx thread(%d):\n", get_errno());
}

printf("######################### UART loopback test END ###########################\n");

} else {
help_func();
}

return 0;
}

0 comments on commit 89969db

Please sign in to comment.