无法从串行设备读取和拔出连接器

问题描述:

我有一个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将继续检测到任何内容。

再次成功从串口读取数据的唯一方法是重新启动应用程序。我想知道为什么这样,以及如何从运行时拔出的串口连接器中恢复。

+2

很难知道问题是您的主机停止接收还是电路板停止传输。带LED显示活动的RS-232诊断软件狗可以在这种情况下提供帮助。我注意到你没有检查EOF('read'返回0)。也许这可能是一个问题? – Celada

+2

“'success = failure'”是相当幽默的一行代码! – Celada

+2

这是一个USB RS-232加密狗? – dbasnett

使用select()只有一个文件描述符是不寻常的。它也增加了复杂程度。
由于串行端口被配置为非规范输入,通过适当选择VMIN and VTIME,您可以使用简单的代码一次完成字符的读取。例如。尝试VMIN = 1VTIME = 10*timeout.tv_sec

但是当你想通了,如果你愿意处理(或希望)超时,而不是等待至少一个字符到达,然后VMIN = 0会效仿你的原代码与select()

VMIN = 0和VTIME> 0
这是一个纯定时读数。如果数据在输入队列中可用,则将其传输到主叫方的缓冲区,最大数量为nbytes,并立即返回给主叫方。否则,驱动程序阻塞直到数据到达,或者VTIME十分之一从通话开始到期。如果定时器在没有数据的情况下到期,则返回零。单个字节足以满足此读取调用,但如果输入队列中有更多可用字段,则它将返回给调用者。请注意,这是一个整体计时器,而不是一个字符。

但是(如OP),我百思不得其解,为什么重新连接端口连接器应该中断任何读取或选择监控,从来没有遇到过这样的问题。