串行套接字-忽略在非规范模式下收到的POLLHUP ?



我有一个树莓派通过UART连接到微控制器。RPI上的代码试图读取传入的非规范UART数据,但随机接收POLLHUP。我已经能够通过关闭并重新打开文件来恢复,但这不是理想的。

是否有一种方法可以禁用Linux中终端的断开连接检测行为?我不确定为什么要提高POLLHUP。我怀疑一些控制字符仍然被解释,尽管我调用cfmakeraw()。电缆不太可能是问题,因为规范的调试输出工作良好(诚然,在不同的引脚上,但是相同的波特率和相同类型的电缆)。

示例代码,setup:
bool UartSocket::setup()
{
int fd = ::open("/dev/serial0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == 0)
{
return false;
}
struct termios portSettings;
::memset(&portSettings, 0, sizeof(portSettings));
if (m_rSyscalls.tcgetattr(fd, &portSettings) != 0)
{
m_logger.error("tcgetattr() failed, errno = %d.", errno);
return false;
}
m_rSyscalls.cfsetispeed(&portSettings, 115200);
m_rSyscalls.cfsetospeed(&portSettings, 115200);
cfmakeraw(&portSettings);
// Fiddling with more settings out of desperation
portSettings.c_iflag &= ~IGNBRK; // disable break processing
portSettings.c_lflag &= ~ICANON;
portSettings.c_cc[VEOF] = 0;
if (m_rSyscalls.tcsetattr(fd, TCSANOW, &portSettings) != 0)
{
m_logger.error("tcsetattr() failed, errno = %d.", errno);
return false;
}
// Prepare to poll on recv() calls
m_pollfd.fd = fd;
m_pollfd.events = POLLIN;
return true;
}
示例代码,Rx:
ssize_t UartSocket::recv(char* buf, size_t maxRead)
{
ssize_t readResult = -1;
int pollResult = ::poll(&m_pollfd, 1, 1000);
if (pollResult > 0)
{
if (m_pollfd.revents & POLLERR)
{
int error = 0;
socklen_t errlen = sizeof(error);
if (getsockopt(
fd,
SOL_SOCKET,
SO_ERROR,
static_cast<void*>(&error),
&errlen))
{
m_logger.error(
"getsockopt failed when trying to diagnose an error.");
}
m_logger.error(
"Error on uart %s. Error = %d, len = %u.",
m_rConfig.getPath().c_str(),
error,
errlen);
return -1;
}
if (m_pollfd.revents & POLLIN)
{
readResult = ::read( //
fd,
buf,
maxRead);
m_logger.info("readResult = %d.", readResult);
if (readResult > 0)
{
// Party, we are happy
return readResult;
}
else if (readResult == 0)
{
// empty read..no-op
m_logger.dump("Got an empty UART read.");
}
else
{
if (errno == EAGAIN)
{
// No data was available to read; do nothing.
readResult = 0;
m_logger.dump("Got an empty UART read.");
}
else
{
m_logger.error(
"Failure reading uart %s, errno = %d.",
m_rConfig.getPath().c_str(),
errno);
}
}
}
// We wait for the buffer to empty before handling any hangups
if ((m_pollfd.revents & POLLHUP) && (readResult == 0))
{
m_logger.error("Hangup on uart %s.", m_rConfig.getPath().c_str());
reopen(); // closes the fd, reopens it and repeats the termios setup
}
}
else if (pollResult == 0)
{
// No data was available to read; do nothing.
readResult = 0;
m_logger.dump("Got an empty UART poll.");
}
else
{
m_logger.error("Failure polling uart 0, errno = %d.", errno);
readResult = -1;
}
return readResult;
}

TL;DR:上面的代码有一个分支,通过关闭和重新打开串行设备来处理POLLHUP。我正在与一个发送原始字节的设备交谈,如果Linux中的术语在POLLHUP的情况下不会使文件描述符不可用,我更希望这样做。理想情况下,他们也应该完全忽略导致这种情况的控制字符,如果它是一个控制字符。有办法做到这一点吗?

通过正确设置波特率解决了POLLHUP问题。

我的原始代码有一个对cfsetispeed(&portSettings, 115200);的调用。这是错误的,B115200需要通过。B115200是一个常量,通常解析为不可预知的东西(例如)。

我建议不要复制我的代码,而是使用这个示例来进行基本的原始tty设置。

最新更新