Jt808应答举例

news2025/1/16 14:56:51

1.前言

最近客户在集成基于Jt808的产品协议的时候,经常会遇到一些问题,比如没有进行转义,或者转义的时机不对,导致校验码没有进行转义。为了让大家更熟悉Jt808的指令组包,我这里整理了一下转义的步骤。

2.组包

以此应答包0x8001为例:7E 8001 0005 413050530988 0001 0009 0200 00 7D01 7E

组包过程如下:

2.1.第一步

我们先封装消息体,包含:应答流水号+应答消息ID+应答结果,即:0009 0200 00

2.2.第二步

我们封装需要计算校验码的消息体部分:包含:应答消息ID:8001 + 消息体属性(长度):0005 + 设备S/N:413050530988 + 消息流水号:00001 + 第一步中的消息体(应答流水号+应答消息ID+应答结果):0009 0200 00;

即:8001 0005 413050530988 0001 0009 0200 00

2.3.第三步

计算校验码,将第二步所有消息进行累加和,得到的结果为7D,可参考下面的方法

    /**
     * XOR every byte
     *
     * @param buf (第二步得到的Buf)
     * @return 输出校验码,如果以上述为例得到的校验码为:7D
     */
    public static int xor(ByteBuf buf) {
        int checksum = 0;
        while (buf.readableBytes() > 0) {
            checksum ^= buf.readUnsignedByte();
        }
        return checksum;
    }

2.4.第四步

将第二步的消息体与第三步得到的校验码组成完整的消息包:8001 0005 413050530988 0001 0009 0200 00 7D

2.5.第五步

对完整的消息包进行转义,即:7E——>7D02;7D——>7D01,可采用下面的方法;最终我们得到转义后的消息为:8001 0005 413050530988 0001 0009 0200 00 7D01

    /**
     * In the message header, message body and check code, 0x7E is escaped as 0x7D 0x02, and 0x7D is escaped as 0x7D 0x01
     *
     * @param out 待输出转义后的消息体
     * @param bodyBuf 第四步中的消息内容
     */
    public static void escape(ByteBuf out, ByteBuf bodyBuf) {
        while (bodyBuf.readableBytes() > 0) {
            int b = bodyBuf.readUnsignedByte();
            if (b == 0x7E) {
                out.writeShort(0x7D02);
            } else if (b == 0x7D) {
                out.writeShort(0x7D01);
            } else {
                out.writeByte(b);
            }
        }
    }

2.6.第六步

增加包头包尾的7E,到此给设备应答的消息包组包完毕,最终下发给设备的消息体应该是:7E80010005413050530988000100090200007D017E

3.最后附上我下发指令的完整代码

3.1.封装平台通用应答

    /**
     * Platform general response
     *
     * @param ctx
     * @param jt808Msg
     * @param replyResultEnum
     * @return
     */
    public static ChannelFuture reply8001(ChannelHandlerContext ctx, Jt808Message jt808Msg, Jt808ReplyResultEnum replyResultEnum) {
        ByteBuf msgBody = Unpooled.buffer(5);
        msgBody.writeShort(jt808Msg.getMsgFlowId());
        msgBody.writeShort(jt808Msg.getMsgId());
        msgBody.writeByte(replyResultEnum.getValue());
        return sendToTerminal(ctx, Jt808MessageIdEnum.MSG_8001.getMessageId(), jt808Msg.getProtocolType(), jt808Msg.getProtocolVersion(), jt808Msg.getPhoneNumberArr(), msgBody);
    }

 3.2.封装指令下发到设备

    /**
     * Send message to terminal
     *
     * @param ctx
     * @param messageId
     * @param protocolType
     * @param protocolFlag
     * @param phoneNumberArr
     * @param msgBody
     * @return
     */
    private static ChannelFuture sendToTerminal(ChannelHandlerContext ctx, int messageId, ProtocolEnum protocolType, int protocolFlag, byte[] phoneNumberArr, ByteBuf msgBody) {
        Jt808Message replyMsg = new Jt808Message();
        replyMsg.setMsgId(messageId);
        replyMsg.setProtocolType(protocolType);
        replyMsg.setVersionFlag(protocolType == ProtocolEnum.JT808_2019 ? 1 : 0);
        replyMsg.setProtocolVersion(protocolFlag);
        replyMsg.setPhoneNumberArr(phoneNumberArr);
        replyMsg.setMsgFlowId(SessionUtil.getNextMsgFlowId(ctx));
        replyMsg.setMsgBody(msgBody);
        ChannelFuture future = ctx.writeAndFlush(replyMsg);
        future.addListener((ChannelFutureListener) channelFuture -> {
            if (!channelFuture.isSuccess()) {
                log.error("Sending data exception", channelFuture.cause());
            }
        });
        return future;
    }

 3.3.最后组成完整的包,并将指令下发给设备

/**
 * <p>Description: JT808 message entity encoder</p>
 *
 * @author Mr.Li
 * @date 2022-10-20
 */
@Slf4j
public class Jt808ProtocolEncoder extends MessageToByteEncoder<Jt808Message> {

    @Override
    protected void encode(ChannelHandlerContext ctx, Jt808Message msg, ByteBuf out) throws Exception {
        ByteBuf msgBody = msg.getMsgBody();
        int msgBodyLen = msgBody == null ? 0 : msgBody.readableBytes();
        //Protocol Type
        ProtocolEnum protocolType = msg.getProtocolType();
        //the length of remove the tip and tail
        int contentLen = protocolType == ProtocolEnum.JT808_2019 ? Jt808Constant.JT2019_MSG_BASE_LENGTH + msgBodyLen - 2 : Jt808Constant.MSG_BASE_LENGTH + msgBodyLen - 2;
        //Subcontracting is required to add the total number of messages and packet number 4 bytes
        if (msg.isMultiPacket()) {
            contentLen = contentLen + 4;
        }

        ByteBuf bodyBuf = ByteBufAllocator.DEFAULT.heapBuffer(contentLen);
        try {
            //message id
            bodyBuf.writeShort(msg.getMsgId());
            //The length of the message body in the message body property
            int msgBodyAttr = msgBodyLen | (msg.getEncryptType() << 10);
            //The subcontract identity in the message body property
            if (msg.isMultiPacket()) {
                msgBodyAttr = msgBodyAttr | 0b00100000_00000000;
            }

            //The Jt808-2019 version adds the version identifier and protocol version number
            if (protocolType == ProtocolEnum.JT808_2019) {
                //Version identification
                msgBodyAttr = msgBodyAttr | 0b01000000_00000000;
                //message body property
                bodyBuf.writeShort(msgBodyAttr);
                //Protocol version Number
                bodyBuf.writeByte(msg.getProtocolVersion());
            } else {
                //message body properties
                bodyBuf.writeShort(msgBodyAttr);
            }

            //terminal number
            bodyBuf.writeBytes(msg.getPhoneNumberArr());
            //Message serial number
            bodyBuf.writeShort(msg.getMsgFlowId());
            //Package item of message (subcontracting needs to add the total number of message packets and packet number)
            if (msg.isMultiPacket()) {
                bodyBuf.writeShort(msg.getPacketTotalCount());
                bodyBuf.writeShort(msg.getPacketOrder());
            }
            //message body
            if (msgBodyLen > 0) {
                bodyBuf.writeBytes(msgBody);
            }
            //check code
            int checkCode = CommonUtil.xor(bodyBuf);
            bodyBuf.writeByte(checkCode);
            //message header
            out.writeByte(Jt808Constant.MSG_HEAD_TAIL_FLAG);
            //The read index is reset to the starting position
            bodyBuf.readerIndex(0);
            //escape
            Jt808PacketUtil.escape(out, bodyBuf);
            //message tail
            out.writeByte(Jt808Constant.MSG_HEAD_TAIL_FLAG);
            log.info("downlink command:{}", ByteBufUtil.hexDump(out));
        } catch (Exception e) {
            log.error("{}message encoding exception,message:{}", protocolType, msg, e);
        } finally {
            //release message body
            if (msgBody != null) {
                ReferenceCountUtil.release(msgBody);
            }
            //release bodyBuf
            ReferenceCountUtil.release(bodyBuf);
        }
    }
}

欢迎对物联网感兴趣的朋友加我微信交流学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1154379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

android 8.1 disable unsupported sensor

如果device不支持某种sensor,可以在android/frameworks/base/core/java/android/hardware/SystemSensorManager.java里将其disabled掉。以disable proximity sensor为例。 public SystemSensorManager(Context context, Looper mainLooper) {synchronized(sLock) {if (!sNativ…

mysql---DCL(用户创建及限制)

DCL: 权限控制语句 grant revoke 数据库用户管理: 创建用户 修改用户的权限 删除用户 grant 要在终端执行。 用户创建语句注释 create user ky32localhost identified by 123456; create user 创建用户的开头 ky32localhost ky32 表示用户的主机名 localhost 新建的…

一文吃透低代码开发与传统IT开发的区别

目录 一、含义不同 二、开发门槛不同 三、两者之间的区别 1、从技术特征来看 2、从目标开发者来看 四、低代码平台使用感受&#xff1f; &#xff08;1&#xff09;自定义模块&#xff0c;满足不同的业务需求 &#xff08;2&#xff09;工作流引擎&#xff0c;简化复杂流程的管…

js判断数据类型的方式详解(面试题)

一.typeof 1.用来判断基本数据类型 null、Object、String判断的结果都为object 二.instanceof 检测构造函数的 prototype 属性是否在某个实例对象的原型链上 不能判断简单数据类型&#xff0c;只能判断复杂数据类型。 复杂数据类型的具体类型不一定判断正确。 手写instanceof…

[软件下载]解决copperliasim(原v-rep)的教育版无法下载的问题

前言 v-rep&#xff08;现在叫做copperliasim,但是v-rep字数比较少&#xff0c;并且叫的人也比较多&#xff0c;故下文皆称vrep&#xff09;是一款优秀的机器人仿真软件&#xff0c;在国内似乎用的人不多&#xff0c;但是国外据说还是比较流行的。 目前或许有不少的朋友在下载…

数的种类 -bitset的应用

很容易想到下面的DP dp&#xff08;i&#xff0c;j&#xff09; 考虑前i个数字看是否能构成j for(int i1;i<n;i)for(int j5e5;j>a[i];j)dp[j]|dp[j-a[i]]; 发现会超时 引入bitset优化 可以让原来的复杂度除以64 是一个经典的冲暴力的手段 #include<bits/stdc.h>…

matlibplot绘图设置标签角度

如下图所示&#xff0c;当我们绘图的时候有时候会遇到标注太长显示不全&#xff0c;这时候需要修改标注的角度来实现&#xff1a; **plt.xticks(rotation70)**设置x轴旋转70度 import matplotlib.pyplot as plt import numpy as np CHN[13.6081.06**i for i in range(1,31)] U…

百度AICA首席AI架构师培养计划第七期毕业,大模型深入产业见成果

10月28日&#xff0c;由深度学习技术及应用国家工程研究中心与百度联合创办的 AICA 首席AI架构师培养计划&#xff0c;迎来第7期毕业典礼&#xff0c;88位学员获得AI架构师认证。截至目前&#xff0c;AICA已累计为业界培养了410位产业AI领军人才。同时&#xff0c;AICA第7期毕业…

光环云出席国际数据经济产业合作大会,成为国际数据经济产业园首批生态合作企业

光环云作为临港新片区国际数据港全球云算服务生态合作伙伴受邀出席会议&#xff0c;与跨境数科等单位共同参与共建国际数据港启动仪式&#xff0c;光环云执行董事兼CEO吴曼以《AGI-x时代跨境数据流动》为主题作主旨演讲。 10月27日&#xff0c;国际数据经济产业合作大会在临港新…

史上最短苹果发布会;三星、LG、高通联手进军 XR 市场丨 RTE 开发者日报 Vol.74

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

CVE-2023-1698:WAGO系统远程代码执行漏洞复现

文章目录 WAGO系统远程代码执行漏洞(CVE-2023-1698)复现0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 WAGO系统远程代码执行漏洞(CVE-2023-1698)复现 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术…

六、W5100S/W5500+RP2040树莓派Pico<UDP Server数据回环测试>

文章目录 1. 前言2. 协议简介2.1 简述2.2 优点2.3 UDP Server的步骤2.4 应用 3. WIZnet以太网芯片4. UDP Sever回环测试4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 测试现象 5. 注意事项6. 相关链接 1. 前言 UDP是一种无连接的网络协议&#xff0c;它提供了一种简…

MS-NAS

方法 作者未提供代码

EtherCAT的4种寻址方式解析

我们知道&#xff0c;一个EtherCAT数据帧&#xff08;frame&#xff09;里面包含很多个报文&#xff08;datagram&#xff09;&#xff0c;不管是什么样式的报文&#xff0c;它们的目的只有一个&#xff0c;就是读写从站寄存器或内存。所以寻址就是以什么方式访问哪个从站的哪个…

剑指offer(C++)-JZ5:替换空格(算法-其他)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 请实现一个函数&#xff0c;将一个字符串s中的每个空格替换成“%20”。 例如&#xff0c;当字符串为We A…

Mybatis执行流程简析

一、前言 日常工作中&#xff0c;我们用到mybatis的时候&#xff0c;都是写一个Mapper接口xml文件/注解形式&#xff0c;然后就可以在业务层去调用我们在Mapper接口中定义的CRUD方法&#xff0c;很方便&#xff0c;但一直都没有去研究过执行逻辑&#xff0c;下面附一篇我自己研…

在NISQ小型计算机上执行大型并行量子计算的可能性

简介 Steve White提出了密度矩阵重整化群&#xff08;DMRG&#xff09;的基本思想&#xff0c;即纠缠是一种有价值的资源&#xff0c;可以用来精确或近似地描述大量子系统。后来&#xff0c;这一思想被理解为优化矩阵积状态&#xff08;MPS&#xff09;的算法&#xff0c;支持…

组件与Props:React中构建可复用UI的基石

目录 组件&#xff1a;构建现代UI的基本单位 Props&#xff1a;组件之间的数据传递 Props的灵活性&#xff1a;构建可配置的组件 组件间的通信&#xff1a;通过回调函数传递数据 总结&#xff1a; 组件&#xff1a;构建现代UI的基本单位 组件是前端开发中的关键概念之一。…

氮化镓功率HEMT的表征与建模

来源&#xff1a;Characterization and Modeling of a Gallium Nitride Power HEMT(IEEE TRANSACTIONS ON INDUSTRY APPLICATIONS) GaN high-electron-mobility transistor (HEMT) GaN高电子迁移率晶体管   该模型包括一个电压相关电流源Ids、两个电压相关电容Cgd和Cds、一…

UG\NX二次开发 球坐标到直角坐标的转换

文章作者:里海 来源网站:《里海NX二次开发3000例专栏》 感谢粉丝订阅 感谢 JiaLiHuiNaoGui 订阅本专栏,非常感谢。 简介 已知角度θ和ϕ,距离d,求P点坐标。 "> 代码 #include "me.hpp" using namespace NXOpen; using namespace std;void GetP<