Serial port eating bytes

Hello,

I got FT232 USB<->RS485 module connected to machine running on FreeBSD 9.1 release.
while trying to fix communication problem, I have found that some of data was not read correctly, for example:

Data Sent:
0x16 0x0f 0x00 0x16 0x16 0x02

Data read from the port:
0x0f 0x00 0x16 0x02

so double 0x16 read as one, single 0x16 does not read at all.... This code works well on Ubuntu.
here is the how I'm configuring the port (speed configuration is not shown)
Code:
// opening port that way:
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);

int uart_configure(int fd, int stopbits,int parity)
{
    struct termios options;
    if(stopbits<1 || stopbits>2) return -1;
	tcgetattr(fd, &options);

    options.c_cflag     |= (CLOCAL | CREAD);
    options.c_cflag     &= ~CRTSCTS; // Disable flow HW control
    options.c_cflag     &= ~PARENB; // Disable Parity

    options.c_iflag     &=~(IXON|IXOFF|IXANY|IGNBRK); // Disable XON/XOFF

    options.c_lflag     &= ~(ICANON | ECHO | ECHOE |ISIG);
    options.c_oflag     &= ~OPOST;
    options.c_cc[VMIN]  = 0;
    options.c_cc[VTIME] = 0;


	// stopbits
	options.c_cflag &= ~CSTOPB; // 1 stop bit
	if(stopbits==2)
			options.c_cflag |= CSTOPB; // 2 stop bits

	options.c_cflag &= ~CSIZE; /* Mask the character size bits */
	options.c_cflag |= CS8;    /* Select 8 data bits */

	options.c_cflag &= ~PARENB;
	switch(parity)
	{
	case 0: // none
			// leave empty
			break;
	case 1: // odd parity
			options.c_cflag |= PARENB;
			options.c_cflag |= PARODD;

			break;
	case 2:
			options.c_cflag |= PARENB;
			options.c_cflag &= ~PARODD;
			break;
	default:
			return -1;
	}

	tcsetattr(fd, TCSANOW, &options);
	return 0;
}

Thanks in advance
 
Can you duplicate the problem with a "real" (i.e. non-USB) serial port? That might isolate the problem to a USB issue or a TTY issue.

There are known issues with tcdrain(3), so if your code depends on it you may have problems.
 
I just tested it over build-in RS232 port, same issue, one 0x16 disheartening , double passes as single 0x16 ...
also tested with loopback terminal (RX pin connected directly to TX pin):
request length : 8
0x16 0x03 0x16 0x00 0x00 0x0b 0x03 0x62
response length : 6
0x03 0x00 0x00 0x0b 0x03 0x62

It is also possible there is an issue in my code, in the way how I read data, so here is the code:
Code:
bzero(rxbuff,M_BUFF_SIZE);

// Read
fd_set read_fds;
FD_ZERO(&read_fds);

p = rxbuff;
timeout = timeout_start / M_TIMEOUT_QUANT; // first timeout may vary (up to 1 sec), M_TIMEOUT_QUANT = 10 
while(timeout)
{
		tv_timeout.tv_sec = 0;
		tv_timeout.tv_usec = M_TIMEOUT_QUANT*1000; // read timeout quant
		FD_SET(_m_serial_fd, &read_fds);
		r = select(_m_serial_fd+1,&read_fds,NULL,NULL,&tv_timeout); 
		switch(r)
		{
		case -1: // Select error 
			perror("Select");
			return -1;
			break;
		case 0: // timeout
			timeout--;
			break;
		default: // normal read 
			timeout = timeout_read / M_TIMEOUT_QUANT; // transtaction finish timeout (~100ms)
			l = p-rxbuff;
			if(l<M_BUFF_SIZE){
				r = read(_m_serial_fd,p,M_BUFF_SIZE - l);
				if(r<0){
						perror("Read");
						return -1;
				}
				p+=r;
			}else{ // too long response
					result = -2; // response too long
					read(_m_serial_fd,txbuff,M_BUFF_SIZE ); // read data anyway, into dummy buffer to clear read buffer
			}
			break;
		}
}
// process data
length = p-rxbuff;
 
First thing that comes to my mind is that your loop terminates pre-maturely because the division of timeout_read / M_TIMEOUT_QUANT truncates in a way you're not expecting it to do. Is timeout_read an int or a float/double?
 
everything is integer values. There is no issue with timeouts, I have tested it with 100 of seconds. It is very strange that 0x16 works like some kind of escape symbol ...

PS: 0x16 | SYN (synchronous idle) < from ASCII table...

BTW Thanks for quick reply!
 
Um, I think you need to be in RAW mode to use SYN. That is 0x16, or ^V which the TTY driver interprets as a literal insert. Try it on the command line and you will see it does just what you have described.
 
Solution found:

options.c_lflag = 0; // just clear all the flags !

in addition, the problem was caused by IEXTEN flag in c_lflags
Thanks !
 
Back
Top