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.最后组成完整的包,并将指令下发给设备

/**
 * 

Description: JT808 message entity encoder

* * @author Mr.Li * @date 2022-10-20 */ @Slf4j public class Jt808ProtocolEncoder extends MessageToByteEncoder { @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); } } }

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

Jt808应答举例_第1张图片

你可能感兴趣的:(物联网,IOT套件笔记,Java,服务器,网络,jt808)