首页 > 解决方案 > 当 RTS/CTS 流控制打开时,串行 write() 停止发送

问题描述

我正在尝试通过串行端口 (/dev/ttyS0) 从我的 Ubuntu 机器向 RS232-CAN 适配器重复发送数据。该消息包含 19 个字节的数据,每秒发送大约 4 次。在运行的前 5-20 分钟内一切正常,但突然发送停止并且 write() 调用将继续填充输出缓冲区,直到超过 4096 字节,此时 write() 调用开始失败。

仅当通过属性标志 CRTSCTS 启用硬件流控制时才会出现此问题。起初我认为问题是 CTS 线路收到停止信号,但在程序运行时检查此标志总是将其显示为 ON。事实上,在发送停止发生的那一刻,调制解调器控制标志似乎都没有改变。

数据发送停止是突然的,一旦发生,在程序重新启动之前不会再次发送数据。我尝试在 write() 之后使用 select() (发送停止后总是超时)和 tcdrain() (发送停止后永远阻塞)。数据内容也不重要。我尝试发送正确格式的 CAN 消息和随机垃圾,但无论哪种方式都会出现问题。

另一端的设备配置为使用硬件流控制,我尝试使用 115200 和 57600 的波特率。我不确定还有什么检查可能导致问题。启用 RTS/CTS 时是否缺少其他步骤或配置设置?打开 RTS/CTS 是否会添加我没有考虑的额外检查?

代码

int SetAttributes (int fd, int speed, int parity)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);

        if (tcgetattr (fd, &tty) != 0)
        {
            printf ("error %d from tcgetattr", errno);
            return -1;
        }

        cfsetospeed (&tty, speed);
        cfsetispeed (&tty, speed);

        tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;

        tty.c_iflag &= ~IGNBRK;
        tty.c_lflag = 0;
        tty.c_oflag = 0;
        tty.c_cc[VMIN]  = 0;
        tty.c_cc[VTIME] = 5;
        tty.c_iflag &= ~(IXON | IXOFF | IXANY);
        tty.c_cflag |= (CLOCAL | CREAD);
        tty.c_cflag &= ~(PARENB | PARODD);
        tty.c_cflag |= parity;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag |= CRTSCTS;

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
        {
            printf ("error %d from tcsetattr", errno);
            return -1;
        }

        return 0;
}

void SetBlocking (int fd, int block)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);

        if (tcgetattr (fd, &tty) != 0)
        {
            printf ("error %d from tggetattr", errno);
            return;
        }

        tty.c_cc[VMIN]  = block ? 1 : 0;
        tty.c_cc[VTIME] = 5;

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
        {
            printf ("error %d from tcsetattr", errno);
        }
}


int main(int argc, char** argv)
{

    char *portname = "/dev/ttyS0";
    int bytesInBuffer = 0;
    int bytesWritten = 0;
    int modemControlBits = 0;

    int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);

    if (fd < 0)
    {
        printf ("error %d opening %s: %s", errno, portname, strerror (errno));
        return -1;
    }

    SetAttributes (fd, B57600, 0);
    SetBlocking (fd, 0);

    if (tcflush(fd, TCIOFLUSH) == -1)
    {
        printf("error %d flushing: %s\n", errno, strerror(errno));
        return -1;
    }

    while (true)
    {
        bytesWritten = write (fd, "NineteenCharacters!", 19);
        printf("TX: NineteenCharacters!\n");

        ioctl(fd, TIOCOUTQ, &bytesInBuffer);
        printf("Bytes Written: %d --- Bytes Left in Buffer: %d\n", bytesWritten, bytesInBuffer);


        ioctl(fd, TIOCMGET, &modemControlBits);
        printf("Serial Control Bits - LE:%02x - DTR:%02x - RTS:%02x - ST:%02x - SR:%02x- CTS:%02x - DCD:%02x - RNG:%02x - DSR:%02x\n",
            (TIOCM_LE & modemControlBits), (TIOCM_DTR & modemControlBits), (TIOCM_RTS & modemControlBits), (TIOCM_ST & modemControlBits),
            (TIOCM_SR & modemControlBits), (TIOCM_CTS & modemControlBits), (TIOCM_CAR & modemControlBits), (TIOCM_RNG & modemControlBits),
            (TIOCM_DSR & modemControlBits));

        usleep (250000);
    }

    return 0;
}

问题开始时的控制台输出

Bytes Written: 19 --- Bytes Left in Buffer: 19
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100
TX: NineteenCharacters!
Bytes Written: 19 --- Bytes Left in Buffer: 19
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100
TX: NineteenCharacters!
Bytes Written: 19 --- Bytes Left in Buffer: 19
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100
TX: NineteenCharacters!
Bytes Written: 19 --- Bytes Left in Buffer: 22
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100
TX: NineteenCharacters!
Bytes Written: 19 --- Bytes Left in Buffer: 41
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100
TX: NineteenCharacters!
Bytes Written: 19 --- Bytes Left in Buffer: 60
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100
TX: NineteenCharacters!
Bytes Written: 19 --- Bytes Left in Buffer: 79
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100
TX: NineteenCharacters!
Bytes Written: 19 --- Bytes Left in Buffer: 98
Serial Control Bits - LE:00 - DTR:02 - RTS:04 - ST:00 - SR:00- CTS:20 - DCD:40 - RNG:00 - DSR:100

标签: clinuxserial-portflow-control

解决方案


推荐阅读