#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <signal.h>
#include <ctype.h>
volatile int keep_running = 1;
void signal_handler(int sig) {
if (sig == SIGINT)
keep_running = 0;
}
// 配置串口:波特率,8N1,无流控,非规范模式
int setup_serial(int fd, int baudrate) {
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
perror("tcgetattr");
return -1;
}
cfsetospeed(&tty, baudrate);
cfsetispeed(&tty, baudrate);
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= CREAD | CLOCAL;
tty.c_lflag &= ~ICANON;
tty.c_lflag &= ~ECHO;
tty.c_lflag &= ~ECHOE;
tty.c_lflag &= ~ECHONL;
tty.c_lflag &= ~ISIG;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_iflag &= ~(INLCR | ICRNL | IGNCR);
tty.c_oflag &= ~OPOST;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 10;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("tcsetattr");
return -1;
}
return 0;
}
// 解析十六进制字符串,返回字节数组和长度
// 支持两种格式:
// 1. "0102AABB" 连续十六进制
// 2. "01 02 AA BB" 空格分隔(也可无空格)
// 返回的 buffer 需调用者 free
unsigned char* parse_hex(const char *hexstr, size_t *out_len) {
// 去除空格,计算有效十六进制字符个数
size_t len = strlen(hexstr);
char *clean = malloc(len + 1);
if (!clean) return NULL;
int j = 0;
for (size_t i = 0; i < len; i++) {
if (isxdigit(hexstr[i]))
clean[j++] = hexstr[i];
}
clean[j] = '\0';
if (j % 2 != 0) {
fprintf(stderr, "错误:十六进制字符串必须包含偶数个字符(当前有 %d 个十六进制字符)\n", j);
free(clean);
return NULL;
}
*out_len = j / 2;
unsigned char *data = malloc(*out_len);
if (!data) {
free(clean);
return NULL;
}
for (size_t i = 0; i < *out_len; i++) {
char byte_str[3] = {clean[2*i], clean[2*i+1], '\0'};
data[i] = (unsigned char) strtoul(byte_str, NULL, 16);
}
free(clean);
return data;
}
void print_usage(const char *prog) {
fprintf(stderr, "用法: %s [选项] <串口设备> <波特率> [数据] [间隔ms]\n", prog);
fprintf(stderr, "或: %s [选项] <串口设备> <波特率> -x <十六进制数据> [间隔ms]\n", prog);
fprintf(stderr, "选项:\n");
fprintf(stderr, " -x 表示后续数据为十六进制字节(例如 \"01 02 FF\" 或 \"0102FF\")\n");
fprintf(stderr, "示例:\n");
fprintf(stderr, " 发送字符串: %s /dev/ttyS8 115200 \"Hello\\r\\n\" 500\n", prog);
fprintf(stderr, " 发送十六进制: %s /dev/ttyS8 115200 -x \"01 02 03 FF\" 500\n", prog);
fprintf(stderr, " 发送十六进制连续: %s /dev/ttyS8 115200 -x \"010203FF\" 500\n", prog);
}
int main(int argc, char *argv[]) {
if (argc < 4) {
print_usage(argv[0]);
return 1;
}
const char *device = argv[1];
int baudrate;
int br = atoi(argv[2]);
switch (br) {
case 9600: baudrate = B9600; break;
case 115200: baudrate = B115200; break;
case 57600: baudrate = B57600; break;
case 38400: baudrate = B38400; break;
default: baudrate = B9600; break;
}
int hex_mode = 0;
const char *data_arg = NULL;
int interval_ms = 1000;
int arg_index = 3;
// 检查是否有 -x 选项
if (strcmp(argv[3], "-x") == 0) {
hex_mode = 1;
if (argc < 5) {
fprintf(stderr, "错误:-x 后需要十六进制数据\n");
print_usage(argv[0]);
return 1;
}
data_arg = argv[4];
arg_index = 5;
} else {
data_arg = argv[3];
arg_index = 4;
}
if (arg_index < argc) {
interval_ms = atoi(argv[arg_index]);
if (interval_ms <= 0) interval_ms = 1000;
}
// 打开串口
int fd = open(device, O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("open");
return 1;
}
if (setup_serial(fd, baudrate) != 0) {
close(fd);
return 1;
}
signal(SIGINT, signal_handler);
// 准备要发送的数据
unsigned char *send_data = NULL;
size_t send_len = 0;
int free_data = 0;
if (hex_mode) {
send_data = parse_hex(data_arg, &send_len);
if (!send_data) {
close(fd);
return 1;
}
free_data = 1;
printf("十六进制模式,共 %zu 字节:", send_len);
for (size_t i = 0; i < send_len; i++)
printf("%02X ", send_data[i]);
printf("\n");
} else {
send_len = strlen(data_arg);
send_data = (unsigned char*)data_arg; // 直接使用字符串指针,不释放
printf("字符串模式,长度 %zu 字节:%s\n", send_len, data_arg);
}
printf("串口: %s 波特率: %d 间隔: %d ms\n", device, br, interval_ms);
printf("按 Ctrl+C 退出...\n");
while (keep_running) {
ssize_t written = write(fd, send_data, send_len);
if (written < 0) {
perror("write");
break;
}
if (written != (ssize_t)send_len) {
fprintf(stderr, "警告:只写入了 %zd / %zu 字节\n", written, send_len);
}
usleep(interval_ms * 1000);
}
printf("\n退出。\n");
close(fd);
if (free_data && send_data)
free(send_data);
return 0;
}
uart命令测试工具
于 2026-05-11 17:35:03 首次发布

2480

被折叠的 条评论
为什么被折叠?



