【QT+HJ212】03:数据组包

前言

HJ/T212是由国家环保行业制定的数据传输标准协议。
目前广泛使用的是HJ/T212-2005和HJ/T212-2017通信协议。
通信方式包括RS232、RS485、GPRS、TCP/IP等。

学习资料

资料下载地址:https://download.csdn.net/download/qq_37373742/85747016
QT+HJ212专题学习地址

程序预览

程序支持HJ212-2017协议/HJ212-2005协议
程序一:通过串口通讯方式实现上位机和现场机的数据交互,下图左边上位机右边是现场机
在这里插入图片描述
程序二:通过TCP通讯方式实现上位机和现场机的数据交互,下图左边上位机右边是现场机
在这里插入图片描述

学习笔记

上位机程序逻辑在这里插入图片描述现场机程序逻辑
在这里插入图片描述
函数类含义在这里插入图片描述

关键程序代码

数据组包

1.根据命令号CN 设置数据段CP
2.设置命令号CN
3.设置报文拆分包及应答标志Flag
4.报文打包

//HJ/T212标准打包
QString UserProtocol::protocolPack(int cn)
{
    setPacketCP(contentPack(cn));            //报文内容CP设置 contentPack 根据命令号CN报文内容打包
    setPacketCN(cn);                         //报文命令号CN设置
    setReplyAndSplit(needReplyCN(cn),false); //报文Flag 是否应答,是否拆包设置
    setFramePacket(packetPack());            //报文字符串设置  packetPack 报文打包
    return framePack();
}

1.CP内容打包
在这里插入图片描述
数据区内容说明在这里插入图片描述
字段对照表在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据不同命令号CP数据区内容不同。
如现场机通过2021命令号上传设备运行状态数据。数据段CP内容包含DataTime和SB1-RS等。
在这里插入图片描述
实际数据段内容和实际项目需求有关,需要用户自定义

//报文内容打包
QString UserContent::contentPack(int cn)
{
    QString content;
    content.clear();
    if(DeviceDir==Upper) {
        switch(cn) {
        case 1000 : content = overTimeAndReCountSetPack(); break;
        case 1011 : content = emptyContentPack(); break;
        case 1012 : content = timeSetAndQueryPack(); break;
        case 1013 : content = timeCalibrationRespondPack(); break;
        case 1061 : content = emptyContentPack(); break;
        case 1062 : content = realCycleSetQndQueryPack(); break;
        case 1063 : content = emptyContentPack(); break;
        case 1064 : content = minCycleSetAndQueryPack(); break;
        case 1072 : content = passwordSetPack(); break;
        case 2011 : content = emptyContentPack(); break;
        case 2012 : content = emptyContentPack(); break;
        case 2021 : content = emptyContentPack(); break;
        case 2022 : content = emptyContentPack(); break;
        case 2031 : content = historyRequestPack(); break;
        case 2041 : content = historyRequestPack(); break;
        case 2051 : content = historyRequestPack(); break;
        case 2061 : content = historyRequestPack(); break;
        case 3011 : content = analyzerRequestPack(); break;
        case 3012 : content = analyzerRequestPack(); break;
        case 3013 : content = analyzerRequestPack(); break;
        case 3014 : content = analyzerRequestPack(); break;
        case 3015 : content = analyzerRequestPack(); break;
        case 3016 : content = analyzerRequestPack(); break;
        case 3017 : content = analyzerTimeCalibrationRequestPack(); break;
        case 3018 : content = analyzerSamplingCyclePack(); break;
        case 3019 : content = analyzerRequestPack(); break;
        case 3020 : content = analyzerRequestPack(); break;
        case 3021 : content = analyzerRequestPack(); break;
        case 3022 : content = informationRequestPack(); break;
        case 9014 : content = emptyContentPack(); break;
        }
    } else if(DeviceDir==Lower) {
        switch(cn) {
        case 1011 : content = timeSetAndQueryPack(); break;
        case 1013 : content = emptyContentPack(); break;
        case 1061 : content = realCycleSetQndQueryPack(); break;
        case 1063 : content = minCycleSetAndQueryPack(); break;
        case 2011 : content = realDataUploadPack(); break;
        case 2021 : content = manageFacilityStatusUploadPack(); break;
        case 2031 : content = dayDataUploadPack(); break;
        case 2041 : content = manageFacilityTimeUploadPack(); break;
        case 2051 : content = minuteDataUploadPack(); break;
        case 2061 : content = hourDataUploadPack(); break;
        case 2081 : content = restartTimeUploadPack(); break;
        case 3019 : content = analyzerSamplingCyclePack(); break;
        case 3020 : content = analyzerSamplingStopTimeRespondPack(); break;
        case 3021 : content = analyzerIdentifierUploadPack(); break;
        case 3022 : content = informationUploadPack(); break;
        case 9011 : content = requestRespondPack(); break;
        case 9012 : content = resultRespondPack(); break;
        }
    }
    return content;
}

报文拆分包及应答标志
在这里插入图片描述

//是否应答,是否拆包设置
void UserPacket::setReplyAndSplit(bool reply,bool split)
{
    Flag = (version<<2);//version 0为HJ212-2005协议 1为HJ212-2017协议
    Flag &= 0xFC;
    if(split) {Flag |= 0x02;}
    if(reply) {Flag |= 0x01;}
}

报文打包 packetPack
国标HJ/212-2005与2017通讯包组成相同,区别数据段有些差异。
在这里插入图片描述
详细内容请参考博客:【QT+HJ212】01:协议分析

//报文打包
QString UserPacket::packetPack()
{
    if(device()==NULL) {
        MN = deviceMN();
        PW = devicePW();
        ST = deviceST();
        //Flag &= 0x03;
        //Flag = (version()<<2);
    } else {
        MN = device()->deviceMN();
        PW = device()->devicePW();
        ST = device()->deviceST();
        Flag &= 0x03;
        Flag |= (device()->version()<<2);
    }
    QString packet;
    packet.clear();
    if(version()==0) { //HJ/T212-2005标准
        if(direction()==Upper) { //服务器端
            if(CN<9000) {
                packet += QString("QN=%1;").arg(QN);
                packet += QString("ST=%1;").arg(ST);
                packet += QString("CN=%1;").arg(QString::number(CN));
                packet += QString("PW=%1;").arg(PW);
                packet += QString("MN=%1;").arg(MN);
                if(CN!=2012 && CN!=2022) {
                    packet += QString("Flag=%1;").arg(QString::number(Flag));
                }
                packet += QString("CP=&&%1&&").arg(CP);
            } else if(CN==9013){
                packet += QString("ST=91;");
                packet += QString("CN=%1;").arg(QString::number(CN));
                packet += QString("PW=%1;").arg(PW);
                packet += QString("MN=%1;").arg(MN);
                packet += QString("Flag=0;");
                packet += QString("CP=&&QN=%1&&").arg(QN);
            } else if(CN==9014) {
                packet += QString("ST=91;");
                packet += QString("CN=%1;").arg(QString::number(CN));
                packet += QString("CP=&&QN=%1;%2&&").arg(QN).arg(CP);
            }
        } else if(direction()==Lower) { //数采仪端
            if(CN<9000) {
                if(CN==2072) {
                    packet += QString("QN=%1;").arg(QN);
                    packet += QString("ST=%1;").arg(ST);
                    packet += QString("CN=%1;").arg(QString::number(CN));
                    packet += QString("PW=%1;").arg(PW);
                    packet += QString("MN=%1;").arg(MN);
                    packet += QString("Flag=%1;").arg(QString::number(Flag));
                    packet += QString("CP=&&%1&&").arg(CP);
                } else {
                    packet += QString("ST=%1;").arg(ST);
                    packet += QString("CN=%1;").arg(QString::number(CN));
                    packet += QString("PW=%1;").arg(PW);
                    packet += QString("MN=%1;").arg(MN);
                    if(CN>=2000 && CN<3000) {
                        packet += QString("CP=&&%1&&").arg(CP);
                    } else {
                        packet += QString("CP=&&QN=%1;%2&&").arg(QN).arg(CP);
                    }
                }
            } else if(CN==9011){
                packet += QString("ST=91;");
                packet += QString("CN=%1;").arg(QString::number(CN));
                packet += QString("PW=%1;").arg(PW);
                packet += QString("MN=%1;").arg(MN);
                packet += QString("Flag=0;");
                packet += QString("CP=&&QN=%1;%2&&").arg(QN).arg(CP);
            } else if(CN==9012) {
                packet += QString("ST=91;");
                packet += QString("CN=%1;").arg(QString::number(CN));
                packet += QString("PW=%1;").arg(PW);
                packet += QString("MN=%1;").arg(MN);
                packet += QString("CP=&&QN=%1;%2&&").arg(QN).arg(CP);
            } else if(CN==9013) {
                packet += QString("ST=91;");
                packet += QString("CN=%1;").arg(QString::number(CN));
                packet += QString("PW=%1;").arg(PW);
                packet += QString("MN=%1;").arg(MN);
                packet += QString("CP=&&QN=%1&&").arg(QN);
            }
        }
    } else if(version()==1) { //HJ/T212-2016标准
        packet += QString("QN=%1;").arg(QN);
        if(CN < 9000) {
            packet += QString("ST=%1;").arg(ST);
        } else {
            packet += QString("ST=91;");
        }
        packet += QString("CN=%1;").arg(QString::number(CN));
        packet += QString("PW=%1;").arg(PW);
        packet += QString("MN=%1;").arg(MN);
        if(CN < 9000) {
            packet += QString("Flag=%1;").arg(QString::number(Flag));
            if(Flag==6 || Flag==7) {
                packet += QString("PNUM=%1;").arg(QString::number(PNUM));
                packet += QString("PNO=%1;").arg(QString::number(PNO));
            }
        } else {
            packet += QString("Flag=4;");
        }
        packet += QString("CP=&&%1&&").arg(CP);
    }
    return packet;
}

发送数据、分包上传

每帧数据帧的数据区CP最大为950。当数据内容过大时需要对数据进行拆包分包发送。
在这里插入图片描述
如:CN2031 日数据上传 因数据量过大 分包上传
在这里插入图片描述

//给指定服务器发送打包数据
void UserClientDevice::sendPackMsg(const QString & id, const QString & msg,bool reply,bool split)
{
    Q_UNUSED(split)
    if(msg.size() <= 950)   //数据量小于900 900 为一阵数据最大长度
    {
        if(!msg.isEmpty()) {emit sendMsg(id,msg);}
    }
    else
    {
        QString Msg = msg;
        bool ok;
        int cn = fieldExtract(Msg,"CN",&ok).toInt();

        Msg = getCP(Msg);
        QString time = fieldExtract(Msg,"DataTime",&ok);
        Msg = Msg.mid(Msg.indexOf("DataTime")+QString("DataTime").size()+time.size()+1);    //DataTime之后的数据
        if(ok)
        {
            int Pnum = Msg.size()/800 + 1;
            QStringList spitData = Msg.split(";");
            int spitNum = 0;

            for(int i=1; i<=Pnum; i++)
            {
                QString Data = QString("DataTime=%1;").arg(time);
                for(;Data.size()<800;)
                {
                    if(spitNum>=spitData.size())
                        break;
                    Data.append(spitData.at(spitNum));
                    spitNum++;
                }
                QString pumpMsg;
                Protocol->protocolPackHandleWidthPUMPPNO(&pumpMsg,Data,cn,reply,true,Pnum,i);
                if(!msg.isEmpty()) {emit sendMsg(id,pumpMsg);}
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jbyyy、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值