POSIX-поведение с VTIME и read ()

0

После нескольких часов, проведенных в этом онлайн-режиме, я все еще не совсем 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");

}
  • 0
    Не связано, но будьте осторожны при использовании адресного операнда с массивами. Если массив на самом деле не является массивом (и помните, что массивы распадаются на указатели), то, скорее всего, все будет работать не так, как ожидалось. А поскольку массивы распадаются на указатели на их первый элемент, вам фактически не нужен оператор адресации при передаче массивов функциям, ожидающим указатели.
  • 0
    @JoachimPileborg Ах, совершенно верно! Спасибо за это.
Показать ещё 2 комментария
Теги:
macos
serial-port
posix

1 ответ

0
Лучший ответ

Я считаю, что вы правы, когда говорите:

Мне кажется, что как только 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().

  • 0
    Благодарю. Я ожидал, что он будет вести себя аналогично другим операциям тайм-аута, как в pyserial или MATLAB.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню