我知道这个问题已经被多次询问了,我已经研究过,并且发现我的代码中的哪一部分给出了这个错误。我要求它为该解决方案提供替代方案。我正处理的情况是我连续收到一个大包。我已经连接了一个信号来读取如下的串行数据:
connect(&Serial, SIGNAL(readyRead()), this, SLOT(SerialRead()));
每当新的串行数据可供读取时,就会调用SerialRead()
。我正在尝试读取长度不固定的数据包。现在发生的是SerialRead()
读取几个字节的数据然后再次进行读取。由于数据包长度很大,因此无法在一次运行中读取完整的数据包。在我有完整的数据包之前,我无法进一步使用我的代码。幸运的是,我研究了数据包,发现数据包的第4个字节表示数据包的长度。所以现在我有了长度,这意味着我可以检查我是否按照第4个字节收到了完整的字节,然后再进一步移动。为此,我制作了以下代码:
QString serialData,numberOfBytes;
QStringList serialPacket;
void MainWindow::SerialRead()
{
serialData.append(Serial.readAll()); //reading all the serial data
serialPacket = serialData.split(" ");
numberOfBytes = Convert.ToDec(serialPacket[3]); //getting the length of the packer
if(serialPacket.count() >= (numberOfBytes.toInt())) //checking if all the bytes (full packet) is received or not
{
DisplayMessage(serialPacket);
}
}
因此,当我收到完整数据包时,我会转到我的DisplayMessage函数来处理数据包。现在,当出现ASSERT Failure
错误时,我注释掉了行numberOfBytes = Convert.ToDec(serialPacket[3]);
及其余的代码,然后没有错误。所以我认为错误试图说明如果serialPacket [3]不包含任何数据那么它会给出错误。如果这是真的那么什么是它的替代品。任何人都可以告诉我一个检查是否收到完整数据包的好方法。感谢
编辑:
void MainWindow::SerialRead()
{
serialData.append(Serial.readAll()); //Reading the data
if(!serialData.isEmpty()) //Checking if data is empty or not
{
serialPacket = serialData.split(" ",QString::SkipEmptyParts);
if(serialPacket.contains("CC")) //Checking if it contains "CC"
{
int index = serialPacket.indexOf("CC");
numberOfBytes = Convert.ToDec(serialPacket[index+2]);
if(serialPacket.count() >= ((numberOfBytes.toInt())+2))
{
DisplayMessage(serialPacket);
}
}
}
}
答案 0 :(得分:1)
如果在解析器的形式主义中使解析更加明确,解码器将表现得更好。双态机将完成这项工作。以下是完整的测试用例:
// https://github.com/KubaO/stackoverflown/tree/master/questions/packet-read-43228728
#include <QtTest>
#include <private/qringbuffer_p.h>
// See http://stackoverflow.com/a/32317276/1329652
/// A simple point-to-point intra-process pipe. The other endpoint can live in any
/// thread.
class AppPipe : public QIODevice {
//...
};
class Decoder : public QObject {
Q_OBJECT
QPointer<QIODevice> m_device;
QByteArray m_data;
char m_first;
bool m_isFirst = true;
static constexpr char fromHex(char c) {
return
(c >= '0' && c <= '9') ? (c - '0') :
(c >= 'A' && c <= 'F') ? (c - 'A' + 10) :
(c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
-1;
}
void decode(const QByteArray & src) {
for (auto c : src) {
auto val = fromHex(c);
if (val < 0) continue;
if (m_isFirst)
m_first = val << 4;
else
m_data.append(m_first | val);
m_isFirst = !m_isFirst;
}
}
void onReadyRead() {
// The data has the format "XX XX XX" where X are hex digits.
// Spaces and invalid digits are skipped
decode(m_device->readAll());
if (m_data.size() >= 4) {
auto length = 4 + m_data[3];
if (m_data.size() >= length) {
emit hasMessage(m_data.left(length));
m_data.remove(0, length);
}
}
}
public:
Decoder(QIODevice * dev, QObject * parent = {}) : QObject{parent}, m_device{dev} {
connect(dev, &QIODevice::readyRead, this, &Decoder::onReadyRead);
}
Q_SIGNAL void hasMessage(const QByteArray &);
};
class DecoderTest : public QObject {
Q_OBJECT
AppPipe src{nullptr, QIODevice::ReadWrite};
AppPipe dst{&src, QIODevice::ReadWrite};
Q_SLOT void initTestCase() {
src.addOther(&dst);
}
Q_SLOT void test1() {
Decoder dec(&dst, this);
QSignalSpy spy(&dec, &Decoder::hasMessage);
src.write("0"); // send a partial header
QCOMPARE(spy.size(), 0);
src.write("0 00 00 03 "); // send rest of the header
QCOMPARE(spy.size(), 0);
src.write("0A 0B "); // send partial data
QCOMPARE(spy.size(), 0);
src.write("0C "); // send rest of data
QCOMPARE(spy.size(), 1);
QCOMPARE(dst.bytesAvailable(), 0); // ensure all data has been read
const QByteArray packet{"\x00\x00\x00\x03\x0A\x0B\x0C", 4+3};
QCOMPARE(spy.first().size(), 1);
QCOMPARE(spy.first().first(), {packet});
}
Q_SLOT void test2() {
Decoder dec(&dst, this);
QSignalSpy spy(&dec, &Decoder::hasMessage);
src.write("BABE0004 C001 DA7E\n0FAB33"); // send a packet and part of another
QCOMPARE(spy.size(), 1);
src.write("01 AB\n");
QCOMPARE(spy.size(), 2);
QCOMPARE(spy.at(0).size(), 1);
QCOMPARE(spy.at(1).size(), 1);
const QByteArray packet1{"\xBA\xBE\x00\x04\xC0\x01\xDA\x7E", 4+4};
const QByteArray packet2{"\x0F\xAB\x33\x01\xAB", 4+1};
QCOMPARE(spy.at(0).first(), {packet1});
QCOMPARE(spy.at(1).first(), {packet2});
}
};
QTEST_GUILESS_MAIN(DecoderTest)
#include "main.moc"
答案 1 :(得分:1)
正如其他用户的评论中所提到的,您必须确保您尝试接收的数据包在第4个索引处有一些数据。这样您就可以进一步处理它来计算长度。正如你所说serialPacket
的第四个索引将包含长度,你必须设置一些条件,即串行数据包的大小包含至少4或5个字节。类似的东西:
if(serialPacket.size()>=5)
{
numberOfBytes = Convert.ToDec(serialPacket[3]);
}
else
{
QMessageBox MessageBox;
MessageBox.setText("Error receving packets");
}