Linux Serial Port Reading - How to Change Size of Input Buffer

Linux serial port reading - can I change size of input buffer?

You want to use the serial IOCTL TIOCSSERIAL which allows changing both receive buffer depth and send buffer depth (among other things). The maximums depend on your hardware, but if a 16550A is in play, the max buffer depth is 14.

You can find code that does something similar to what you want to do here

The original link went bad: http://www.groupsrv.com/linux/about57282.html
The new one will have to do until I write another or find a better example.

how to change read buffer size of linux serial line?

in a desperate attempt at my office, we modified the host application (running on windows, build on MS Visual Studio, as a .net application). So we created a small C++ serial port control application to just bypass the .net and voila! Without altering the code on the embedded system side, I can now read the full data I expect (from the embedded device side)!

I am not going to blame .net since the problem started showing up after I ported the embedded sytem's code from an older device ARM9TDMI-ARMv4T (running linux with kernel 2.4), to the newer freescale cortex A9 imx6q sabrelite.

However, I will note here that moving away from .net code, the C++ serial port control that we wrote worked both with the old device and the new one.

So the code above should work for reading from the serial port in linux.

I wonder if there is something with the serial port driver of the boundary-devices linux kernel 3.0.35 that is used by the yocto project (and which I am running on the board right now). If somebody knows anything about serial port problems with the sabrelite, pleasee share them. Thanks!

How to handle buffering serial data

To minimize the overhead of making many read() syscalls of small byte counts (e.g. the misguided solution of reading a byte at a time), use an intermediate buffer in your code.

The read() of the serial terminal should be in blocking mode to avoid a return code of zero bytes.

#define BLEN    1024
unsigned char rbuf[BLEN];
unsigned char *rp = &rbuf[BLEN];
int bufcnt = 0;

/* get a byte from intermediate buffer of serial terminal */
static unsigned char getbyte(void)
{
if ((rp - rbuf) >= bufcnt) {
/* buffer needs refill */
bufcnt = read(fd, rbuf, BLEN);
if (bufcnt <= 0) {
/* report error, then abort */
}
rp = rbuf;
}
return *rp++;
}

For proper termios initialization code for the serial terminal, see this answer. You should increase the VMIN parameter to something closer to the BLEN value or at least the length of longest expected message, and a VTIME of 1.

Now you can conveniently access the received data a byte at a time with minimal performance penalty.

#define MLEN    1024  /* choose appropriate value for message protocol */
int main()
{
unsigned char mesg[MLEN];
...

while (1) {
while (getbyte() != 0x10)
/* discard data until start found */ ;

length = 0;
while ((mesg[length] = getbyte()) != 0x11) {
/* accumulate data until end found */
length++;
}

/* process the message */
...


} /* loop for next message */
...
}

Note that your detection for a message frame is not robust.

If the data is binary and therefore can use the same values as these start and end bytes, then this parsing of the received data is prone to misaligned message frames.

See this answer for a description of a proper alogrithm.



Related Topics



Leave a reply



Submit