【发布时间】:2015-03-24 01:57:31
【问题描述】:
经过数小时的在线研究,我仍然不太清楚VTIME 和read(int fildes, void *buf, size_t nbyte); 如何协同工作。在我看来,只要read() 得到一个字节,它就会忽略VTIME。 VTIME 仅在未读取任何字节时才会遵守。
如果我没看错的话,here 的解释似乎证实了这一点:
VMIN = 0 且 VTIME > 0 这是一个纯定时阅读。如果输入队列中有可用数据,则将其传输到调用者的缓冲区,最多 nbytes,并立即返回给调用者。否则,驱动程序会阻塞,直到数据到达,或者当 VTIME 从调用开始到十分之一到期时。如果计时器到期而没有数据,则返回零。 一个字节就足以满足这个读取调用,但如果输入队列中有更多可用,则将其返回给调用者。请注意,这是一个整体计时器,而不是字符间计时器。
有什么方法可以让read() 仅在满足nbyte 时返回或在最后一个字节后达到VTIME 时返回?
VTIME 和 read() 会以这种方式行事似乎有点奇怪。为什么不尝试在超时前读取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");
}
【问题讨论】:
-
不相关,但在将操作数的地址与数组一起使用时要小心。如果数组实际上不是数组(并记住数组衰减为指针),那么事情很可能不会按预期工作。而且由于数组衰减到指向它们第一个元素的指针,因此在将数组传递给期望指针的函数时,您实际上不需要地址运算符。
-
@JoachimPileborg 啊,完全正确!谢谢你。
-
您描述的程序行为与您发布的代码不一致。设置 VMIN 和 VTIM 仅适用于非规范模式,但您的代码并未明确配置非规范或原始模式的串行端口。端口可能已经处于原始模式,但是由于部分/不完整的初始化,您将面临无法预测的程序行为的风险。更有可能您的 read() 是一个非阻塞规范操作,既不使用 VMIN 也不使用 VTIME。
-
我认为它默认为原始模式,因为 VMIN 工作正常,没有写入字符时 VTIME 也是,但我添加了
options.c_lflag &= ~(ICANON | ECHO | ISIG);只是为了确定。
标签: c++ macos unix serial-port posix