LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (http://www.linuxquestions.org/questions/linux-software-2/)
-   -   Serial port output buffer lag (http://www.linuxquestions.org/questions/linux-software-2/serial-port-output-buffer-lag-870422/)

morpheusss 03-23-2011 04:13 AM

Serial port output buffer lag
 
Hi guys!
This is my first post here, hope this is the best place to ask this question. It is definitely a linux problem (same code working fine on windows).
I'm developing an application in C++ (compiled with gcc), running on Ubuntu 10.4 guest OS on XP host. I need to implement MBus protocol and I'm stuck with serial port behavior.
I configure the port properly, then I try to write some data to the port. No matter the length of the buffer I want to write, on the output of the serial port I can see 2 first characters from the buffer, then a space (time delay of about a single char length), and then the rest of the buffer. The delay varies with baudrate (higher baud, smaller delay). Seen on oscilloscope, so I'm quite confident what's going on. All the buffer content is properly sent over the serial port, the only problem is the time delay after first 2 bytes...

Have you got any idea what can cause the problem and how can I get rid of it?

I don't think it is a VM problem, I tried to run this app on PC with native Ubuntu Hardy and the behavior was exact.

Code:

int initport()
{
int fd = 0;
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1)
{
printf("\n SP failed!\n");
return fd;
}
else
{
fcntl(fd, F_SETFL, 0);
}
struct termios options;
// Get the current options for the port...
tcgetattr(fd, &options);
// Set the baud rates to 2400...
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;

// Set the new options for the port...
tcsetattr(fd, TCSANOW, &options);
fcntl(fd, F_SETFL, FNDELAY);
tcflush(fd,TCIOFLUSH);
printf("\nSP OK\n");//erial port opened succesfully, FD = %d\n", fd);
return fd;
}

int main(void)
{
int sfd = initport();

unsigned char bfr[100] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
while (1)
{
write(sfd, bfr, 12);
sleep(1);
}
return 0;
}

Thanx in advance!

rtmistler 03-24-2011 12:11 PM

I have to be honest with you, (1) extreme kudos to you for doing the due diligence and writing the correct program first, testing it out, ... putting in a proper effort before sending out a question; however (2) I have also seen the programming examples much like you have, read, and re-read the Serial HOWTO and for the life of me, I can't get things to always work correctly by using the tc functions and fcntl.

So as a result, I fork() and exec() the following:

stty -F/dev/ttyS# 19200 raw -echo

And wait on the child to complete.

Believe me, I have 4 serial USB tty devices on an embedded system, all different data rates, from 9600 up to 115.2k and getting the ports into raw mode was extremely important for me to properly get my data without delays. For some reason if you don't do that, you get what I saw and what I think you were describing, sometimes you do not get the data until a later point; it's there, but delayed. And when you have async data of indeterminate length, it is a huge deal to be stuck waiting for part of it.

If you really do wish to give the program instructions a continued effort, then read the Linux Serial HOWTO, there's an async port example right in there, and one thing you're missing is a fcntl call that includes FASYNC, and I think you are supposed to set ICANON, not clear it as you have.


All times are GMT -5. The time now is 08:51 AM.