QingObject
2023-04-28 97b673d6ad6c2266a6e26eddf38dae23c00bb855
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package com.genersoft.iot.vmp.jt1078.codec.encode;
 
import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
import com.genersoft.iot.vmp.jt1078.proc.Header;
import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd;
import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
import com.genersoft.iot.vmp.jt1078.session.Session;
import com.genersoft.iot.vmp.jt1078.util.Bin;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.ByteProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
 
import java.util.LinkedList;
 
/**
 * @author QingtaiJiang
 * @date 2023/4/27 18:25
 * @email qingtaij@163.com
 */
public class Jt808EncoderCmd extends MessageToByteEncoder<Cmd> {
    private final static Logger log = LoggerFactory.getLogger(Jt808EncoderCmd.class);
 
    @Override
    protected void encode(ChannelHandlerContext ctx, Cmd cmd, ByteBuf out) throws Exception {
        Session session = ctx.channel().attr(Session.KEY).get();
        Rs msg = cmd.getRs();
        ByteBuf encode = encode(msg, session, cmd.getPackageNo().intValue());
        if (encode != null) {
            log.info("< {} hex:{}", session, ByteBufUtil.hexDump(encode));
            out.writeBytes(encode);
        }
    }
 
 
    public static ByteBuf encode(Rs msg, Session session, Integer packageNo) {
        String id = msg.getClass().getAnnotation(MsgId.class).id();
        if (!StringUtils.hasLength(id)) {
            log.error("Not find msgId");
            return null;
        }
 
        ByteBuf byteBuf = Unpooled.buffer();
 
        byteBuf.writeBytes(ByteBufUtil.decodeHexDump(id));
 
        ByteBuf encode = msg.encode();
 
        Header header = msg.getHeader();
        if (header == null) {
            header = session.getHeader();
        }
 
        if (header.is2019Version()) {
            // 消息体属性
            byteBuf.writeShort(encode.readableBytes() | 1 << 14);
 
            // 版本号
            byteBuf.writeByte(header.getVersion());
 
            // 终端手机号
            byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 20)));
        } else {
            // 消息体属性
            byteBuf.writeShort(encode.readableBytes());
 
            byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 12)));
        }
 
        // 消息体流水号
        byteBuf.writeShort(packageNo);
 
        // 写入消息体
        byteBuf.writeBytes(encode);
 
        // 计算校验码,并反转义
        byteBuf = escapeAndCheck0(byteBuf);
        return byteBuf;
    }
 
 
    private static final ByteProcessor searcher = value -> !(value == 0x7d || value == 0x7e);
 
    //转义与校验
    public static ByteBuf escapeAndCheck0(ByteBuf source) {
 
        sign(source);
 
        int low = source.readerIndex();
        int high = source.writerIndex();
 
        LinkedList<ByteBuf> bufList = new LinkedList<>();
        int mark, len;
        while ((mark = source.forEachByte(low, high - low, searcher)) > 0) {
 
            len = mark + 1 - low;
            ByteBuf[] slice = slice(source, low, len);
            bufList.add(slice[0]);
            bufList.add(slice[1]);
            low += len;
        }
 
        if (bufList.size() > 0) {
            bufList.add(source.slice(low, high - low));
        } else {
            bufList.add(source);
        }
 
        ByteBuf delimiter = Unpooled.buffer(1, 1).writeByte(0x7e).retain();
        bufList.addFirst(delimiter);
        bufList.addLast(delimiter);
 
        CompositeByteBuf byteBufLs = Unpooled.compositeBuffer(bufList.size());
        byteBufLs.addComponents(true, bufList);
        return byteBufLs;
    }
 
    public static void sign(ByteBuf buf) {
        byte checkCode = bcc(buf);
        buf.writeByte(checkCode);
    }
 
    public static byte bcc(ByteBuf byteBuf) {
        byte cs = 0;
        while (byteBuf.isReadable())
            cs ^= byteBuf.readByte();
        byteBuf.resetReaderIndex();
        return cs;
    }
 
    protected static ByteBuf[] slice(ByteBuf byteBuf, int index, int length) {
        byte first = byteBuf.getByte(index + length - 1);
 
        ByteBuf[] byteBufList = new ByteBuf[2];
        byteBufList[0] = byteBuf.retainedSlice(index, length);
 
        if (first == 0x7d) {
            byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x01);
        } else {
            byteBuf.setByte(index + length - 1, 0x7d);
            byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x02);
        }
        return byteBufList;
    }
}