tags:

views:

166

answers:

7

So I have this test code to send "HELLO" over a USB serial port:

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");
}

The program executes fine and "HELLO" is sent but there is one problem. "HELLO" doesn't seem to be sent when the write() function is called, but rather when the file descriptor is closed. I added the sleep(5) line above to test out this theory and sure enough, "HELLO" is sent ~5 seconds after the program is executed. How can I get "HELLO" to be sent immediately after the write() command instead of on close()?

A: 

the buffer isn't flushed. fflush.

BobTurbo
fflush needs a FILE*, here OP has a file descriptor (and probably would like not to use stdio)
Alexandre C.
`fdopen` can be used; if this solves the OP problem and he has no reason why not to use file handler instead of file descriptor.
ShinTakezou
+4  A: 

From the man page of write():

A successful return from write() does not make any guarantee that data has been committed to disk. In fact, on some buggy implementations, it does not even guarantee that space has successfully been reserved for the data. The only way to be sure is to call fsync(2) after you are done writing all your data.

You need to call fsync() on your file descriptor to ensure the data is actually committed.

lrm
Adding "fsync(fd);" right after the write(fd) line returns -1: "Invalid argument".
Ryan
What does `errno` say?
lrm
Unrelated. The problem is that the terminal device is in line-buffered mode.
R..
Oh, it's probably `EROFS` or `EINVAL`...
lrm
errno is set to EINVAL
Ryan
Have you tried `tcflush()` ?
lrm
tcflush(fd, TCOFLUSH); returns 0 but doesn't help
Ryan
How about `tcdrain()`?
lrm
Also, try transmitting a new line.
lrm
tcdrain(fd); returns 0 but doesn't help
Ryan
I've tried sending \r\n, \r, and \n and none of them help
Ryan
A: 

Please see this question. BAsically you need to flush the file in order for IO to take place when you want to.

Alexandre C.
A: 

Try doing a

fflush( NULL );

after the write(). Maybe there is some internal buffer which is not flushed.

Frerich Raabe
could not solve the problem for 2 reason: 1) does fflush care about files opened with open? maybe a fdopen is required; 2) notes from the man page: fflush() only flushes the user space buffers provided by the C library. To ensure that the data is physically stored on disk the kernel buffers must be flushed too, for example, with sync(2) or fsync(2)
ShinTakezou
A: 

Output ports are often buffered, so that there's a greater or lesser gap between you writing to an output stream, and the content actually being sent to the disk, line, or whatever. This is generally for efficiency.

See fflush(3) to force the buffer to be committed to the output.

You might also be able to open the output descriptor in a way which makes it non-buffered, but using fflush to say 'that's it, I'm done', is probably better.

Norman Gray
Ooops, yes, fflush(3) is for `FILE*`, and as others have pointed out, fsync(2) is probably what you want if you do need to use FDs.
Norman Gray
In fact, look at fcntl(2) on your platform. On some platforms, that will allow you to disable buffering for output, but that's not portable. If you want to give up on portability altogether, then the ioctls for your device will probably help with this, but that's getting desperate.
Norman Gray
fd -> fdopen -> fh; fh -> fileno -> fd... the problem is not having "FILE*" or fd (if compliance is for POSIX and not strictly C89/C99)
ShinTakezou
A: 

Change this line:

tty.c_cc[VMIN] = 0;

to this:

tty.c_cc[VMIN] = 1;
R..
Just tried that and it didn't help
Ryan
+3  A: 

The device is a tty device, so fsync isn't going to help, maybe not fflush either.

By default the device is working in canonical mode which means that data is packaged up into units of lines. You'll probably find that adding a cr/lf pair to your data will cause it to be sent.

You need to make sure canonical mode is off. Also, R's answer will be of use.

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

JeremyP