У меня проблема с вызовами read()
, не блокирующими .
Это на самом деле заключение, а не наблюдение.
Предположительно, ваша программа сообщает об отсутствии чтения байтов, что технически не является ошибкой.
... из того, что я исследовал, это должно быть чтение в режиме блокировки. (fcntl(fd, F_SETFL, 0);
)
Правильно, дескриптор файла сконфигурирован для режима блокировки.
Я думаю, что я где-то неправильно настроил опцию.
Да, ваша конфигурация termios неполная. (Он использует правильные побитовые операции, но, к сожалению, он неполон и содержит ошибки, см. ДОБАВЛЕНИЕ.)
При настройке на неканонический режим необходимо также указать параметры VMIN и VTIME .
Если не указано (как в вашем коде), вероятно, будут действовать значения по умолчанию VMIN = 0 и VTIME = 0, что эквивалентно неблокирующему чтению.
Обратите внимание, что длина байта в системном вызове read () оказывает минимальное влияние на поведение завершения (кроме ограничения количества возвращаемых байтов).
Со страницы man для читайте (2) :
read () пытается прочитать до count
байтов из файлового дескриптора fd
в буфер, начиная с buf
.
Следовательно, параметр count
фактически является максимальным.
Фактическое число считанных байтов может быть от нуля до count
в зависимости от значений, настроенных для VMIN и VTIME (и фактических доступных данных).
См. Блокирование Linux против последовательных неблокирующих операций. Прочитайте для более подробной информации.
Чтобы прочитать как минимум два байта на системный вызов (без ограничения по времени), включите в конфигурацию termios следующее:
options.c_cc[VMIN] = 2;
options.c_cc[VTIME] = 0;
Вышеуказанные два оператора, вставленные в вашу программу перед системным вызовом tcsetattr () , будут вызывать постоянную блокировку вашей программы до тех пор, пока в каждом операторе read(fd, buffer, 2)
не будет возвращено ровно два байта.
Оператор read(fd, buffer, 4)
также будет блокировать навсегда и возвращать 2, 3 или 4 байта данных (в зависимости от времени программы в отношении приема и буферизации данных).
ADDENDUM
Оказывается, в вашей инициализации termios есть несколько ошибок.
После публикации ваша программа не передает и не принимает какие-либо данные правильно, и вы не смогли обнаружить эти ошибки или не упомянули их.
Следующий оператор в вашей программе стирает все предыдущие операции c_cflag
и непреднамеренно перенастраивает скорость передачи в B0 и размер символа в CS5 :
options.c_cflag &= CS8;
Правильный синтаксис:
options.c_cflag |= CS8;
Заявление
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
должно быть расширено за счет большего количества атрибутов для соответствия cfmakeraw () :
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
Следующая инструкция в вашей программе отключает каждый атрибут в c_iflag
, за исключением IGNPAR , и оставляет атрибут IGNPAR в неизвестном / неоднозначном состоянии:
// disable parity check
options.c_iflag &= IGNPAR;
Чтобы соответствовать cfmakeraw () , его следует изменить на:
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL);
Со всеми упомянутыми исправлениями я могу заставить вашу программу работать как положено.