【发布时间】:2021-02-24 15:15:30
【问题描述】:
我正在使用非阻塞 IO,我只是尝试对串行端口进行写入和读取。串行端口的读取按预期工作,而写入则没有。
这就是我设置串行线路的方式。如您所见,它设置为非阻塞和规范。也许有些标志是多余的,但它们大多取自这里的示例:Serial setup example
tSerial::tSerial(const char *serialPort, bool echo)
{
// Open the serial port. Change device path as needed (currently set to an standard FTDI USB-UART cable type device)
m_serialPort = open(serialPort, O_RDWR);
// Create new termios struct, we call it 'tty' for convention
struct termios tty;
// Read in existing settings, and handle any error
if (tcgetattr(m_serialPort, &tty) != 0)
{
spdlog::error("[tSerial] error {} from tcgetattr: {}", errno, strerror(errno));
throw std::runtime_error("Failed to get existing serial settings");
}
tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size
tty.c_cflag |= CS8; // 8 bits per byte (most common)
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
// tty.c_lflag &= ~ICANON;
tty.c_cflag |= ICANON;
if (!echo)
{
tty.c_lflag &= ~ECHO; // Disable echo
}
else
{
tty.c_lflag |= ECHO; // Enable echo
}
// tty.c_lflag &= ~ECHOE; // Disable erasure
// tty.c_lflag &= ~ECHONL; // Disable new-line echo
// tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes
tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
// Set in/out baud rate to be 115200
cfsetispeed(&tty, B115200);
cfsetospeed(&tty, B115200);
// Save tty settings, also checking for error
if (tcsetattr(m_serialPort, TCSANOW, &tty) != 0)
{
spdlog::error("[tSerial] error {} from tcsetattr: {}", errno, strerror(errno));
throw std::runtime_error("Failed to set new serial settings");
}
// Set non-blocking
int flags;
if ((flags = fcntl(m_serialPort, F_GETFL, 0)) == -1)
{
flags = 0;
}
fcntl(m_serialPort, F_SETFL, flags | O_NONBLOCK);
}
这就是我尝试写作的方式。我正在使用select 等待IO 资源可用,因为尝试直接写入它会给出错误Resource temporarily unavailable。但即使等待 20 秒,设备仍然不可用。
void tSerial::writeSerial(std::string message)
{
int n;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(m_serialPort, &rfds);
spdlog::debug("[tSerial] writing command to serial {}", message);
struct timeval tv;
tv.tv_sec = 20;
tv.tv_usec = 0;
int retval = select(1, NULL, &rfds, NULL, &tv);
if (retval == -1)
{
spdlog::error("[tSerial] select error");
}
else if (retval)
{
n = write(m_serialPort, message.c_str(), message.length());
tcflush(m_serialPort, TCIOFLUSH);
if (n < 0)
{
spdlog::error("[tSerial] error writing: {}", strerror(errno));
}
}
else
{
spdlog::error("[tSerial] Resource unavailable after 20 seconds wait");
}
}
【问题讨论】:
-
所以调用
write返回 -1 ?在这种情况下,errno是什么?根本不需要选择,没有时间设备“不可用”。直接从 cmd 行写入有效吗? -
没有
selectwrite如你所说返回-1。errno是 11,EAGAIN。从这个link,在第二个答案中建议使用select。echoing 到设备按预期工作。 microcom 也可以使用它。 -
嗯,我看不出代码有什么问题。您确定设备没有被其他程序保持忙碌吗?如果将其设置为原始模式会发生什么(有关标志,请参见 termios 的手册页)?为什么不直接在
open中设置为 no-block 呢?如果至少设置了一个设置,tcsetattr会成功,请再次阅读以查看所有设置是否已真正应用。尝试this answer 创建一个虚拟串口设备并尝试它是否适用。使用stty检查真实设备。
标签: c++ c linux serial-port