无法从串行设备读取和拔出连接器
问题描述:
我有一个Linux应用程序应该从串行设备/dev/ttyS0
读取。该系列器件通过以下方式打开:无法从串行设备读取和拔出连接器
// Open the serial port
if((serial_device = open("/dev/ttyS0", O_RDWR | O_NOCTTY)) < 0){
fprintf(stderr, "ERROR: Open\n");
exit(EXIT_FAILURE);
}
// Get serial device attributes
if(tcgetattr(serial_device,&options)){
fprintf(stderr, "ERROR: Terminal Get Attributes\n");
exit(EXIT_FAILURE);
}
cfsetspeed(&options,speed); // Set I/O baud rates
cfmakeraw(&options); // Set options to transceive raw data
options.c_cflag |= (CLOCAL | CREAD); // Enable the receiver and set local mode
options.c_cflag &= ~CSTOPB; // 1 stop bit
options.c_cflag &= ~CRTSCTS; // Disable hardware flow control
options.c_cc[VMIN] = 1; // Minimum number of characters to read
options.c_cc[VTIME] = 10; // One second timeout
// Set the new serial device attributes
if(tcsetattr(serial_device, TCSANOW, &options)){
fprintf(stderr, "ERROR: Terminal Set Attributes\n");
exit(EXIT_FAILURE);
}
我然后使用select
功能,试图从串行设备读取:
// Flush I/O Bffer
if(tcflush(serial_device,TCIOFLUSH)){
fprintf(stderr, "ERROR: I/O Flush\n");
exit(EXIT_FAILURE);
}
// Write message to board
if(write(serial_device,msg, strlen(msg)) != (int)strlen(msg)){
fprintf(stderr, "ERROR: Write\n");
exit(EXIT_FAILURE);
}
switch(select(serial_device+1, &set, NULL, NULL, &timeout)){
// Error
case -1:
fprintf(stderr, "ERROR: Select\n");
exit(EXIT_FAILURE);
// Timeout
case 0:
success = false;
break;
// Input ready
default:
// Try to read a character
switch(read(serial_device, &c, 1)){
// Error (miss)
case -1:
success = false;
break;
// Got a character
default:
msg[i++] = c;
break;
}
break;
}
// Set 200ms timeout
this->timeout.tv_sec = 0;
this->timeout.tv_usec = 200000;
}
我试图通过确定重新打开端口读不成功:
if(!success)
close(serial_device);
openPort(); // Same as above
}
然而,实际拔下串行连接器的行为会导致应用程序是无法读取任何furt她和选择什么都不会做,但超时。在应用程序运行时重新插入连接器将无法解决问题,并且select将继续检测到任何内容。
再次成功从串口读取数据的唯一方法是重新启动应用程序。我想知道为什么这样,以及如何从运行时拔出的串口连接器中恢复。
答
使用select()
只有一个文件描述符是不寻常的。它也增加了复杂程度。
由于串行端口被配置为非规范输入,通过适当选择VMIN
and VTIME
,您可以使用简单的代码一次完成字符的读取。例如。尝试VMIN = 1
和VTIME = 10*timeout.tv_sec
但是当你想通了,如果你愿意处理(或希望)超时,而不是等待至少一个字符到达,然后VMIN = 0
会效仿你的原代码与select()
。
VMIN = 0和VTIME> 0
这是一个纯定时读数。如果数据在输入队列中可用,则将其传输到主叫方的缓冲区,最大数量为nbytes,并立即返回给主叫方。否则,驱动程序阻塞直到数据到达,或者VTIME十分之一从通话开始到期。如果定时器在没有数据的情况下到期,则返回零。单个字节足以满足此读取调用,但如果输入队列中有更多可用字段,则它将返回给调用者。请注意,这是一个整体计时器,而不是一个字符。
但是(如OP),我百思不得其解,为什么重新连接端口连接器应该中断任何读取或选择监控,从来没有遇到过这样的问题。
很难知道问题是您的主机停止接收还是电路板停止传输。带LED显示活动的RS-232诊断软件狗可以在这种情况下提供帮助。我注意到你没有检查EOF('read'返回0)。也许这可能是一个问题? – Celada
“'success = failure'”是相当幽默的一行代码! – Celada
这是一个USB RS-232加密狗? – dbasnett