Linux串口出厂测试工具与使用说明

news2024/11/16 19:26:49

1、说明

本文针对Linux系统上如何对各类串口硬件进行出厂测试进行硬件连接和软件使用说明,提供的软件测试工具wchsertest,适用于USB、PCI、PCIe转串口设备等、同样也适用于原生ttyS串口。

2、串口测试硬件连接

在测试前,需要制作单独的硬件治具,按下表连接信号线:

串口针式座子(DB9)硬件连线

引脚名

引脚号

引脚名

引脚号

RTS

7

<---------------------->

CTS

8

RTS

7

<---------------------->

RI

9

TXD

3

<---------------------->

RXD

2

DTR

4

<---------------------->

DSR

6

DTR

4

<---------------------->

CD

1

引脚连接示意图:

3、软件使用方法

(1)插入待测试USB/PCI/PCIe转串口设备。

(2)以CH342F(USB转2串口芯片)为例,安装对应VCP厂商驱动程序,进入/dev目录查看出现如下设备节点:

以CH382为例,安装对应VCP厂商驱动程序,进入/dev目录查看出现如下设备节点:

(3)运行软件,输入命令格式:

./[可执行文件] –D [设备节点路径]

实例1(测试CH342的UART0):sudo ./serial_port_test -D /dev/ttyCH343USB0

实例2(测试CH382的UART0):sudo ./serial_port_test -D /dev/ttyWCH0

4、测试错误码说明

根据输出的错误码和终端输出信息可判断故障信号线,下表为错误码和说明。

错误码

错误码说明

0

DTR--DSR线错误

1

DTR--DCD线错误

2

RTS--CTS线错误

3

RTS--RI线错误

4

TXD--RXD线错误

5、测试实例

(1)测试成功实例

软件分别以2400bps、9600bps、115200bps各测试一次。

 

(2)测试错误实例

根据输出信息可知,DTR—DSR信号通讯存在错误,错误码:0。

6、wchsertest工具源码

/*
 * serial port factory test utility.
 *
 * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd.
 * Web:     http://wch.cn
 * Author:  WCH <tech@wch.cn>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Cross-compile with cross-gcc -I /path/to/cross-kernel/include
 *
 * V1.0 - initial version
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <getopt.h>
#include <linux/serial.h>
#include <stdbool.h>
#define termios asmtermios
#include <asm/termios.h>
#undef termios
#include <termios.h>

#define DTR_ON	    1
#define DTR_OFF	    0
#define RTS_ON	    1
#define RTS_OFF	    0
#define BUF_SIZE    64
#define DTR_ON_CMD  0x0
#define DTR_OFF_CMD 0x1
#define RTS_ON_CMD  0x2
#define RTS_OFF_CMD 0x3

extern int ioctl(int d, int request, ...);

static const char *device = "/dev/ttyCH343USB0";
static int hardflow = 0;
static int verbose = 0;
static FILE *fp;

static const struct option lopts[] = {
	{ "device", required_argument, 0, 'D' },
	{ NULL, 0, 0, 0 },
};

static void print_usage(const char *prog)
{
	printf("Usage: %s [-DSvf]\n", prog);
	puts("  -D --device    tty device to use\n");
	exit(1);
}

static void parse_opts(int argc, char *argv[])
{
	int c;

	while (1) {
		c = getopt_long(argc, argv, "D:S:h", lopts, NULL);
		if (c == -1) {
			break;
		}
		switch (c) {
		case 'D':
			if (optarg != NULL)
				device = optarg;
			break;
		case 'h':
		default:
			print_usage(argv[0]);
			break;
		}
	}
}

/**
 * libtty_setcustombaudrate - set baud rate of tty device
 * @fd: device handle
 * @speed: baud rate to set
 *
 * The function return 0 if success, or -1 if fail.
 */
static int libtty_setcustombaudrate(int fd, int baudrate)
{
	struct termios2 tio;

	if (ioctl(fd, TCGETS2, &tio)) {
		perror("TCGETS2");
		return -1;
	}

	tio.c_cflag &= ~CBAUD;
	tio.c_cflag |= BOTHER;
	tio.c_ispeed = baudrate;
	tio.c_ospeed = baudrate;

	if (ioctl(fd, TCSETS2, &tio)) {
		perror("TCSETS2");
		return -1;
	}

	if (ioctl(fd, TCGETS2, &tio)) {
		perror("TCGETS2");
		return -1;
	}

	return 0;
}

/**
 * libtty_setopt - config tty device
 * @fd: device handle
 * @speed: baud rate to set
 * @databits: data bits to set
 * @stopbits: stop bits to set
 * @parity: parity to set
 * @hardflow: hardflow to set
 *
 * The function return 0 if success, or -1 if fail.
 */
static int libtty_setopt(int fd, int speed, int databits, int stopbits, char parity, char hardflow)
{
	struct termios newtio;
	struct termios oldtio;
	int i;

	bzero(&newtio, sizeof(newtio));
	bzero(&oldtio, sizeof(oldtio));

	if (tcgetattr(fd, &oldtio) != 0) {
		perror("tcgetattr");
		return -1;
	}
	newtio.c_cflag |= CLOCAL | CREAD;
	newtio.c_cflag &= ~CSIZE;

	/* set data bits */
	switch (databits) {
	case 5:
		newtio.c_cflag |= CS5;
		break;
	case 6:
		newtio.c_cflag |= CS6;
		break;
	case 7:
		newtio.c_cflag |= CS7;
		break;
	case 8:
		newtio.c_cflag |= CS8;
		break;
	default:
		fprintf(stderr, "unsupported data size\n");
		return -1;
	}

	/* set parity */
	switch (parity) {
	case 'n':
	case 'N':
		newtio.c_cflag &= ~PARENB; /* Clear parity enable */
		newtio.c_iflag &= ~INPCK;  /* Disable input parity check */
		break;
	case 'o':
	case 'O':
		newtio.c_cflag |= (PARODD | PARENB); /* Odd parity instead of even */
		newtio.c_iflag |= INPCK;	     /* Enable input parity check */
		break;
	case 'e':
	case 'E':
		newtio.c_cflag |= PARENB;  /* Enable parity */
		newtio.c_cflag &= ~PARODD; /* Even parity instead of odd */
		newtio.c_iflag |= INPCK;   /* Enable input parity check */
		break;
	default:
		fprintf(stderr, "unsupported parity\n");
		return -1;
	}

	/* set stop bits */
	switch (stopbits) {
	case 1:
		newtio.c_cflag &= ~CSTOPB;
		break;
	case 2:
		newtio.c_cflag |= CSTOPB;
		break;
	default:
		perror("unsupported stop bits\n");
		return -1;
	}

	if (hardflow)
		newtio.c_cflag |= CRTSCTS;
	else
		newtio.c_cflag &= ~CRTSCTS;

	newtio.c_cc[VTIME] = 10; /* Time-out value (tenths of a second) [!ICANON]. */
	newtio.c_cc[VMIN] = 64; /* Minimum number of bytes read at once [!ICANON]. */

	tcflush(fd, TCIOFLUSH);

	if (tcsetattr(fd, TCSANOW, &newtio) != 0) {
		perror("tcsetattr");
		return -1;
	}

	/* set tty speed */
	if (libtty_setcustombaudrate(fd, speed) != 0) {
		perror("setbaudrate");
		return -1;
	}

	return 0;
}

/**
 * libtty_open - open tty device
 * @devname: the device name to open
 *
 * In this demo device is opened blocked, you could modify it at will.
 */
static int libtty_open(const char *devname)
{
	int fd = open(devname, O_RDWR | O_NOCTTY);
	int flags = 0;

	if (fd < 0) {
		perror("open device failed");
		return -1;
	}

	if (fcntl(fd, F_SETFL, 0) < 0) {
		printf("fcntl failed.\n");
		return -1;
	}

	if (isatty(fd) == 0) {
		printf("not tty device.\n");
		return -1;
	}

	return fd;
}

/**
 * libtty_close - close tty device
 * @fd: the device handle
 *
 * The function return 0 if success, others if fail.
 */
static int libtty_close(int fd)
{
	return close(fd);
}

/**
 * libtty_tiocmset - modem set
 * @fd: file descriptor of tty device
 * @bDTR: 0 on inactive, other on DTR active
 * @bRTS: 0 on inactive, other on RTS active
 *
 * The function return 0 if success, others if fail.
 */
static int libtty_tiocmset(int fd, char bDTR, char bRTS)
{
	unsigned long controlbits = 0;

	if (bDTR)
		controlbits |= TIOCM_DTR;
	if (bRTS)
		controlbits |= TIOCM_RTS;

	return ioctl(fd, TIOCMSET, &controlbits);
}

/**
 * libtty_tiocmget - modem get
 * @fd: file descriptor of tty device
 * @modembits: pointer to modem status
 *
 * The function return 0 if success, others if fail.
 */
static int libtty_tiocmget_check(int fd, unsigned long *modembits, int cmd)
{
	int ret = 0;

	ret = ioctl(fd, TIOCMGET, modembits);
	if (ret == 0) {
		switch (cmd) {
		case DTR_OFF_CMD: // DTR--DSR/DCD
			if ((*modembits & TIOCM_DSR) != 0) {
				printf("[error code: %d] DTR--DSR ERROR\n", 0);
				ret = -1;
			}
			if ((*modembits & TIOCM_CD) != 0) {
				printf("[error code: %d] DTR--DCD ERROR\n", 1);
				ret = -1;
			}
			break;
		case DTR_ON_CMD:
			if ((*modembits & TIOCM_DSR) == 0) {
				printf("[error code: %d] DTR--DSR ERROR\n", 0);
				ret = -1;
			}
			if ((*modembits & TIOCM_CD) == 0) {
				printf("[error code: %d] DTR--DCD ERROR\n", 1);
				ret = -1;
			}
			break;
		case RTS_OFF_CMD: // RTS--CTS/RI
			if ((*modembits & TIOCM_CTS) != 0) {
				printf("[error code: %d] RTS--CTS ERROR\n", 2);
				ret = -1;
			}
			if ((*modembits & TIOCM_RI) != 0) {
				printf("[error code: %d] RTS--RI ERROR\n", 3);
				ret = -1;
			}
			break;
		case RTS_ON_CMD:
			if ((*modembits & TIOCM_CTS) == 0) {
				printf("[error code: %d] RTS--CTS ERROR\n", 2);
				ret = -1;
			}
			if ((*modembits & TIOCM_RI) == 0) {
				printf("[error code: %d] RTS--RI ERROR\n", 3);
				ret = -1;
			}
			break;
		default:
			break;
		}
	}
	return ret;
}

static void sig_handler(int signo)
{
	printf("capture sign no:%d\n", signo);
	if (fp != NULL) {
		fflush(fp);
		fsync(fileno(fp));
		fclose(fp);
	}
	exit(0);
}

void start_test(int fd)
{
	int ret, i, times, num, nwrite, nread, len;
	int len_w, pos_w, ret1, ret2, ret3;
	int total = 0, off_w, off_r;
	char c;
	unsigned long modemstatus;
	unsigned char buf_write[BUF_SIZE];
	unsigned char buf_read[BUF_SIZE];

	memset(buf_write, 0x00, BUF_SIZE);
	memset(buf_read, 0x00, BUF_SIZE);

	for (times = 0; times < 64; times++) {
		for (i = 0; i < BUF_SIZE; i++)
			buf_write[i] = i + BUF_SIZE * (times % 4);

		/* Send 64 bytes */
        off_w = 0;
        len = BUF_SIZE;
        while (len > 0) {
            nwrite = write(fd, buf_write + off_w, len);
            if (nwrite < 0) {
                perror("write");
                exit(1);
            }
            off_w += nwrite;
            len -= nwrite;
        }
        
		/* Receive and judge */
        off_r = 0;
		while (nwrite > 0) {
			nread = read(fd, buf_read + off_r, nwrite);
            if (nread < 0) {
                printf("read error!\n");
				exit(1);
            }
            off_r += nread;
            nwrite -= nread;
		}

		total += nread;

		/* compare the buffer contents */
		if (memcmp(buf_read, buf_write, BUF_SIZE) != 0) {
			printf("[error code: %d] TXD/RXD test error\n", 4);
			goto exit;
		}
	}
	printf("TXD/RXD test passed\n");

	/* Set DTR invalid */
	if (libtty_tiocmset(fd, DTR_OFF, RTS_OFF) != 0)
		goto exit;
	usleep(10000);
	ret1 = libtty_tiocmget_check(fd, &modemstatus, DTR_OFF_CMD);

	/* Set DTR valid */
	if (libtty_tiocmset(fd, DTR_ON, RTS_OFF) != 0)
		goto exit;
	usleep(10000);
	ret2 = libtty_tiocmget_check(fd, &modemstatus, DTR_ON_CMD);

	/* Set RTS valid */
	if (libtty_tiocmset(fd, DTR_OFF, RTS_ON) != 0)
		goto exit;
	usleep(10000);
	ret3 = libtty_tiocmget_check(fd, &modemstatus, RTS_ON_CMD);

	if ((ret1 || ret2 || ret3) == 0)
		printf("DTR/RTS/DSR/CTS/DCD/RI test passed\n");
	printf("\n");

exit:
	return;
}

int main(int argc, char *argv[])
{
	int fd, ret, i, num, nwrite, nread;
	int len_w, pos_w, ret1, ret2, ret3, ret4;
	int total = 0, off = 0;
	char c;
	unsigned long modemstatus;
	unsigned char buf_write[BUF_SIZE];
	unsigned char buf_read[BUF_SIZE];

	parse_opts(argc, argv);
	signal(SIGINT, sig_handler);

	fd = libtty_open(device);
	if (fd < 0) {
		printf("libtty_open: %s error.\n", device);
		exit(0);
	}

	/* 2400bps test */
	ret = libtty_setopt(fd, 2400, 8, 1, 'n', hardflow);
	if (ret != 0) {
		printf("libtty_setopt error.\n");
		exit(0);
	}
	start_test(fd);

	/* 9600bps test */
	ret = libtty_setopt(fd, 9600, 8, 1, 'n', hardflow);
	if (ret != 0) {
		printf("libtty_setopt error.\n");
		exit(0);
	}
	start_test(fd);

	/* 115200bps test */
	ret = libtty_setopt(fd, 115200, 8, 1, 'n', hardflow);
	if (ret != 0) {
		printf("libtty_setopt error.\n");
		exit(0);
	}
	start_test(fd);

	ret = libtty_close(fd);
	if (ret != 0) {
		printf("libtty_close error.\n");
		exit(0);
	}

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/410486.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

寸照换底色技巧大全,超详细图文教程

在日常的设计工作中&#xff0c;我们常常需要将图片的背景色进行修改&#xff0c;以适应不同的场景和需求。其中最常用的方法就是寸照换底色技巧。本文将为大家介绍一些常见的寸照换底色技巧&#xff0c;并提供超详细的图文教程&#xff0c;帮助大家轻松完成这项任务。 一、使…

2023最新面试题-Java-6

1. Date API Java 8 在包java.time下包含了一组全新的时间日期API。新的日期API和开源的Joda-Time库差不多&#xff0c;但 又不完全一样&#xff0c;下面的例子展示了这组新API里最重要的一些部分&#xff1a; Clock类提供了访问当前日期和时间的方法&#xff0c;Clock是时区敏…

springboot加载命令行参数ApplicationArguments

往期文章 springcloud整合knike4j聚合微服务接口文档 spring源码 - 条件注解ConditionnalOnClass的原理分析 springboot项目实现导出pdf功能&#xff0c;这也太简单了吧 目录 文章目录往期文章目录一、介绍二、通过应用程序参数获取配置1. 通过bean获取应用程序参数2. 通过V…

在外web浏览器远程访问jupyter notebook服务器

文章目录前言视频教程1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口5. 固定公网地址转载自远控源码文章&#xff1a;公网远程访问jupyter notebook【cpolar内网穿透】 前言 Jupyter Notebook&#…

我现在必须new一个对象!!!

目录 前言 1.new 2.delete 3.底层逻辑 4.定位new 5.对比 前言 &#x1f383;之前在使用C语言的时候&#xff0c;我们便使用 malloc 和 calloc 等函数进行动态内存的开辟。但 C 之中又引入了两个操作符 new 和 delete 来代替C语言中的函数进行动态内存的管理。下面就一起…

苏州源特VPT87DDF01B 隔离变压器 小体积/SMD/3000VDC 隔离

1 产品特点  小体积隔离变压器  隔离电压 3000VDC  工作温度&#xff1a;-40~125℃&#xff08;包含产品温升&#xff09;  存储温度&#xff1a;-55~125℃  SMD 表贴安装  回流焊温度&#xff1a;峰值温度≤250℃&#xff08;10s&#xff09;  回流焊次数&#…

Softing新版HART多路复用器软件支持西门子控制器

用于访问配置和诊断数据的HART多路复用器软件——Softing smartLink SW-HT&#xff0c;现在支持西门子的ET200远程IO和FDT/DTM接口。 smartLink SW-HT是一个基于Docker容器的软件应用。通过该软件&#xff0c;用户可以快速地访问以太网远程IO的HART设备&#xff0c;并且无需额外…

【Linux】进程间通信之管道(pipe)

文章目录前言为什么要进程间通信进程间通信的理论依据管道管道的原理创建匿名管道管道的特点管道的场景利用管道控制子进程命名管道命名管道的打开规则命名管道和匿名管道的区别用命名管道实现server和client通信前言 大家好久不见&#xff0c;今天开始我们将进入进程间通信章…

redis高可用方案:主从复制+哨兵模式,经典案例:一主二从三哨兵,及springboot集成配置

Redis高可用方案&#xff1a;主从复制哨兵模式 经典案例&#xff1a;一主二从三哨兵&#xff0c;及springboot集成配置 第一.配置 1.主节点配置&#xff08;redis.conf&#xff09; # 主节点配置 仅展示必要配置 redis.conf # 保护模式设置为关&#xff0c;方便其他节点访问…

推荐几款炫酷的 MySQL 可视化管理工具!好用到爆!!

MySQL 的管理维护工具非常多&#xff0c;除了系统自带的命令行管理工具之外&#xff0c;还有许多其他的图形化管理工具&#xff0c;工具好用是一方面&#xff0c;个人的使用习惯也很重要&#xff0c;这里介绍 13 款 MySQL 图形化管理工具&#xff0c;供大家参考。 1&#xff1a…

vite .env.test环境使用ant design vue ,打包后a-date-picker控件无法选择日期

前端开发后台管理系统&#xff0c;常用的UI库当属Element UI和 Ant Design Vue&#xff0c;但是前段时间遇到一个奇葩问题&#xff0c;在这里记录一下&#xff0c;防止小伙伴们踩坑。 后台系统&#xff0c;大家肯定都用过时间控件&#xff0c;本期我们使用的是ant design vue&…

2道关于chan的面试题

题目一: 下面关于通道描述正确的是: 1.读nil chan会触发panic 2.写nil chan会触发panic 3.读关闭的chan会触发panic 4.写关闭的chan会触发panic解答&#xff1a;这个提涉及到2个知识点&#xff0c;操作nil的chan会怎么样&#xff0c;操作关闭的chan会怎么样&#xff0c;下面我…

双目相机测距原理

双目相机测距是一种常用的计算机视觉技术&#xff0c;它利用两个摄像头同时拍摄同一场景&#xff0c;通过测量两个摄像头视野中同一物体在图像上的像素差异&#xff0c;从而计算出物体距离的方法。 具体原理如下&#xff1a; 双目相机的构成 双目相机由两个摄像头组成&#…

用ChatGPT怎么赚钱?普通人用这5个方法也能赚到生活费

ChatGPT在互联网火得一塌糊涂&#xff0c;因为它可以帮很多人解决问题。比如&#xff1a;帮编辑人员写文章&#xff0c;还可以替代程序员写代码&#xff0c;帮策划人员写文案策划等等。ChatGPT这么厉害&#xff0c;能否用它来赚钱呢&#xff1f;今天和大家分享用ChatGPT赚钱的5…

Cesium关于3Dtiles的细节分享

介绍 介绍一下Cesium中有关3dTiles的奇淫技巧&#xff0c;存在一些埋坑的地方&#xff0c;以下内容仅为自己摸索的细节和方法&#xff0c;仅供参考&#xff0c;若有更好的办法欢迎讨论 通用快速获取feature中包含的属性信息 有时候需要快速获得3dTiles中的feature中的属性信…

deb文件如何安装到iphone方法分享

Cydia或同类APT管理软件在线安装 Cydia或同类APT管理软件在线安装,这个是最佳的安装方式,因为通常无需考虑依赖关系,但缺点是对网络的要求比较高;命令行中以dpkg-iXXX.deb的形式安装,好处是可以以通配符一次性安装多个deb,而且也可以直接看到脚本的运行状况和安装成功/失…

执行命令行程序测试自动化

这几天有一个小工具需要做测试&#xff0c;是一个命令行工具&#xff0c;这个命令行工具有点类似mdbg等命令行工具&#xff0c;即程序运行后&#xff0c;在命令行等待用户敲入的命令&#xff0c;处理命令并显示结果&#xff0c;再继续等待用户敲入新的命令。 原来的测试用例都…

Vue实现自动化平台(五)--用例编辑页面

上一章&#xff1a;Vue实现自动化平台&#xff08;四&#xff09;--接口管理页面的实现_做测试的喵酱的博客-CSDN博客 github地址&#xff1a;https://github.com/18713341733/vuemiaotest 这个目前只是用来练手的&#xff0c;项目还没成型。等以后我写完了&#xff0c;再更…

公网远程访问局域网SQL Server数据库【无公网IP内网穿透】

目录 1.前言 2.本地安装和设置SQL Server 2.1 SQL Server下载 2.2 SQL Server本地连接测试 2.3 Cpolar内网穿透的下载和安装 2.3 Cpolar内网穿透的注册 3.本地网页发布 3.1 Cpolar云端设置 3.2 Cpolar本地设置 4.公网访问测试 5.结语 转发自CSDN远程穿透的文章&…

不用但一定要懂 ---- iOS 之 响应链、传递链 与 手势识别

iOS 事件的主要由&#xff1a;响应连 和 传递链 构成。一般事件先通过传递链&#xff0c;传递下去。响应链&#xff0c;如果上层不能响应&#xff0c;那么一层一层通过响应链找到能响应的UIResponse。 响应链&#xff1a;由最基础的view向系统传递&#xff0c;first view ->…