You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4中C程序以服务运行时无法写入USB端口的问题

问题分析与解决方案

核心问题

你的C程序手动运行正常,但通过systemd Path单元触发的服务运行时,出现Bad file descriptor错误,无法写入USB串口/dev/ttyUSB0。根源在于服务触发时机与设备就绪状态不匹配,加上程序本身的串口操作逻辑存在优化空间。


一、修正systemd单元配置

1. 替换Path单元监控目标

原Path单元监控/sys/class/net/usb0(USB以太网接口),但该接口就绪时,USB串口/dev/ttyUSB0可能尚未完成初始化或权限配置。直接监控串口设备节点:

# /etc/systemd/system/usb_trigger.path
[Unit]
Description=Path unit for LoRa USB serial port

[Path]
PathExists=/dev/ttyUSB0
Unit=your_service_name.service

[Install]
WantedBy=multi_user.target

2. 优化Service单元依赖与生命周期

添加设备绑定规则,确保服务与串口设备生命周期同步,避免设备未就绪时启动服务:

# /etc/systemd/system/your_service_name.service
[Unit]
Description=LoRa CAN Data Forwarder
After=sys-devices-platform-serial8250-tty-ttyUSB0.device network.target
BindsTo=sys-devices-platform-serial8250-tty-ttyUSB0.device

[Service]
Type=simple
User=fstlisboa
Group=dialout
ExecStart=/home/fstlisboa/software-13/lora/bin/lora-linux-main.out
Restart=always
RestartSec=2

[Install]
WantedBy=multi_user.target

3. 更可靠的触发方式:使用udev规则

如果串口设备节点名称可能变化(如ttyUSB1),创建udev规则精准匹配LoRa模块,确保设备就绪时触发服务:

创建/etc/udev/rules.d/99-lora-serial.rules:

SUBSYSTEM=="tty", ATTRS{idVendor}=="XXXX", ATTRS{idProduct}=="YYYY", GROUP="dialout", MODE="0660", SYMLINK+="lora_serial", TAG+="systemd", ENV{SYSTEMD_WANTS}="your_service_name.service"
  • 替换XXXX和YYYY为LoRa模块的USB厂商/产品ID(用lsusb命令查看)
  • 自动创建软链接/dev/lora_serial,程序中可改用该路径避免设备名称变化问题

二、优化C程序串口操作逻辑

1. 移除无效的内存检查

char msg[strlen(str) + 4];是栈上分配的变长数组,永远不会返回NULL,该判断无效,且可能导致栈溢出。改为动态分配:

void send_msg(Lora lora, char *str)
{
    int serial_port_fd = open_port(USB_PORT);
    if (serial_port_fd < 0) {
        return;
    }

    size_t msg_len = strlen(str) + 4;
    char *msg = malloc(msg_len);
    if (msg == NULL) {
        perror("ERROR memory allocation failed");
        close(serial_port_fd);
        return;
    }

    msg[0] = lora.dest_adress_high;
    msg[1] = lora.dest_adresss_low;
    msg[2] = lora.dest_freq;
    strcpy(msg + 3, str); // 替换原循环,简化逻辑

    if (write(serial_port_fd, msg, msg_len) < 0) {
        perror("ERRO writing msg failed");
    }

    free(msg);
    close(serial_port_fd);
}

2. 避免频繁打开/关闭串口

每次发送都打开关闭串口会增加系统调用开销和出错概率,改为程序初始化时打开一次,全局复用:

int global_serial_fd = -1;

int main() {
    // ...其他初始化逻辑
    global_serial_fd = open_port(USB_PORT);
    if (global_serial_fd < 0) {
        perror("Failed to open LoRa serial port");
        exit(EXIT_FAILURE);
    }

    // ...创建线程等操作

    // 程序结束时关闭串口
    close(global_serial_fd);
    free(can_lora_array);
    return 0;
}

void send_msg(Lora lora, char *str)
{
    if (global_serial_fd < 0) {
        perror("Serial port not initialized");
        return;
    }

    size_t msg_len = strlen(str) + 4;
    char *msg = malloc(msg_len);
    if (msg == NULL) {
        perror("ERROR memory allocation failed");
        return;
    }

    msg[0] = lora.dest_adress_high;
    msg[1] = lora.dest_adresss_low;
    msg[2] = lora.dest_freq;
    strcpy(msg + 3, str);

    if (write(global_serial_fd, msg, msg_len) < 0) {
        perror("ERRO writing msg failed");
    }

    free(msg);
}

三、验证与调试

  1. 重新加载systemd配置:
sudo systemctl daemon-reload
sudo systemctl enable --now usb_trigger.path your_service_name.service
  1. 查看服务实时日志:
journalctl -u your_service_name.service -f
  1. 检查串口设备权限:
ls -l /dev/ttyUSB0

确保组为dialout,权限包含rw。

内容的提问来源于stack exchange,提问作者ElOvo123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:24:52