VersaAssistant 通信协议#
接口协议说明#
以下所有低位在前发送
通信协议格式#
帧头 header 定义#
字节偏移 [0],字节大小 [5byte]
数据段 frame_user 定义#
字节偏移 [5],字节大小 [(9*+(*uLen * 4))*byte*]
帧尾 frame_tail(CRC16 整包校验)#
字节偏移 [5 + 9 + (uLen * 4byte)],字节大小 [2]
通信协议依赖(CRC8/CRC16)#
bsp_crc16.h/cpp、bsp_crc8.h/cpp
协议处理文件#
bsp_protocol.cpp、bsp_protocol.h
使用方法#
流程#
需要自行实现物理意义的通信功能。
使用
bsp_protocol接口处理数据,再通过自实现的收发接口发送。
初始化#
// 定义数据发送处理结构体
protocol_struct protocol;
// 初始化协议处理结构体,txMaxCount为允许的最大float可变数据长度,不能大于 MAX_DATA_SIZE = 28
init_protocol(&protocol, txMaxCount);
发送#
// 设置数据类型
protocol.frame.frame_user.header.cmd =
protocol.frame.frame_user.header.device_type =
protocol.frame.frame_user.header.device_id =
protocol.frame.frame_user.header.data_id =
// data_len 需要小于 max_data_len
protocol.frame.frame_user.data.data_len =
// 设置数据
for(uint16_t row=0;row<protocol.frame.frame_user.data.data_len;row++)
{
if (row < protocol.frame.frame_user.data.data_len)
{
protocol.frame.frame_user.data.pData[row] =
}
}
make_protocol(protocol);
// 需要自行实现通信接口,如果是串口,务必使用DMA提升稳定性,非DMA发送的数据时序一般不是连续的,容易断帧
transmit(protocol.message.pData, protocol.message.data_len);
接收#
receive(your_data,current_len);
memcpy(&pProtocolVersaRx->message.pData[0], your_data, current_len);
// 可以用 result 的值进行数据断帧检查,在此不做演示,断帧检查需要重复遍历,较为消耗资源,建议使用DMA和空闲中断接收方式,实现第一层的数据帧处理。然后再利用 result 进行二次检验
result = parse_protocol(protocol, current_len);
if(result == PROTOCOL_RESULT_OK)
{
// 使用数据
protocol.frame.frame_user.header.cmd;
protocol.frame.frame_user.header.device_type;
protocol.frame.frame_user.header.device_id;
protocol.frame.frame_user.header.data_id;
protocol.frame.frame_user.data.data_len;
protocol.frame.frame_user.data.pData[];
}
释放#
deinit_protocol(&protocol);
memset(&protocol, 0, sizeof(protocol));
protocol.frame.frame_user.data.pData = NULL;
protocol.message.pData = NULL;
为避免收发冲突,建议分别定义两个协议结构体处理发送与接收。
protocol_struct protocolTx;
protocol_struct protocolRx;
init_protocol(&protocolTx, txMaxCount);
init_protocol(&protocolRx, txMaxCount);
案例(Qt)#
以下为 Qt 中解析示例,初始化与赋值略。
接收#
void VersaPhysicalCom::parseProtocol(QByteArray &data)
{
int result;
if (pProtocolVersaRx != nullptr)
{
if (lastProtocolStartIndex > 0)
{
data.remove(0, lastProtocolStartIndex);
lastProtocolStartIndex = 0;
}
// 获取帧头索引
startProtocolIndex = data.indexOf(PROTOCOL_HEAD_ID, lastProtocolStartIndex);
if (startProtocolIndex != -1)
{
const char *pParseData = data.constData() + startProtocolIndex;
int dataSize = data.size();
int currentParseLength = qMin((int) (dataSize - startProtocolIndex),
(int) (pProtocolVersaRx->message.max_data_len));
if ((lastProtocolStartIndex <= startProtocolIndex) &&
(currentParseLength >= DATAS_MIN_SIZE))
{
memcpy(&pProtocolVersaRx->message.pData[0], pParseData + startProtocolIndex, currentParseLength);
result = parse_protocol(pProtocolVersaRx, currentParseLength);
switch (result)
{
// 解析成功
case PROTOCOL_RESULT_OK:
{
// 记录成功的位置,下一次的位置在此之后
lastProtocolStartIndex = startProtocolIndex + pProtocolVersaRx->message.data_len;
emit refreshProtocolRx();
// 还可以继续解析
if (lastProtocolStartIndex + DATAS_MIN_SIZE < dataSize)
{
parseProtocol(data);
}
break;
}
case PROTOCOL_RESULT_ERR:
{
// 转到下一个帧头检测
lastProtocolStartIndex = startProtocolIndex + 2;
parseProtocol(data);
break;
}
case PROTOCOL_RESULT_CHECK_HEAD_ERR:
{
// 转到下一个帧头检测
lastProtocolStartIndex = startProtocolIndex + 2;
parseProtocol(data);
break;
}
case PROTOCOL_RESULT_CHECK_FRAME_ERR:
{
// 数据帧头检查成功,但是数据损坏,移动到帧头之后检查新数据包,损坏数据包丢弃
lastProtocolStartIndex = startProtocolIndex + DATAS_OFFSET_ADDR;
parseProtocol(data);
break;
}
case PROTOCOL_RESULT_OUT_OF_MSG_LEN:
{
// 超出解析长度,数据包出错,解析下一个数据包
lastProtocolStartIndex = startProtocolIndex + DATAS_OFFSET_ADDR;
parseProtocol(data);
break;
}
case PROTOCOL_RESULT_OUT_OF_DATA_LEN:
{
// 通过包头计算,还未收到完整的数据包,等待下一个数据包来即可。
break;
}
default:
{
// 转到下一个帧头检测
lastProtocolStartIndex = startProtocolIndex + 2;
parseProtocol(data);
}
}
}
}
}
}
发送#
// const QString &address, quint16 port 是网络调试模式需要的参数,和协议无关
void VersaPhysicalCom::protocolVersaWrite(const QString &address, quint16 port)
{
if (pProtocolVersaTx != nullptr)
{
make_protocol(pProtocolVersaTx);
QByteArray writeData(reinterpret_cast<char *>(&pProtocolVersaTx->message.pData[0]),
pProtocolVersaTx->message.data_len);
// 124 字节只能收到 62字节,感觉是WIN的bug
if (pProtocolVersaTx->message.data_len == 124)
{
writeData.append('\0');
}
if ((mVersaProtocolIndex == eProtocolVersa) &&
(writeData.size() > 0))
{
startWrite(address, port, writeData);
}
}
}
支持的通信方式#
本软件所有通信方式均支持协议模式:串口、网络(TCP Server/Client、UDP)、USB(HID)。