VersaAssistant 通信协议#

接口协议说明#

  • 以下所有低位在前发送

通信协议格式#

数据段 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

使用方法#

流程#

  1. 需要自行实现物理意义的通信功能。

  2. 使用 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)。