使用VTIME和read()的POSIX行为

时间:2015-01-25 13:16:51

标签: c++ macos unix serial-port posix

花了几个小时在线研究这个问题,我仍然不清楚VTIMEread(int fildes, void *buf, size_t nbyte);如何一起工作。在我看来,只要read()得到一个字节,它就会忽略VTIME。只有在没有读取字节时才会服从VTIME

如果我正确读到这一点,here的解释似乎证实了这一点:

  

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

是否有任何方法可以在read()满足在最后一个字节后达到nbyte时返回VTIME?< / p>

VTIMEread()以这种方式行事似乎有点奇怪。为什么在超时之前不会尝试阅读nbytes

例如,在下面的代码中,read()在返回之前不会等待10秒。如果没有发生写入,那么它就会发生。

int main (void) {

    int usbSerial;
    struct termios options;
    std::string port = "/dev/tty.usb001";


    usbSerial = open(port.c_str(), O_RDWR| O_NOCTTY | O_NONBLOCK);

    // Check if unopen
    if(usbSerial == -1) {
        printf("Error: Unable to open %s\n", port.c_str());
    }
    else { // Set to blocking
        fcntl(usbSerial, F_SETFL, 0);
        printf("Connection to serial device established.\n");
    }

    // Set port settings
    tcgetattr(usbSerial, &options); // read old port settings
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);

    options.c_cflag &= ~PARENB;    // set no parity, 1 stop bit, data bits
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    options.c_cflag     &=  ~CRTSCTS;           // no flow control.
    options.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines

    options.c_cc[VMIN]   =  0;
    options.c_cc[VTIME]  =  100;


    // Flush port and then apply new options
    tcflush(usbSerial, TCIOFLUSH);
    if (tcsetattr(usbSerial, TCSANOW, &options) != 0) {    // TCSANOW == make option change immediately
        printf("Error %i from tcsetattr.\n", errno);
    }

    // write
    unsigned char message[] = {0x03, 0x05, 0x01, 0x01, 0x04};
    ssize_t n = write(usbSerial, &message, sizeof(message)/sizeof(message[0]));


    unsigned char buffer[64] = {};
    tcdrain(usbSerial);


    ssize_t readChars = read(usbSerial, &buffer, 10);

    printf("Done.\n");

}

1 个答案:

答案 0 :(得分:0)

当你说:

时,我相信你是对的
  

在我看来,只要read()得到一个字节,它就会忽略VTIME。

read()的返回值:

  

成功时,返回读取的字节数(零表示文件结束),文件位置按此编号前进。如果此数字小于请求的字节数,则不是错误;这可能发生,例如因为现在实际可用的字节数较少(可能是因为我们接近文件结尾,或者因为我们正在读取管道,或来自终端),或者因为read()被信号打断了。 link

您可能需要循环,可能类似(未经测试):

int totalNeeded = 10;
int remaining   = 10;
while (remaining > 0){
    ssize_t readChars = read(usbSerial, &buffer[totalNeeded - remaining], remaining);
    if (readChars > 0){
        remaining -= readChars;
    }
    else{
        // handle error or EOF
    }
}

不确定您需要如何处理部分读取,尤其是因为O_NONBLOCK,但我认为VTIME与read()之间的行为互动受read()控制。