C write () не отправляет данные до вызова close (fd) - PullRequest
7 голосов
/ 12 июля 2010

Итак, у меня есть этот тестовый код для отправки «HELLO» через последовательный порт USB:

int fd;
struct termios tty;

if((fd = open("/dev/ttyUSB0", O_WRONLY|O_NONBLOCK|O_NOCTTY)) == -1){
err(1, "Cannot open write on /dev/ttyUSB0");
}

tcgetattr(fd, &tty);
tty.c_iflag = 0;
tty.c_oflag = 0;
tty.c_lflag = 0;
tty.c_cflag = 0;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 0;
cfsetospeed(&tty, B19200);
cfsetispeed(&tty, B19200);
tty.c_cflag |= CREAD|CRTSCTS|HUPCL|CS8;
tcsetattr(fd, TCSANOW, &tty);

printf("Write: %i\n", write(fd, "HELLO", 5));

sleep(5);

if(close(fd) != 0){
warn("Could not close write fd");
}

Программа выполняется нормально, и «HELLO» отправляется, но есть одна проблема.«Привет», похоже, не отправляется, когда вызывается функция write (), а когда закрывается дескриптор файла.Я добавил строку сна (5) выше, чтобы проверить эту теорию и, конечно же, «HELLO» отправляется через 5 секунд после выполнения программы.Как я могу получить "HELLO" для отправки сразу после команды write () вместо close ()?

Ответы [ 8 ]

8 голосов
/ 12 июля 2010

Устройство является устройством tty, поэтому fsync не поможет, возможно, и не fflush.

По умолчанию устройство работает в каноническом режиме, что означает, что данные упакованы в единицы строк.Вы, вероятно, обнаружите, что добавление пары cr / lf к вашим данным приведет к их отправке.

Необходимо убедиться, что канонический режим отключен.Также будет полезен ответ Р.

http://en.wikibooks.org/wiki/Serial_Programming/termios

5 голосов
/ 12 июля 2010

Со справочной страницы write():

Успешный возврат из write () не дает никаких гарантий того, что данные были записаны на диск. Фактически, в некоторых ошибочных реализациях это даже не гарантирует, что пространство было успешно зарезервировано для данных. Единственный способ убедиться в этом - вызвать fsync (2) после того, как вы закончите записывать все свои данные.

Вам необходимо вызвать fsync() в вашем файловом дескрипторе, чтобы убедиться, что данные действительно зафиксированы.

3 голосов
/ 03 февраля 2016

Прежде всего, не знаю, почему вы сначала устанавливаете все поля termios в 0, а затем, без каких-либо изменений в предшествующий ему 0, решаете установить обычные флаги rs232 для cflag. (вместо того, чтобы делать это без ИЛИ напрямую, где вы теперь установите его на 0 выше).

Что бы вы хотели установить вместо всех этих флагов - просто cfmakeraw () поля termios.

также sync (); без каких-либо параметров (НЕ fsync!;), похоже, отправляет весь ожидающий вывод на ВСЕ файловые дескрипторы, а не только на блочные устройства. также сокеты tcp и rs232 ..

, а также open () имеет опцию O_SYNC (O_SYNC и O_ASYNC имеют сбивающие с толку имена, но не имеют ничего общего с тактируемым протоколом последовательной линии или нет, тот немедленно фиксирует write (), а другой генерирует сигнал для перехват, когда ввод становится доступным (вроде как rs232 на основе IRQ на DOS;)

установка O_SYNC в open () может уже решить вашу проблему.

также «читая данные на другом конце» ... есть такие вещи, как «светодиоды» и «резисторы», которые вы можете просто подключить к TXD и увидеть данные;) также есть вещи, которые называются «rs232 breakout» box 'или область видимости, которая может сделать его - непосредственно видимым -;) гораздо проще, чем "угадывать", какая сторона ведет себя неправильно.

ВНИМАНИЕ: НЕ ИСПЫТАЛ КОД. это компилируется. но у меня все мои кабели ttyUSB0 в другом здании. но я думаю, что ваша главная проблема в любом случае O_SYNC. установка для всех termios crap значения 0 почти такая же, как для cfmakeraw () ... и зачем устанавливать CREAD, если вы собираетесь открывать его только для записи? (зачем открывать его только для записи, а не для чтения в любом случае? - а также только с записью, вам не нужно бояться, что он станет управляющим tty (O_NOCTTY;), так что в случае только записи это тоже точно не нужно .. .

только что заметил, что форматер% i (то же самое для% d btw) также вызывает несоответствие типов, предупреждающее возвращаемое значение ssize_t для write (), приведенное к (int)

#include<termios.h>
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>

void main(){
int fd;
struct termios tty;
fd=-1;
while(fd<0){fd=open("/dev/ttyUSB0",O_WRONLY|O_NONBLOCK|O_NOCTTY|O_SYNC);sleep(1);};
cfmakeraw(&tty);
tty.c_cflag=CREAD|CRTSCTS|HUPCL|CS8;
cfsetospeed(&tty,B19200);
cfsetispeed(&tty,B19200);
tcsetattr(fd,TCSANOW,&tty);
printf("Write: %i\n",(int)write(fd,"HELLO",5));
sync();//if all else fails, also try without, O_SYNC should already fix that.
close(fd);
};
2 голосов
/ 12 июля 2010

Выходные порты часто буферизуются, так что существует большой или меньший разрыв между записью в выходной поток и содержимым, фактически отправляемым на диск, строку или что-либо еще. Это вообще для эффективности.

См. Fflush (3) для принудительной фиксации буфера на выходе.

Вы также можете открыть выходной дескриптор таким образом, что он не будет буферизироваться, но лучше использовать fflush, чтобы сказать «все, я сделал»,

0 голосов
/ 12 июля 2010

Изменить эту строку:

tty.c_cc[VMIN] = 0;

к этому:

tty.c_cc[VMIN] = 1;
0 голосов
/ 12 июля 2010

Попробуйте сделать

fflush( NULL );

после write().Может быть, есть какой-то внутренний буфер, который не очищается.

0 голосов
/ 12 июля 2010

Пожалуйста, посмотрите этот вопрос . В общем, вам нужно сбросить файл, чтобы IO состоялся, когда вы хотите.

0 голосов
/ 12 июля 2010

буфер не очищен.fflush.

...