Error on serial port (ser8250)

I have a problem when using serial ports. I use the 8250 driver provided by QNX, on an x86 system.

I transfer data at high frequency (read / write).
To read the data I use the function: ssize_t read (int fd, void * buf, size_t nbyte);

Randomly, this function returns a size read inconsistent data (ssize_t).

The return value of the function is greater than the “nbyte” parameter. This is normally impossible, qnx indication in the documentation.

What have any idea?

Thank you

I’ll assume that you aren’t mistaking a -1 return value for ssize_t for a large number if you are printing it out as an unsigned value.

Can we see the exact lines of code you are using to read and can you give us an idea of what values you pass for nbyte and what return value you are seeing.

Also curious to know if your reads are multi-threaded in any way.

Tim

My code read function
int CSerialCom::Read( char * pcData, int iSize )
{
// Init
const int NO_DATA_RCV = 0;
errno = 0;
int iNbBytes = NO_DATA_RCV;

// Test the state of the connection
if( GetCnxState() != OPENED )
{		
	return iNbBytes;
}
			
// Read
iNbBytes = read( m_iFileDesc, pcData, iSize );			
if( iNbBytes == QNXINTERNALERROR )
{				
	if( errno == EAGAIN )
	{
		iNbBytes = 0;					
	}		
	else
	{
		CLog::LogAndRaiseException( LOC, errno, _SLOG_ERROR );			
	}							
}		

return iNbBytes;			

}

Info:
The function return value is equal to “iSize” + 1. “iSize” never exceeded 100 bytes (ionotify).
This application is not mutli-thread. It uses pulse and ascynchrone messages.

Thanks
Rémi

I don’t see any where in this function where you compare iSize to iNbBytes. I am guessing you are detecting the problem someplace after you return from this function.

Without seeing that code too it’s impossible to guess what might be happening other than suspecting iSize is changing between the time you make this function call and the time you compare what you think iSize is vs iNbBytes.

It would be much more helpful if you had a check in this function like

if (iNbBytes > iSize)
{
CLog::LogAndRaiseException( LOC, errno, _SLOG_ERROR ); // Raise some kind of error you can detect
}

right before you return iNbBytes.

Then run your code and see if this gets triggered or if you just see the other place you are making that comparison get triggered. It should trigger both if there is really a problem with read. But I’ve never encountered anything like what you describe.

Tim

Hi,

Here is a test code:

#include <termios.h>
#include <unistd.h>
#include <sys/iomsg.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
int iComDesc = 0;
struct termios stInfoCom = {0};
struct sigevent m_EventCom;
int iChid = 0;
int iCoid = 0;
unsigned char ucBuffer[16] = {0};
int iSizeRead = 0;
errno = EOK;
int iRcvId = 0;
struct _pulse stPulse = {0};
int iRet = 0;
unsigned long ulNbRead = 0;
unsigned long ulNbBytes = 0;

printf("[---------- SERIAL TEST ON %s ----------]\n",argv[1]);

/********************************************************/
/*						OPEN PORT						*/
/********************************************************/
iComDesc = open( argv[1], O_RDWR | O_NONBLOCK );
if( iComDesc == -1 )
	return 0;			
iRet = tcgetattr( iComDesc, &stInfoCom );
if( iRet == -1 )
	return 0;			
iRet = cfmakeraw( &stInfoCom );
if( iRet == -1 )
	return 0;				
stInfoCom.c_iflag = 0;	
stInfoCom.c_oflag = 0;	
stInfoCom.c_cflag &= ~CSIZE;	
stInfoCom.c_cflag |= CS8;	
stInfoCom.c_cflag &= ~PARENB;	
stInfoCom.c_cflag &= ~CSTOPB;	
stInfoCom.c_lflag = 0;	
for( int iCpt=0; iCpt< (int)sizeof(stInfoCom.c_cc); iCpt++)
{
	stInfoCom.c_cc[iCpt] = 0;
}	
iRet = cfsetispeed( &stInfoCom, 115200 );
if( iRet == -1 )
	return 0;	
iRet = cfsetospeed (&stInfoCom, 115200 );
if( iRet == -1 )
	return 0;			
iRet = tcsetattr( iComDesc, TCSANOW, &stInfoCom );
if( iRet == -1 )
	return 0;	
	
/********************************************************/
/*					ARM	NOTIFICATION					*/
/********************************************************/
iChid = ChannelCreate( 0 );
iCoid = ConnectAttach( 0, 0, iChid,_NTO_SIDE_CHANNEL, 0 );
SIGEV_PULSE_INIT( &m_EventCom, iCoid, SIGEV_PULSE_PRIO_INHERIT, 
					( _PULSE_CODE_MINAVAIL + atoi(argv[2]) ), 0 );

iRet = ionotify( iComDesc, _NOTIFY_ACTION_TRANARM,
					_NOTIFY_COND_INPUT, &m_EventCom );
if( iRet == -1 )
	return 0;	
iRet = tcflush( iComDesc, TCIFLUSH );
if( iRet == -1 )
	return 0;		

/********************************************************/
/*				READ DATA 2 PER 2						*/
/********************************************************/
while(1)
{			
	iRcvId = MsgReceive( iChid, &stPulse, sizeof(stPulse), NULL ); 
	
	if ( ( stPulse.code == ( _PULSE_CODE_MINAVAIL + atoi(argv[2]) ) ) || ( iRcvId > 0 ) )
	{	
		iRet = ionotify( iComDesc, _NOTIFY_ACTION_TRANARM,
							_NOTIFY_COND_INPUT, &m_EventCom );		
		
		do
		{
			errno=0;
			iSizeRead = read( iComDesc, ucBuffer, 2);
			ulNbRead++;
			ulNbBytes = ulNbBytes + iSizeRead;
			if ( ( iSizeRead == -1 && errno != EAGAIN ) || ( iSizeRead > 2 ) )
			{
				printf("[ERROR][System][read]-[fildes:%X,buf:%X,nbyte:%u]-[return:%d]-[errno:%d;%s]\n",
					iComDesc, ucBuffer, 2, iSizeRead, errno, strerror( errno ) );

				iSizeRead = read( iComDesc, ucBuffer+2, iSizeRead-2);
				printf("\t");
				for (int iCpt2=0; iCpt2<16; iCpt2++)
				{
					printf("%02hhX ",ucBuffer[iCpt2]);
				}
				printf(" +iSizeRead:%d\n",iSizeRead);
				printf("[----------------------------------------------]\n");	
				 
				return 0;	
			}
		} while( iSizeRead > 0 );
	}	

	iSizeRead = 0;
	printf("\r[INFO]-[READ]- NbRead:%015lu NbOctet:%015lu",ulNbRead,ulNbBytes);
	fflush(stdout);
}
printf("[INFO]-[READ]- Data read...finish\n");	
printf("[----------------------------------------------]\n");

return 0;

}

With this code I produce my problem, the read function reads more characters than requested. However it does not provide in my buffer.
The result is identical with _NOTIFY_ACTION_POLLARM.
I made another application with a simple blocking read, it does not seem to have any problem.

For information I use 4 serial ports along with an instance of the application, an instance of a driver and different interrupt for each port

I advanced on my problem.

I worked on the source files ddk-devc-ser8250 and in particular on the part io-char. I found some potential errors in the code; io_read part. Access to certain variables (nbBytes, bup-> cnt, …) are not properly protected.
After correction, I have no problem reading that returns a value greater than nbBytes

I have another problem that was already there before, but that seemed to me to be the same.
Randomly reading the serial port 2x return me the same character.
Example:
I sent: 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19
I read: 0x10 0x11 0x12 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19

Has anyone ever had this problem?
Someone he had problems with the devc-ser8250 driver?
Someone he had problems with the io-char library?

Thank you in advance

I don’t quite understand what you wrote here. This test program is only using 1 serial port that gets passed in. So is this your setup with the test program.

  1. Start devb-ser8250
  2. Start your test program for 1 serial port (eg: myProg /dev/ser1)

You send some data. You observe the problem?

One instance of devb-ser8250 can manage multiple serial ports. We use this all the time. You can then have 1 multi-threaded application read from 4 different serial ports or you can have 4 separate applications reading from 4 different serial ports.

I’ve only seen this if there is noise on the line (bad serial cable, bad serial connector) or you have set the serial port connection incorrectly (baudrate, handshake, stopbits etc). I’ve never seen devb-ser8250 insert extra characters.

Tim

I use an instance of devc-ser8250 for 4 serial ports.

Launch:
devc-ser8250 -b9600 -E -F -u3 100,0x5 -E -F -u4 108,0x5 -E -F -u5 110,0x5 -E -F -u6 118,0x5 &

I use an application for each serial port. I added writes to the serial port.
Flow:
RX: 80Kbits/s
TX 80Kbits/s

Have you ever used serial links with high data rates?
Have you ever had problems with the library “io-char”?

Rémi

My Launch:
devc-ser8250 -u1 3f8,4 -u2 2ft,3

I’m using 2 different Irq’s while you are using just 1.

You’ve disabled hardware flow control. We leave it enabled. Not sure if this could be any issue or not as I have no experience with disabling hardware flow control.

All our serial stuff is going at 57600 or roughly half as fast as yours but I consider 57600 to be high speed.

The only part of the io-char library we use is open/close/read (my reads are actually done after returning from a select() with timeout function call). We don’t use any of the tc* functions. When I want to setup the serial ports I use the stty command via a system call: system(“stty baud=56700 par=none stopb=1 bits=8 </dev/ser1”);

Note: If you are actually going to need to process 80Kbits (10000 bytes) a second you might want to increase the size of the buffer from the default 2048 character size so that you don’t overflow the buffer if you can’t read fast enough.

Tim

I found a workaround for my problem:

I use the 8250 driver as follows :
devc-ser8250 -b9600 -E –F –t1 -u3 100,0x5 -b9600 -E –F –t1 –u4 108,0x6 -b9600 -E –F –t1 –u5 110,0x0c -b9600 -E –F –t1 –u6 118,0x0f &

Sharing IT problem. I am also obliged to use a 1 FIFO to prevent OVERRUN