我在QSerialPort
周围创建了一个包装器库。我想与我的设备通信。首先,我将list
命令发送到我的设备,它应该返回该设备支持的命令列表。但是,在调试我的代码时,我发现list
命令正在发送到设备并且设备返回正确的响应(我使用串行流量嗅探器Linux工具调试)。但是,我没有使用QSerialPort
从我的设备获得任何响应(而串行流量嗅探器工具被禁用)。经过多次测试后,我无法使其正常工作。
我的Serial.h:
class Serial : public Print {
public:
Serial();
explicit Serial(const char *dev_path);
~Serial();
int begin(unsigned long baudrate);
int begin(unsigned long baudrate, uint8_t cfg);
void end(void);
int available(void) const;
bool availableForWrite(void) const;
void flush(void);
bool isError(void) const;
void reset(void);
unsigned long write(uint8_t c);
unsigned long write(uint8_t *p_data, unsigned long maxSize);
int read(void);
void close();
QSerialPort &getPort()
{
return *_p_port;
}
public slots:
void readyBe(void);
private:
QSerialPort *_p_port;
unsigned long _baudrate;
};
我的Serial.cpp:
Serial::Serial()
{
_p_port = new QSerialPort();
if (_p_port == nullptr)
throw std::runtime_error("Can't allocate memory");
}
Serial::Serial(const char *dev_path)
{
_p_port = new QSerialPort(QString(dev_path), QApplication::instance());
if (_p_port == nullptr)
throw std::runtime_error("Can't allocate memory");
// _p_port->setPortName(QString(dev_path));
if (_p_port->open(QIODevice::ReadWrite) == false) {
throw std::runtime_error("Can't open the serial _p_port");
delete _p_port;
}
_p_port->setBaudRate(QSerialPort::Baud9600);
_p_port->setDataBits(QSerialPort::Data8);
_p_port->setParity(QSerialPort::NoParity);
_p_port->setStopBits(QSerialPort::OneStop);
_p_port->setFlowControl(QSerialPort::NoFlowControl);
}
Serial::~Serial()
{
if (_p_port != nullptr) {
end();
delete _p_port;
}
}
int Serial::begin(unsigned long baudrate)
{
if (_p_port->setBaudRate(baudrate, QSerialPort::AllDirections) == false)
return -1;
_baudrate = baudrate;
return 0;
}
void Serial::end()
{
if (_p_port->isOpen())
_p_port->close();
}
int Serial::available(void) const
{
int num_bytes = _p_port->bytesAvailable();
return num_bytes;
}
bool Serial::availableForWrite(void) const
{
if (_p_port->isWritable())
return true;
return false;
}
void Serial::flush()
{
_p_port->flush();
}
unsigned long Serial::write(uint8_t c)
{
if (_p_port->putChar(c))
return 1;
return 0;
}
unsigned long Serial::write(uint8_t *p_data, unsigned long maxSize)
{
return _p_port->write(reinterpret_cast<const char *>(p_data), (qint64)maxSize);
}
int Serial::read(void)
{
char c;
_p_port->getChar(&c);
return c;
}
void Serial::reset(void)
{
_p_port->clear(QSerialPort::AllDirections);
_p_port->clearError();
}
bool Serial::isError(void) const
{
if (_p_port->error() == QSerialPort::NoError)
return false;
return true;
}
我的main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
// w.show();
Serial serial("ttyACM0");
if (serial.begin(115200))
std::cout << "Failed to set Baud rate" << std::endl;
std::cout << "Sending data" << std::endl;
// QObject::connect(&(serial.getPort()), SIGNAL(readyRead()), &serial, SLOT(readyBe()));
serial.print("list\r");
serial.flush();
while (true) {
while (true) {
while (serial.available() == 0) {
if (serial.isError()) {
std::cout << "Error" << std::endl;
// serial.reset();
}
}
char c = serial.read();
std::cout << c;
if (c == '\n')
break;
}
std::cout << std::endl;
}
return a.exec();
}
答案 0 :(得分:1)
您几乎错过了此代码所需的一切:事件循环。现实生活中的I / O是异步的。你不能只是阅读&#34;来自端口,没有一些方法在数据可用时获得通知,并且实际上让异步I / O请求得到处理。是的,有一些遗留的API允许你这样做,但它们主要导致意大利面条代码,浪费的线程和糟糕的性能。
while (serial.available() == 0)
循环是无操作。它实际上没有让available()
返回任何其他值。 available()
内部执行的所有内容都是读取类的整数成员。您永远不会运行任何可以更新存储在该成员中的值的代码。即使您将此转换为serial.waitForReadyRead()
,其中 更新可用字节数,您仍然没有旋转事件循环,因此您不会成为能够处理超时,或对应用程序可能需要做出反应的任何其他事件做出反应。 QIODevice::waitForReadyRead
只是为了做一件事:当readyRead
信号发射时返回。它不会处理任何其他事件,并且它是用于移植阻塞代码的拐杖,并不真正用于生产用途。
您应该将代码重新设计为异步,并由来自QSerialPort
的信号驱动。然后,工作将在QCoreApplication::exec
内完成 - 您不会拥有自己的循环。这种反转控制对于使异步I / O工作至关重要。
参见例如this answer是一个非常简单的异步方法示例,this answer是一个更完整的方法。