После нескольких часов, проведенных в этом онлайн-режиме, я все еще не совсем VTIME
как VTIME
и read(int fildes, void *buf, size_t nbyte);
работать вместе. Мне кажется, что как только read()
получает один байт, он игнорирует VTIME
. VTIME
выполняется только при отсутствии чтения байтов.
Если я читаю это право, объяснение здесь, похоже, подтверждает это:
VMIN = 0 и VTIME> 0 Это чистое считывание по времени. Если данные доступны во входной очереди, они переносятся в буфер вызывающего абонента максимум до nbytes и немедленно возвращаются вызывающему. В противном случае драйвер блокируется до тех пор, пока данные не поступят, или когда десятые десятки VTIME не истекут с начала вызова. Если таймер истекает без данных, возвращается ноль. Для удовлетворения этого запроса на чтение достаточно одного байта, но если во входной очереди доступно больше, оно возвращается вызывающему. Обратите внимание, что это общий таймер, а не межсимвольный.
Есть ли способ сделать read()
возвращаться только тогда, когда nbyte
будет удовлетворен или когда VTIME
достигнут после последнего байта?
Кажется немного странным, что VTIME
и read()
будут действовать таким образом. Почему бы не попробовать читать nbytes
до 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");
}
Я считаю, что вы правы, когда говорите:
Мне кажется, что как только read() получает один байт, он игнорирует VTIME.
Возвращаемое значение для read()
:
При успехе возвращается количество прочитанных байтов (нуль указывает конец файла), а позиция файла продвигается по этому номеру. Это не ошибка, если это число меньше количества запрошенных байтов; это может произойти, например, из-за того, что на данный момент доступно меньше байтов (возможно, потому, что мы были близки к концу файла или потому, что мы читаем из канала или с терминала), или потому, что read() был прерван сигнал. ссылка
Вам может потребоваться цикл, возможно, что-то вроде (untested):
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()
.