c - 当 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
解决方案
推荐阅读
- ruby-on-rails - OneLogin SAML 身份验证后的 Web 重定向
- vue.js - _vm.arr[0] 未定义 Vue.js, Nuxt
- java - 考虑到夏令时,如何获得实时时区偏移?
- wordpress - 如何从 WordPress 帖子图像生成 PDF?
- java - 从 getter setter 传递值
- excel - 如何解决自定义排序运行时错误 1004
- reactjs - /src/components/Form.js: 'import' 和 'export' 可能只出现在顶层 (59:0)
- bash - 如何在linux终端bash`apt install`命令中添加每行项目?
- blockchain - 尝试用松露编译合同时出现 Pragma solidity 错误
- rest - Keycloak JWT 中显示的嵌套组