Jt808应答举例

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> {@Overrideprotected void encode(ChannelHandlerContext ctx, Jt808Message msg, ByteBuf out) throws Exception {ByteBuf msgBody = msg.getMsgBody();int msgBodyLen = msgBody == null ? 0 : msgBody.readableBytes();//Protocol TypeProtocolEnum protocolType = msg.getProtocolType();//the length of remove the tip and tailint 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 bytesif (msg.isMultiPacket()) {contentLen = contentLen + 4;}ByteBuf bodyBuf = ByteBufAllocator.DEFAULT.heapBuffer(contentLen);try {//message idbodyBuf.writeShort(msg.getMsgId());//The length of the message body in the message body propertyint msgBodyAttr = msgBodyLen | (msg.getEncryptType() << 10);//The subcontract identity in the message body propertyif (msg.isMultiPacket()) {msgBodyAttr = msgBodyAttr | 0b00100000_00000000;}//The Jt808-2019 version adds the version identifier and protocol version numberif (protocolType == ProtocolEnum.JT808_2019) {//Version identificationmsgBodyAttr = msgBodyAttr | 0b01000000_00000000;//message body propertybodyBuf.writeShort(msgBodyAttr);//Protocol version NumberbodyBuf.writeByte(msg.getProtocolVersion());} else {//message body propertiesbodyBuf.writeShort(msgBodyAttr);}//terminal numberbodyBuf.writeBytes(msg.getPhoneNumberArr());//Message serial numberbodyBuf.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 bodyif (msgBodyLen > 0) {bodyBuf.writeBytes(msgBody);}//check codeint checkCode = CommonUtil.xor(bodyBuf);bodyBuf.writeByte(checkCode);//message headerout.writeByte(Jt808Constant.MSG_HEAD_TAIL_FLAG);//The read index is reset to the starting positionbodyBuf.readerIndex(0);//escapeJt808PacketUtil.escape(out, bodyBuf);//message tailout.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 bodyif (msgBody != null) {ReferenceCountUtil.release(msgBody);}//release bodyBufReferenceCountUtil.release(bodyBuf);}}
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SkyWalking官方文档-1-概述

概述 SkyWalking是一个开源的可观测平台&#xff0c;用于收集&#xff0c;分析&#xff0c;聚合&#xff0c;以及可视化处理来自服务和云原生框架的数据。SkyWalking提供了一种简单的方法来维护分布式系统的清晰视图&#xff0c;即使是跨云。 它是一种现代APM&#xff0c;专门…

电子学会C/C++编程等级考试2023年05月(五级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:问题求解 给定一个正整数N,求最小的M满足比N大且M与N的二进制表示中有相同数目的1。 举个例子,假如给定N为78,二进制表示为1001110,包含4个1,那么最小的比N大的并且二进制表示中只包含4个1的数是83,其二进制是1010011,因…

虚拟机Ubuntu下运行vue-element-admin项目

一.环境搭建 1.安装nodejs sudo apt install nodejs 安装完成后&#xff0c;查看对应的版本号 nodejs -v没有问题&#xff0c;会输出对应版本号&#xff0c;我这里是10.19.0 v10.19.0 2.安装npm sudo apt install npm安装完成查看对应的版本号&#xff0c;确认OK npm -…

企业知识库知识分类太有必要了,是省时省力的关键!

企业知识库是存储、组织和共享企业内部知识的重要工具。在现代企业中&#xff0c;知识是一项宝贵的资产&#xff0c;对于提高企业的竞争力和创新能力至关重要。而通过企业知识库进行知识分类&#xff0c;可以将海量信息有序划分和组织&#xff0c;让企业员工能够快速定位、理解…

SpringSecurity 认证实战

一. 项目数据准备 1.1 添加依赖 <dependencies><!--spring security--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!--web起步依赖-…

Linux学习第25天:Linux 阻塞和非阻塞 IO 实验(二): 挂起

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 为方便和上一节的衔接&#xff0c;在正式开始学习前&#xff0c;先把本节的思维导图引入&#xff1a; 二、阻塞IO实验 1.硬件原理图分析 2.实验程序 #define I…

rqt-robot-steering控制面板

目录 安装rqt-robot-steering控制面板&#xff08;已安装则跳过&#xff09;新建一个终端&#xff0c;先启动ros系统再新建一个终端&#xff0c;运行rqt-robot-steering再打开一个终端&#xff0c;验证使用控制面板控制小乌龟移动 安装rqt-robot-steering控制面板&#xff08;已…

多模态对比语言图像预训练CLIP:打破语言与视觉的界限

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

CSS3盒模型

CSS3盒模型规定了网页元素的显示方式&#xff0c;包括大小、边框、边界和补白等概念。2015年4月&#xff0c;W3C的CSS工作组发布了CSS3基本用户接口模块&#xff0c;该模块负责控制与用户接口界面相关效果的呈现方式。 1、盒模型基础 在网页设计中&#xff0c;经常会听到内容…

Android底层摸索改BUG(二):Android系统移除预置APP

首先我先提供以下博主博文&#xff0c;对相关知识点可以提供理解、解决、思考的 Android 系统如何预装第三方应用以及常见问题汇集android Android.mk属性说明及预置系统app操作说明系Android 中去除系统原生apk的方法 取消预置APK方法一&#xff1a; 其实就是上面的链接3&a…

qt-C++笔记之在两个标签页中按行读取两个不同的文件并且滚动条自适应滚动范围高度

qt-C笔记之在两个标签页中按行读取两个不同的文件并且滚动条自适应滚动范围高度 code review! 文章目录 qt-C笔记之在两个标签页中按行读取两个不同的文件并且滚动条自适应滚动范围高度1.运行2.文件结构3.main.cc4.main.pro5.a.txt6.b.txt7.上述代码中QVBoxLayout&#xff0c…