uart命令测试工具

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值