我正在研究解码类似 HDLC 的协议,并从网上找到的一些代码开始(https://github.com/jarkko-hautakorpi/Arduhdlc)。以下代码是摘录,重点介绍我遇到的问题。它读取 QByteArray(来自串行),然后丢弃初始和最终帧边界字节,管理转义序列并检查 CRC
#include <QCoreApplication>
#include <QDebug>
#include "hdlc_qt.h"
#define FRAME_BOUNDARY_OCTET 0x7E
#define CONTROL_ESCAPE_OCTET 0x7D
#define INVERT_OCTET 0x20
QByteArray receive_frame_buffer;
quint16 frame_position;
quint16 frame_checksum;
bool escape_character;
bool hdlcFrameCRC_check(int frame_index);
void charReceiver(QByteArray dataArray)
{
quint8 data = 0;
qDebug() << "Received:\t"<<dataArray.toHex();
for(QByteArray::iterator it = dataArray.begin(); it != dataArray.end(); it++) {
data = (*it);
//qDebug ("data: %x",data);
/* Start flag or end flag */
if(data == FRAME_BOUNDARY_OCTET) {
qDebug("FRAME_BOUNDARY_OCTET: %x",data);
qDebug() << "frame_position:"<<frame_position;
if(escape_character == true) {
escape_character = false;
}
/* Do CRC check if frame is valid */
else if( (frame_position >= 2) && (hdlcFrameCRC_check(frame_position)) ) {
/* Call user defined function to handle HDLC frame */
qDebug() << "ValidFrame"<<receive_frame_buffer.toHex();
}
qDebug() << "frame_buffer:\t"<<receive_frame_buffer.toHex();
/* Reset all for next frame */
frame_position = 0;
frame_checksum = 0;
receive_frame_buffer.clear();
continue;
}
if(escape_character) {
escape_character = false;
data ^= INVERT_OCTET;
} else if(data == CONTROL_ESCAPE_OCTET) {
escape_character = true;
continue;
}
//receive_frame_buffer[frame_position] = data;
receive_frame_buffer.append(data); //changed to avoid compiler warning
// qDebug ("rx_framebuf[%d] = %x",frame_position,receive_frame_buffer.at(frame_position));
frame_position++;
/* If we don't ever receive valid frame,
* buffer will keep growing bigger and bigger.
* Hard coded max size limit and then reset
*/
if(frame_position >= 2048)
{
receive_frame_buffer.clear();
frame_position = 0;
frame_checksum = 0;
}
}
}
bool hdlcFrameCRC_check(int frame_index)
{
/* frame = ...[CRC-LO] [CRC-HI] */
quint16 crc_received = 0;
crc_received = receive_frame_buffer[frame_index-1]; // msb
crc_received = crc_received << 8;
crc_received |= receive_frame_buffer[frame_index-2]; // lsb
quint16 crc_calculated = qChecksum((const char*)receive_frame_buffer.constData(), frame_index-2);
//crc_calculated = crc_calculated^0xFFFF;
qDebug("CRC received:%x",crc_received);
qDebug("CRC calculated:%x",crc_calculated);
if(crc_received == crc_calculated) {
return true;
} else {
return false;
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QByteArray test1 = QByteArray("\x7E\x08\x1A\x00\x00\x07\x2B\x08\x00\x08\x16\x00\x00\x08\x8E\x07\xF7\x22\x20\x7E",20);
QByteArray test2 = QByteArray("\x7e\x08\x22\x00\x00\x07\x28\x08\x08\x08\x10\x00\x05\x08\x95\x07\xff\xf6\x41\x7e",20);
QByteArray test3 = QByteArray("\x7e\x08\x22\x00\x00\x07\x21\x08\x09\x08\x10\x00\x07\x08\x8f\x08\x00\xe7\x89\x7e",20);
QByteArray test4 = QByteArray("\x7e\x08\x0e\x00\x00\x07\x2f\x08\x07\x08\x1b\x00\x00\x08\x93\x07\xf8\x9a\xb1\x7e",20);
QByteArray test5 = QByteArray("\x7e\x08\x27\x00\x00\x07\x27\x08\x0a\x08\x10\x00\x05\x08\x93\x07\xfd\x18\x53\x7e",20);
QVector<QByteArray> test;
test.push_back(test1);
test.push_back(test2);
test.push_back(test3);
test.push_back(test4);
test.push_back(test5);
for(int i = 0; i < test.size();++i) {
qDebug()<<"-------------------------------------------------------";
qDebug()<<"Test #" << i+1<< ":\t "<< test[i].toHex();
charReceiver(test[i]);
}
return a.exec();
}
我准备了一些测试,分别命名为 test1、...、test5,并发现它在 CRC 验证步骤中失败。问题是,在某些测试中,传递给方法的 CRC 序列是初始序列中不存在的序列。对于 test1,CRC 序列(“\x22\x20”)正确传递,而在 test2 中,方法接收的是“\xff\xf6”,而不是“\xf6\x41”,对于 test3 和 test4 也是如此,而 test5 是正确的。您有什么可能的解释和补救措施吗?
一定要记得检查中间值。
我不太了解底层的方面,但似乎只要结果大于 127(8 位),
QByteArray[index]
就可能导致quint16 。0xffxx
只需对 进行 QDebug 即可
receive_frame_buffer[...]
:例如,对于第四个测试,其结果应该是b1
(index - 1
)和9a
(index - 2
),您实际上会得到:显然,这会导致
ff9a
转变和使用|
操作员。不幸的是,我没有使用 C++ 的经验,因此可能有更优雅的方法来做到这一点,但如果您想避免进一步的临时变量,最简单的解决方案是使用以下命令屏蔽
QByteArray[]
结果0xff
: