0

I have an inconsistency problem while I read in my serial port using Linux and C.

The code that I use to configure the serial port is this:

serial = open("/dev/ttymxc1", O_RDWR | O_NOCTTY | O_SYNC); //Open in non blocking read/write mode if (serial == -1) { //ERROR - CAN'T OPEN SERIAL PORT printf("Error - Unable to open UART. Ensure it is not in use by another application\n"); } struct termios tty; memset (&tty, 0, sizeof tty); if (tcgetattr (serial, &tty) != 0) { printf("error from tcgetattr"); return -1; } cfsetospeed (&tty, B115200); tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars // disable IGNBRK for mismatched speed tests; otherwise receive break // as \000 chars //tty.c_iflag &= ~IGNBRK; // disable break processing tty.c_lflag = 0; // no signaling chars, no echo, // no canonical processing tty.c_oflag = 0; // no remapping, no delays tty.c_cc[VMIN] = 0; // read doesn't block tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, // enable reading tty.c_cflag &= ~(PARENB | PARODD); // shut off parity tty.c_cflag |= 0; tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CRTSCTS; if (tcsetattr (serial, TCSANOW, &tty) != 0) { printf("error from tcsetattr"); return -1; } 

Then I poll the UART (from the same thread which has configured the serial port) with the following code:

while(1) { if (serial != -1) { //memset(rx, 0, sizeof(rx)); int rx_length = read(serial, &rx, MAX_TXRX_BUF); //Filestream, buffer to store in, number of bytes to read (max) if(rx_length > 0){ //Bytes received //rx[rx_length] = '\0'; printf("1) %i bytes read : %s\n", rx_length, rx); //forward_data(rx, rx_length); printf("2) %i bytes read : %s\n", rx_length, rx); //tcflush(serial, TCIOFLUSH); } // else: NO DATA } else{ fprintf(stderr, "TEST: %s SERIAL FAIL\n", __func__); releaseUart(); } } 

The problem is that this print:

printf("1) %i bytes read : %s\n", rx_length, rx); 

always WORKS and print the correct data read from serial. While the second print:

printf("2) %i bytes read : %s\n", rx_length, rx); 

which is immediately below the first one, sometimes works and other items it just prints an unknown character.

Below I show you the ouput but in the case in which it works and in the case in which it does not work:

Correct:

1) 2 bytes read : gv 2) 2 bytes read gv 

Wrong:

1) 2 bytes read : gv 2) 2 bytes read: � 

Why even if the two prints are one below the other sometimes I get these kind of inconsistencies in printing the SAME buffer?

Thanks in advance very much for your help.

Best regards, Marco

6
  • 1
    After applying zwol's fixes, you may be trying to output binary that is outside the ASCII range. It may try to interpret it as utf-8 and get confused. That diamond question mark symbol is an indicator of that. Try: void prt(unsigned char *buf,int len) { unsigned int chr; for (; len > 0; --len, ++buf) { chr = *buf; if ((chr >= 0x20) && (chr <= 0x7E)) printf("%c",(char) chr); else printf("{?%2.2X?}",chr); } } Commented Jan 29, 2019 at 20:35
  • What do you have rx declared as? Is it a char or word or long? Commented Jan 29, 2019 at 22:14
  • 1
    "Below I show you the ouput ..." -- Your output looks bogus. In the "correct" output, why does the second line have no colon? In the "wrong" output, where did the "SERIAL READ:" come from instead of "bytes read :" that's in the printf()? Commented Jan 30, 2019 at 8:12
  • Hello @sawdust I simply made a mistake copying it, I have corrected the question with the same output. Commented Jan 30, 2019 at 10:11
  • Hello @Baddack it is declared as char rx[MAX_TXRX_BUF]; Commented Jan 30, 2019 at 11:52

1 Answer 1

1

I cannot explain why the output changes between the first printf and the second. However, read does not NUL-terminate its buffer, which means, after you do

int rx_length = read(serial, &rx, MAX_TXRX_BUF); 

you do not have a valid C string in rx. You need to do something like this instead:

char rx[MAX_TXRX_BUF + 1]; // extra space for terminator ssize_t rx_length = read(serial, rx, MAX_TXRX_BUF); if (rx_length >= 0) { rx[rx_length] = '\0'; // use rx here // if rx_length == 0, handle EOF } else { // read error } 

Even though I don't know why the output changes, I predict that if you put your two printf statements where I have // use rx here, they will always print the same thing.

N.B. taking the address of an entire array, as you did with &rx, is almost always a mistake. In most cases what you actually want, in order to refer to an array in C, is the address of the first element, which is what you get with just rx. (For reasons too tedious and tangential to get into here, read doesn't care which one of the two you supply it, but in other cases it can lead to subtle bugs. Therefore, best practice in C is to use the address of the first element even in cases where it doesn't matter; reserve &rx for the rare cases where you do specifically need the address of the entire array.)

Sign up to request clarification or add additional context in comments.

3 Comments

Hello and thank you for your reply and suggestions. I have added your changes, but even if I put the two printf inside where you told me sometimes the ouput of the second is corrupted as I shown above. I do not know why, it is very strange. rx is definied as unsigned char rx[MAX_TXRX_BUF];
(1) Did you change rx to unsigned char rx[MAX_TXRX_BUF + 1] also? (2) Run your program under valgrind, does it report any errors? If so, fix them; did that make the problem go away?
Hello @zwol and thank you for your hints. I have also changed rx to unsigned char rx[MAX_TXRX_BUF + 1] but the same problem happens. I will check with valgrind to see if it reports any errors. At the moment I have not solved it. I am also following some suggestions from other users for example by printing the wrong character when it appears. I found by printing the wrong character that it is a NULL. If I find other helpful informations I will post them here. Thank you for your time.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.