linuxOS_D21X/source/artinchip/test-uart/test_uart.c

710 lines
15 KiB
C
Raw Normal View History

2024-11-29 08:33:21 +00:00
// SPDX-License-Identifier: Apache-2.0
2024-11-29 08:13:19 +00:00
/*
2025-08-14 07:13:29 +00:00
* Copyright (C) 2021-2025 ArtInChip Technology Co., Ltd.
2024-11-29 08:13:19 +00:00
* Author: Keliang Liu <keliang.liu@artinchip.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>
#include <getopt.h>
#include <string.h>
#include <sys/time.h>
#include <sys/select.h>
#include "artinchip/sample_base.h"
#define VERSION_STRING "1.0"
#define TEST_MODE_NORMAL 0
#define TEST_MODE_PRESSURE 1
#define TEST_MODE_STABILITY 2
#define TEST_MODE_CIRCLE 3
2024-11-29 08:23:11 +00:00
#define TEST_MODE_CIRCLE_X1 4
2024-11-29 08:13:19 +00:00
#define SIMPLE_ARGC_NUM 4
#define NORMAL_ARGC_NUM 5
#define uart_printf(fmt, ...) printf("%s " fmt, get_cur_time(), ##__VA_ARGS__)
static const char *m_send_device = "/dev/ttyS2";
static const char *m_receive_device = "/dev/ttyS3";
static int m_baudrate = 9600;
char *test_msg1 = "1234567890artinchip0987654321";
char *test_msg2 = "1234567890abcdefghijklmnopqurstuvwxyzartinchipzyxwvutsruqponmlkjihgfedcba0987654321";
char *str_null = "no";
static int m_test_mode = -1;
static char *get_cur_time()
{
2024-11-29 08:23:11 +00:00
static char s[24];
time_t t;
struct tm *ltime;
time(&t);
ltime = localtime(&t);
strftime(s, 24, "[%Y-%m-%d %H:%M:%S]", ltime);
return s;
2024-11-29 08:13:19 +00:00
}
static const struct option lopts[] = {
{"normal", optional_argument, 0, 'N'},
{"pressure", optional_argument, 0, 'P'},
{"stability", optional_argument, 0, 'S'},
{"circle", optional_argument, 0, 'C'},
2024-11-29 08:23:11 +00:00
{"circle x1", optional_argument, 0, 'c'},
2024-11-29 08:13:19 +00:00
{NULL, 0, 0, 0},
};
static void print_usage(const char *prog)
{
printf("Usage: %s -N/P/S/C dev1 dev2 baudrate\n", prog);
printf(" -N --normal Normal test\n"
2024-11-29 08:23:11 +00:00
" -P --pressure Pressure test with Speed test\n"
" -S --stability Stability test\n"
" -C --circle Continue circle test within one port\n"
" -c --circle Circle test within one port for one time\n"
" dev1 send device, %s means no \n"
" dev2 receive device, %s means no \n",
str_null, str_null);
2024-11-29 08:13:19 +00:00
printf("%s -N /dev/ttyS1 /dev/ttyS2 115200\n", prog);
printf("%s -P %s /dev/ttys2 115200\n", prog, str_null);
printf("%s -S /dev/ttyS1 %s 115200\n", prog, str_null);
printf("%s -C /dev/ttyS1 115200\n", prog);
exit(1);
}
static char *get_test_mode_string(int mode)
{
2024-11-29 08:23:11 +00:00
switch (mode) {
2024-11-29 08:13:19 +00:00
case TEST_MODE_NORMAL:
return "Normal Test";
case TEST_MODE_PRESSURE:
return "Pressure Test";
case TEST_MODE_STABILITY:
return "Stability";
case TEST_MODE_CIRCLE:
return "Circle";
2024-11-29 08:23:11 +00:00
case TEST_MODE_CIRCLE_X1:
return "circle";
2024-11-29 08:13:19 +00:00
default:
return "UNKNOWN";
}
}
static void print_parameter(int argc)
{
printf("Test Mode: %d(%s) \n", m_test_mode, get_test_mode_string(m_test_mode));
printf("Sender : %s \n", m_send_device);
if (argc == SIMPLE_ARGC_NUM)
printf("Receiver : %s \n", m_send_device);
else
printf("Receiver : %s \n", m_receive_device);
printf("Baudrate : %d \n\n", m_baudrate);
}
static int parse_opts(int argc, char *argv[])
{
int c;
int ret = 0;
2024-11-29 08:23:11 +00:00
while (1) {
c = getopt_long(argc, argv, "NPSCc", lopts, NULL);
2024-11-29 08:13:19 +00:00
if (c == -1)
break;
2024-11-29 08:23:11 +00:00
switch (c) {
2024-11-29 08:13:19 +00:00
case 'N':
m_test_mode = TEST_MODE_NORMAL;
break;
case 'P':
m_test_mode = TEST_MODE_PRESSURE;
break;
case 'S':
m_test_mode = TEST_MODE_STABILITY;
break;
case 'C':
m_test_mode = TEST_MODE_CIRCLE;
break;
2024-11-29 08:23:11 +00:00
case 'c':
m_test_mode = TEST_MODE_CIRCLE_X1;
break;
2024-11-29 08:13:19 +00:00
default:
print_usage(argv[0]);
ret = -1;
break;
}
}
m_send_device = argv[2];
if (argc == SIMPLE_ARGC_NUM) {
m_receive_device = str_null;
m_baudrate = atoi(argv[3]);
2024-11-29 08:23:11 +00:00
} else if (argc == NORMAL_ARGC_NUM) {
if (m_test_mode == TEST_MODE_CIRCLE
|| m_test_mode == TEST_MODE_CIRCLE_X1) {
2024-11-29 08:13:19 +00:00
printf("circle test just need 3 parameters \n");
printf("%s -C /dev/ttyS1 115200\n", argv[0]);
return -1;
}
m_receive_device = argv[3];
m_baudrate = atoi(argv[4]);
2024-11-29 08:23:11 +00:00
} else {
print_usage(argv[0]);
2024-11-29 08:13:19 +00:00
return -1;
}
2024-11-29 08:23:11 +00:00
2024-11-29 08:13:19 +00:00
return ret;
}
static int is_null_device(const char *device)
{
return !strcasecmp(device, str_null);
}
static int open_device(const char *device)
{
int fd;
int ret;
fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
2024-11-29 08:23:11 +00:00
if (fd < 0) {
2024-11-29 08:13:19 +00:00
printf("can't open device %s!\n", device);
return -1;
}
ret = fcntl(fd, F_SETFL, 0);
if (ret < 0)
printf("fcntl for failed!\n");
ret = isatty(fd);
2024-11-29 08:23:11 +00:00
if (ret == 0) {
2024-11-29 08:13:19 +00:00
printf("standard input is not a terminal device for %s\n", device);
close(fd);
return -1;
}
return fd;
}
static int config_device(int fd, int nSpeed, int nBits, int nParity, int nStop)
{
struct termios newtio, oldtio;
2024-11-29 08:23:11 +00:00
if (tcgetattr(fd, &oldtio) != 0) {
2024-11-29 08:13:19 +00:00
perror("tcgetattr");
return -1;
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
2024-11-29 08:23:11 +00:00
switch (nBits) {
2024-11-29 08:13:19 +00:00
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
default:
printf("Unsupported data size\n");
return -1;
}
2024-11-29 08:23:11 +00:00
switch (nParity) {
2024-11-29 08:13:19 +00:00
case 'o':
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'e':
case 'E':
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'n':
case 'N':
newtio.c_cflag &= ~PARENB;
break;
default:
printf("Unsupported parity\n");
return -1;
}
2024-11-29 08:23:11 +00:00
switch (nStop) {
2024-11-29 08:13:19 +00:00
case 1:
newtio.c_cflag &= ~CSTOPB;
break;
case 2:
newtio.c_cflag |= CSTOPB;
break;
default:
printf("Unsupported stop bits\n");
return -1;
}
2024-11-29 08:23:11 +00:00
switch (nSpeed) {
2024-11-29 08:13:19 +00:00
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 19200:
cfsetispeed(&newtio, B19200);
cfsetospeed(&newtio, B19200);
break;
case 38400:
cfsetispeed(&newtio, B38400);
cfsetospeed(&newtio, B38400);
break;
case 57600:
cfsetispeed(&newtio, B57600);
cfsetospeed(&newtio, B57600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
case 230400:
cfsetispeed(&newtio, B230400);
cfsetospeed(&newtio, B230400);
break;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
break;
case 500000:
cfsetispeed(&newtio, B500000);
cfsetospeed(&newtio, B500000);
break;
case 576000:
cfsetispeed(&newtio, B576000);
cfsetospeed(&newtio, B576000);
break;
case 921600:
cfsetispeed(&newtio, B921600);
cfsetospeed(&newtio, B921600);
break;
case 1000000:
cfsetispeed(&newtio, B1000000);
cfsetospeed(&newtio, B1000000);
break;
case 1152000:
cfsetispeed(&newtio, B1152000);
cfsetospeed(&newtio, B1152000);
break;
case 1500000:
cfsetispeed(&newtio, B1500000);
cfsetospeed(&newtio, B1500000);
break;
case 2500000:
cfsetispeed(&newtio, B2500000);
cfsetospeed(&newtio, B2500000);
break;
case 3000000:
cfsetispeed(&newtio, B3000000);
cfsetospeed(&newtio, B3000000);
break;
default:
printf("\tSorry, Unsupported baud rate, set default 115200!\n");
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
}
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 1;
tcflush(fd, TCIFLUSH);
2024-11-29 08:23:11 +00:00
if (tcsetattr(fd, TCSANOW, &newtio) != 0) {
2024-11-29 08:13:19 +00:00
perror("tcsetattr");
return -1;
}
return 0;
}
int uart_recv(int fd, char *rcv_buf, int data_len, int timeout)
{
int len, fs_sel;
fd_set fs_read;
struct timeval time;
time.tv_sec = timeout / 1000;
time.tv_usec = timeout % 1000 * 1000;
FD_ZERO(&fs_read);
FD_SET(fd, &fs_read);
memset(rcv_buf, 0, data_len);
fs_sel = select(fd + 1, &fs_read, NULL, NULL, &time);
2024-11-29 08:23:11 +00:00
if (fs_sel) {
2024-11-29 08:13:19 +00:00
len = read(fd, rcv_buf, data_len);
return len;
}
else
return -1;
}
int uart_send(int fd, char *send_buf, int data_len)
{
ssize_t ret = 0;
ret = write(fd, send_buf, data_len);
2024-11-29 08:23:11 +00:00
tcdrain(fd);
tcflush(fd, TCOFLUSH);
2024-11-29 08:13:19 +00:00
if (ret == data_len)
return ret;
else
return -1;
}
/*
send what you input
if input nothing, will send the default string
*/
static void uart_send_test(int fd)
{
char send_buf[10240];
int send_len;
uart_printf("=============================================\n");
uart_printf("Please input messages you want to send\n");
2024-11-29 08:23:11 +00:00
while (1) {
2024-11-29 08:13:19 +00:00
scanf("%s", send_buf);
if (strlen(send_buf) == 0)
strcpy(send_buf, test_msg1);
send_len = uart_send(fd, send_buf, strlen(send_buf));
if (send_len > 0)
printf("%s send %d: |%s|\n", m_send_device, send_len, send_buf);
else
printf("send data failed\n");
}
}
/* Receive and re-send the received one */
static void uart_receive_test(int fd, int log)
{
char rcv_buf[1025];
int rcv_len = 0;
2024-11-29 08:23:11 +00:00
while (1) {
2024-11-29 08:13:19 +00:00
rcv_len = uart_recv(fd, rcv_buf, 1000, 10000);
2024-11-29 08:23:11 +00:00
if (rcv_len > 0) {
2024-11-29 08:13:19 +00:00
if (log) {
rcv_buf[rcv_len] = '\0';
printf("%s recv %d: |%s|\n", m_receive_device, rcv_len, rcv_buf);
}
}
else
continue;
2024-11-29 08:23:11 +00:00
2024-11-29 08:13:19 +00:00
usleep(10000);
}
}
static void uart_stability_receive_test(int fd)
{
int len;
char rcv_buf[1025];
unsigned int count = 0;
unsigned int total = 0;
2024-11-29 08:23:11 +00:00
2024-11-29 08:13:19 +00:00
printf("=============== receiving =================== \n");
while (1) {
len = uart_recv(fd, rcv_buf, 1000, 10000);
if (len > 0)
count += len;
usleep(10000);
if (count > 64 * 1024) {
total += count;
count = 0;
uart_printf("%s receive %d B\n", m_receive_device, total);
}
}
}
static void cal_speed(long len, struct timeval start, struct timeval end)
{
long timeused = ((end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec)) / 1000;
printf("===========================================\n");
uart_printf("Len: %ld b, Time: %ldms, Speed: %ld bps\n", len * 8, timeused, (len * 8 * 1000 / timeused));
}
/*
speed test for send
*/
static void uart_speed_test_send(int fd)
{
char buf[1024] = {0};
char send_buf[1025] = {0};
int send_len;
long count = 0;
int i;
uart_printf("type any key to send 100kB \n");
for (i = 0; i < 128; i++)
send_buf[i] = 'A' + i % 10;
2024-11-29 08:23:11 +00:00
while (1) {
2024-11-29 08:13:19 +00:00
scanf("%s", buf);
count = 0;
uart_printf("start send. \n");
2024-11-29 08:23:11 +00:00
for (i = 0; i < 800; i++) {
2024-11-29 08:13:19 +00:00
send_len = uart_send(fd, send_buf, 128);
if (send_len > 0)
count += send_len;
}
uart_printf("send finish: %ld \n", count);
}
}
/* speed test for receive */
static void uart_speed_test_receive(int fd)
{
int rcv_len = 0;
int receive_begin = 0;
long count = 0;
struct timeval start, end;
char rcv_buf[1025] = {0};
printf("=============== receiving ===================\n");
2024-11-29 08:23:11 +00:00
while (1) {
2024-11-29 08:13:19 +00:00
rcv_len = uart_recv(fd, rcv_buf, 1024, 10000);
2024-11-29 08:23:11 +00:00
if (rcv_len > 0) {
if (!receive_begin) {
2024-11-29 08:13:19 +00:00
receive_begin = 1;
gettimeofday(&start, NULL);
count = rcv_len;
2024-11-29 08:23:11 +00:00
} else {
2024-11-29 08:13:19 +00:00
count += rcv_len;
}
2024-11-29 08:23:11 +00:00
} else {
if (receive_begin) {
2024-11-29 08:13:19 +00:00
receive_begin = 0;
gettimeofday(&end, NULL);
cal_speed(count, start, end);
count = 0;
}
count = 0;
}
}
}
int create_fd(const char *device)
{
int fd = -1;
if (is_null_device(device)) {
DBG("device is invalid: %s\n", device);
fd = -1;
2024-11-29 08:23:11 +00:00
} else {
2024-11-29 08:13:19 +00:00
fd = open_device(device);
if (config_device(fd, m_baudrate, 8, 'N', 1) < 0) {
close(fd);
fd = -1;
}
}
return fd;
}
void *create_receive_thread(void *arg)
{
int fd = *(int *)arg;
if ((fd == -1) || (fd == 0)) {
ERR("Invalid UART device file: %d\n", fd);
return NULL;
}
if (m_test_mode == TEST_MODE_PRESSURE)
uart_speed_test_receive(fd);
else if (m_test_mode == TEST_MODE_STABILITY)
uart_stability_receive_test(fd);
else
uart_receive_test(fd, 1);
return NULL;
}
void uart_normal_test(int argc)
{
pthread_t tid;
int send_fd = create_fd(m_send_device);
int rcv_fd = create_fd(m_receive_device);
if (send_fd == -1) {
send_fd = rcv_fd;
if (send_fd == -1) {
uart_printf("send and receive fd are all failed to open \n");
exit(-1);
}
uart_receive_test(send_fd, 1);
2024-11-29 08:23:11 +00:00
} else {
if (argc == SIMPLE_ARGC_NUM)
2024-11-29 08:13:19 +00:00
pthread_create(&tid, NULL, create_receive_thread, &send_fd);
2024-11-29 08:23:11 +00:00
else
2024-11-29 08:13:19 +00:00
pthread_create(&tid, NULL, create_receive_thread, &rcv_fd);
uart_send_test(send_fd);
}
}
void uart_pressure_test(int argc)
{
pthread_t tid;
int send_fd = create_fd(m_send_device);
int rcv_fd = create_fd(m_receive_device);
if (send_fd == -1) {
send_fd = rcv_fd;
if (send_fd == -1) {
uart_printf("send and receive fd are all failed to open \n");
exit(-1);
}
uart_speed_test_receive(send_fd);
2024-11-29 08:23:11 +00:00
} else {
if (argc == SIMPLE_ARGC_NUM)
pthread_create(&tid, NULL, create_receive_thread, &send_fd);
else
pthread_create(&tid, NULL, create_receive_thread, &rcv_fd);
2024-11-29 08:13:19 +00:00
uart_speed_test_send(send_fd);
}
}
void uart_stability_test(void)
{
pthread_t tid = 0;
int send_fd = create_fd(m_send_device);
int recv_fd = create_fd(m_receive_device);
if (send_fd == -1) {
send_fd = create_fd(m_receive_device);
if (send_fd == -1) {
DBG("send and receive fd are all failed to open \n");
exit(-1);
}
uart_receive_test(send_fd, 0);
} else {
int len;
unsigned int count = 0;
unsigned int total = 0;
pthread_create(&tid, NULL, create_receive_thread, &recv_fd);
printf("=============== sending ===================== \n");
while (1) {
len = uart_send(send_fd, test_msg2, strlen(test_msg2));
if (len > 0)
count += len;
usleep(10000);
if (count > 64 * 1024) {
total += count;
count = 0;
uart_printf("%s send %d B\n", m_send_device, total);
}
}
}
}
/* Circle RX/TX of one Port for send receive test */
2024-11-29 08:23:11 +00:00
static void uart_circle_test(int times)
2024-11-29 08:13:19 +00:00
{
int send_len = 0;
int rcv_len = 0;
2024-11-29 08:23:11 +00:00
int count = 0;
2024-11-29 08:13:19 +00:00
int fd = create_fd(m_send_device);
char rcv_buf[1025];
2025-08-14 07:13:29 +00:00
if (fd == -1) {
DBG("failed to open %s\n", m_send_device);
exit(-1);
}
2024-11-29 08:13:19 +00:00
2024-11-29 08:23:11 +00:00
while (1) {
2024-11-29 08:13:19 +00:00
send_len = uart_send(fd, test_msg1, strlen(test_msg1));
if (send_len > 0)
uart_printf("send data is: %s\n", test_msg1);
else
uart_printf("send data failed\n");
2024-11-29 08:23:11 +00:00
usleep(20000);
2024-11-29 08:13:19 +00:00
rcv_len = uart_recv(fd, rcv_buf, 100, 10000);
2024-11-29 08:23:11 +00:00
if (rcv_len > 0) {
2024-11-29 08:13:19 +00:00
rcv_buf[rcv_len] = '\0';
uart_printf("receive data is: %s\n", rcv_buf);
2024-11-29 08:23:11 +00:00
} else {
2024-11-29 08:13:19 +00:00
uart_printf("receive data failed\n");
continue;
}
2024-11-29 08:23:11 +00:00
if (strcmp(test_msg1, rcv_buf) || send_len != rcv_len) {
2024-11-29 08:13:19 +00:00
uart_printf(" tested failed !\n");
uart_printf("send: %d [%s]\n", send_len, test_msg1);
uart_printf("receive: %d [%s]\n", rcv_len, rcv_buf);
}
2024-11-29 08:23:11 +00:00
else
uart_printf("Test Success !\n");
count ++;
if(times == count)
break;
2024-11-29 08:13:19 +00:00
usleep(5000000);
}
}
int main(int argc, char *argv[])
{
if (argc != SIMPLE_ARGC_NUM && argc != NORMAL_ARGC_NUM) {
print_usage(argv[0]);
exit(-1);
}
if (parse_opts(argc, argv) < 0) {
print_usage(argv[0]);
exit(-1);
}
print_parameter(argc);
switch (m_test_mode) {
case TEST_MODE_NORMAL:
uart_normal_test(argc);
break;
case TEST_MODE_PRESSURE:
uart_pressure_test(argc);
break;
case TEST_MODE_STABILITY:
uart_stability_test();
break;
case TEST_MODE_CIRCLE:
2024-11-29 08:23:11 +00:00
uart_circle_test(-1);
break;
case TEST_MODE_CIRCLE_X1:
uart_circle_test(1);
2024-11-29 08:13:19 +00:00
break;
default:
ERR("Unsupported mode: %d\n", m_test_mode);
return -1;
}
return 0;
}