无法写入串行设备,但可以从中读取
Unable to write to serial device but able to read from it
我使用的是非阻塞IO,我只是尝试对串行端口进行写入和读取。读取串行端口可以正常工作,而写入则不然。
这就是我设置串行线路的方式。正如您所看到的,它被设置为非阻塞和规范。也许有些标志是多余的,但它们大多取自这里的一个示例:串行设置示例
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");
}
}
我正在使用
select
等待IO资源可用。。。但即使等待20秒,该设备仍然不可用。
您的程序没有按预期运行,因为您没有正确编程select((调用:
int retval = select(1, NULL, &rfds, NULL, &tv);
根据man页面应设置为三个集合中任何一个集合中编号最高的文件描述符加1
由于您正在传递值1
,select((可以检查的唯一文件描述符是stdin
(只读,永远不会准备好输出(,并且永远不会(打开的串行终端的文件描述符(
相反,系统调用需要是
select(m_serialPort + 1, ...);
您的代码有其他问题。
(1( 使用非阻塞模式是有问题的
您似乎更喜欢在程序中添加额外的代码以等待,而不是让操作系统为您执行。如果你的程序不能有效地利用它的时间片,那么你最好让操作系统管理系统资源。
(2( 在write((之后使用tcplush((荒谬和错误的
您可能打算使用tcdrain((
研究man页面。
(3( 当您复制&修改了引入至少一个bug的代码ICANON
在c_lflag
成员中,而不在c_cflag
中。
(4( 良好的编码实践是使用有意义的变量名
将读参数的变量名重新用作写参数是草率和令人困惑的:
fd_set rfds;
...
int retval = select(..., NULL, &rfds, NULL, &tv);
您的程序应该使用类似wfds
的内容作为第三个参数,而不是rfds
。
。。。尝试直接写入会产生错误
Resource temporarily unavailable
使用select((时的问题很容易解释
对于上述问题,您需要提供一个最小的、可重复的示例,即一个完整的程序。
- Clion显示错误,但可以使用Cmake成功构建代码
- 我可以读取静态对象中的文件.txt吗?C++
- Eclipse CDT clang 工具链 - 无法从链接器选项中删除 stdlibc++,但可以添加 libc++,E
- 成员函数不能为集合迭代器和const_iterator的输入重载(但可以为其他 STL 迭代器重载)
- 多个线程可以读取同一个类成员变量吗?
- QSerialPort 有可用字节,但无法读取
- 为什么我们不能使用整数到字符串直接转换,但可以按位到字符串?
- 为什么我不能写cout<<a==b;但可以写cout<<(a==b);
- 无法使用 Openvino 中间表示文件转发() 网络,但可以使用我正在制作 IR 的 ONNX 文件
- VSCode C/C++IntelliSense标识符未定义,但可以解析定义
- ESP8266读取 JSON,但不读取 PHP 文件
- 为什么我不能在未链接的 DLL 上调用方法,但可以这样做?C++
- std::memcmp 可以读取超过第一个差异的任何字节吗?
- 在C++中使用多线程时,是否可以读取半写的、损坏的原始变量?
- 我将如何通过抽象类传递虚拟方法,但可以选择不重写
- 是否可以读取和写入头文件?
- 是否可以将结构与条件语句完全相同的字符串转换为可以读取和操作的语句?
- gtest - 确保方法之前没有被调用,但可以在某个方法调用之后调用
- 无法使用Ostream打印,但可以使用COUT打印
- 设置具有非constexpr函数的constexpr变量(但可以在编译时间计算)