Reputation: 21
I am writing a small program to communicate with a AVR MCU, on PC side I used posix write() and read() to access the serial port, I connected the serial port's RX and TX pins to test if it can properly send and receive data, in theory everything sent out should end up exactly the same in the receive buffer, it is the case when the message being sent is short and sending frequency is low, read() returns the same message as sent out, but when the message gets longer and sent more frequently, read() returns the wrong data, the characters seem to be in the wrong order, my guess is read() or write() is not in block mode, so when old transfer hasn't finish yet, new transfer(write()?) arrived, interrupts the old transfer and changed the TX buffer.
I am a newbie in Linux programing, please anybody help me on this, it's killing me ... any help is greatly appreciated.
Edit: I noticed in the write() man page: 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.
I tried the fsync() function, still getting the same wrong result.
Here is the code:
#include <stdio.h>
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
int main(void) {
int fd;
// fd = open("/dev/tty.usbmodem1a21", O_RDWR | O_NOCTTY | O_NDELAY);
fd = open("/dev/tty.usbmodem1a21", O_RDWR | O_NOCTTY);
if (fd == -1) {
//Could not open the port.
perror("open_port: Unable to open port ");
}
else
fcntl(fd, F_SETFL, 0);
char s[] = "Hello, this is a test of the serial port access";
int cnt;
unsigned char in[100];
for(cnt=0; cnt<10; cnt++) {
int n = write(fd, s, sizeof(s));
if (n < 0)
fputs("write() failed!\n", stderr);
usleep(50000); // works fine with delay
read(fd, in, 100);
printf("%s\n", in);
}
return 0;
}
Eric
Upvotes: 2
Views: 3525
Reputation: 27542
(1) Always check return codes. (2) If you try to printf a string that hasn't been null terminated you are going to end up printing any junk that is in memory (or worse).
My guess is that your real problem is that read/write are NOT guaranteed to write the number of bytes you specify. The number that they actually read/write is in the return code. So as the fd buffer fills up you could be writing 1 byte and then trying to print a non-null string of that 1 byte and everything after it.
Try something like this and see if things change.
int cnt;
unsigned char in[100];
for(cnt=0; cnt<10; cnt++)
{
int n = write(fd, s, sizeof(s));
if (n < 0)
{
perror("write");
exit(EXIT_FAILURE);
}
n = read(fd, in, 100);
if (n < 0)
{
perror("read");
exit(EXIT_FAILURE);
}
in[n] = '\0';
printf("%s\n", in);
}
Upvotes: 2
Reputation: 44240
Start by using the return value from read() . Remember: read does not yield nul-terminated strings.
n=read(fd, in, 100);
printf("%*.*s\n", n,n, in);
Upvotes: 2