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

Serial socket - ignore POLLHUP received in non-canonical mode?

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

有没有办法在 Linux 中禁用 termios 的断开连接检测行为?我不确定为什么首先提出 POLLHUP 。我怀疑尽管我调用了 cfmakeraw(),但某些控制字符仍在被解释。电缆不太可能是问题,因为规范的调试输出工作正常(不可否认,在不同的引脚上,但相同的波特率和相同类型的电缆)。

示例代码,设置:

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 中的 termios 不会使文件描述符在 POLLHUP 的情况下不可用,我会更喜欢它。理想情况下,如果它是控制字符,他们也应该完全忽略导致这种情况的任何控制字符。有办法吗?

POLLHUP 问题已通过正确设置波特率得到解决。

我的原始代码调用了 cfsetispeed(&portSettings, 115200);。这是错误的,需要传递 B115200B115200 是一个常数,通常解析为不可预测的东西 (example)。

我建议不要从我的代码中复制,而是使用 this example 进行基本的原始 tty 设置。