Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C write() doesn't send data until close(fd) is called

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()?

like image 870
Kristina Avatar asked Jul 12 '10 12:07

Kristina


2 Answers

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.

like image 74
Louis Marascio Avatar answered Sep 25 '22 02:09

Louis Marascio


first of all, no idea why you first set all termios fields to 0, and then later, without any modification to that 0 preceding it, decide to set the usual rs232 flags on the cflag. (rather than doing that without the OR directly, where you now set it to 0, above).

what you might like -instead- of setting all those flags is just cfmakeraw() the termios fields.

also, sync(); without any parameters (NOT fsync! ;) seems to send all pending output to ALL filedescriptors, not just block devices. also tcp sockets and rs232..

and also open() has an option O_SYNC (O_SYNC and O_ASYNC have confusing names but have nothing to do with the serial line protocol being clocked or not, the one immediately commits write()'s and the other generates a signal for trapping when input becomes available (kinda like irq based rs232 on dos ;)

setting O_SYNC in the open() might already fix your issue.

also 'by reading the data on the other end'... there are these things called 'leds' and 'resistors' which you can just connect to TXD and SEE the data ;) also there are things called 'rs232 breakout box' or a scope that can make it -directly visible- ;) much easier that way than 'guessing' which side is not behaving properly.

WARNING: DID NOT TEST CODE. it compiles. but i have all my ttyUSB0 cables in another building. but i think your main issue is O_SYNC anyway. setting all termios crap to 0 is pretty much the same as cfmakeraw()... also why set CREAD if you are gonna open it write only? (why open it write only rather than readwrite anyway? - and also with write only you won't have to be scared of it becoming a controlling tty (O_NOCTTY ;) so in the case of write only, that's not exactly needed either...

just noticed the %i (same for %d btw) formatter also triggers a type mismatch warning the ssize_t return value of write() so casted that to (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);
};
like image 22
HRH Sven Olaf of CyberBunker Avatar answered Sep 24 '22 02:09

HRH Sven Olaf of CyberBunker