My application should be able to communicate with different serial port settings which user chooses from UI. Every option works except software flow control. When I turn XON/XOFF on, it works with other peer. But when I turn off XON/XOFF, peer receives random amount of 0x00 bytes.
Is there anything I'm missing?
Note: I do exact same configuration to the peer as well. So when I turn on or off XON/XOFF option, I do the same for the peer.
int serialDevice = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
Serial_Params_t serialSettings;
serialSettings.baudRate = 12; // means 115200
serialSettings.dataBits = 8;
serialSettings.hardwareFlowControl = 0;
serialSettings.parity = 0;
serialSettings.parityOdd = 0;
serialSettings.stopBits = 1;
serialSettings.xonxoff = 0;
setSerialSettings(serialDevice, &serialSettings);
//---------------------------------------------------------------
int8_t setSerialSettings(int serialDevice, Serial_Params_t *settings)
{
struct termios2 tty;
memset(&tty, 0, sizeof tty);
// get current serial settings
if (ioctl(serialDevice, TCGETS2, &tty) == -1)
{
sendLog("Can't get serial attributes | setSerialSettings", LOG_TYPE_ERROR);
return FALSE;
}
// baudrate
int32_t baudrates[] = {B110, B150, B300, B600, B1200, B2400, B4800, B9600, B9600, B19200, B38400, B57600, B115200};
cfsetospeed(&tty, (speed_t)baudrates[settings->baudRate]);
cfsetispeed(&tty, (speed_t)baudrates[settings->baudRate]);
// enable input parity check
tty.c_cflag |= INPCK;
// data bits: CS5, CS6, CS7, CS8
tty.c_cflag &= ~CSIZE;
switch (settings->dataBits)
{
case 5:
tty.c_cflag |= CS5;
break;
case 6:
tty.c_cflag |= CS6;
break;
case 7:
tty.c_cflag |= CS7;
break;
case 8:
default:
tty.c_cflag |= CS8;
break;
}
// stop bit
switch (settings->stopBits)
{
case 1:
default:
tty.c_cflag &= ~CSTOPB;
break;
case 2:
tty.c_cflag |= CSTOPB;
}
// parity
if (settings->parity == 1)
tty.c_cflag |= PARENB;
else
tty.c_cflag &= ~PARENB;
// odd/even parity
if (settings->parityOdd == 1)
tty.c_cflag |= PARODD;
else
tty.c_cflag &= ~PARODD;
// flow control
// XON/XOFF
if (settings->xonxoff == 1)
tty.c_cflag |= (IXON | IXOFF | IXANY);
else
tty.c_cflag &= ~(IXON | IXOFF | IXANY);
// enable RTS/CTS
if (settings->hardwareFlowControl == 1)
tty.c_cflag |= CRTSCTS;
else
tty.c_cflag &= ~CRTSCTS;
tty.c_cc[VMIN] = 1; // raise read flag even you read 1 byte
tty.c_cc[VTIME] = 50; // 1 seconds read timeout (deciseconds)
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
// non-canonical mode
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
// flush port & apply attributes
tcflush(serialDevice, TCIFLUSH);
if (tcsetattr(serialDevice, TCSANOW, &tty) != 0)
{
sendLog("Can't set serial attributes | setSerialSettings", LOG_TYPE_ERROR);
return FALSE;
}
return TRUE;
}
I cannot explain specifically why your peer is receiving extraneous 0x00
bytes because you do not present any code responsible for sending anything at all, but the code you present for setting the serial port properties is faulty several times over. Issues include:
Use of mismatched system interfaces . You may use appropriate ioctls to retrieve and update terminal attributes, or you may use tcgetattr
and tcsetattr
, but you must not mix & match. The data structures in which the Linux ioctls deal are not interchangeable with the one that GLIBC's termios functions work with, though they are similar enough, especially in the type, names, and order of the flag members, that that might not reliably cause noticeable errors. You must have played some tricks and / or ignored some important compiler warnings to even get your code to compile.
Note that mixing & matching applies not only to retrieving and setting the overall terminal settings, but also to all use of the termios.h functions for modifying a terminal settings structure, such as cfgetispeed
and cfgetospeed
. You may use these with a settings structure obtained via tcgetattr
or, less usefully, with a directly-declared instance of the struct termios
defined by termios.h
, but not with one obtained via ioctl
. On the flip side, a structure suitable for use with any of the termios.h functions is not suitable for use with any of the ioctls for manipulating terminal properties.
Setting flag bits in the wrong flag variables . Of particular relevance to the question, you are setting the IXON
, IXOFF
, and IXANY
bits of c_cflag
, but these apply to the c_iflag
member, not c_cflag
. The leading I
in their names is mnemonic for that, though not all of the flag macros follow that convention. You are also setting INPCK
in the wrong member.
But when I turn off XON/XOFF, peer receives random amount of 0x00 bytes.
This may mean the sender is sending data faster than the receiver can cope with it.
Either
Reduce the rate of sending data (This is not so much a baud thing, more like do not send so much data at once.)
Use hardware flow control (and the wire/cables that support it).
Improve the handling the receivers incoming data.
Note: Other possibilities exit to explain the zeroes.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.