18045010223
2025-07-07 0d3a683a0c97154b1f2e6657398664537e4e3e82
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package org.yzh.protocol.basics;
 
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.github.yezhihao.netmc.core.model.Message;
import io.github.yezhihao.netmc.session.Session;
import io.github.yezhihao.protostar.annotation.Field;
import io.github.yezhihao.protostar.util.ToStringBuilder;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.yzh.protocol.commons.MessageId;
 
/**
 * @author yezhihao
 * https://gitee.com/yezhihao/jt808-server
 */
@ToString
@Data
@Accessors(chain = true)
public class JTMessage implements Message {
 
    @Field(length = 2, desc = "消息ID")
    protected int messageId;
    @Field(length = 2, desc = "消息体属性")
    protected int properties;
    @Field(length = 1, desc = "协议版本号", version = 1)
    protected int protocolVersion;
    @Field(length = 6, charset = "BCD", desc = "终端手机号", version = {-1, 0})
    @Field(length = 10, charset = "BCD", desc = "终端手机号", version = 1)
    protected String clientId;
    @Field(length = 2, desc = "流水号")
    protected int serialNo;
    @Field(length = 2, desc = "消息包总数")
    protected Integer packageTotal;
    @Field(length = 2, desc = "包序号")
    protected Integer packageNo;
    /** bcc校验 */
    protected boolean verified = true;
 
    @JsonIgnore
    protected transient Session session;
    @JsonIgnore
    protected transient ByteBuf payload;
    @JsonIgnore
    protected transient Object extData;
    @JsonIgnore
    protected transient int vehicleId;
    @JsonIgnore
    protected transient int driverId;
 
    public JTMessage copyBy(JTMessage that) {
        this.setClientId(that.getClientId());
        this.setProtocolVersion(that.getProtocolVersion());
        this.setVersion(that.isVersion());
        return this;
    }
 
    public Integer getPackageTotal() {
        if (isSubpackage())
            return packageTotal;
        return null;
    }
 
    public Integer getPackageNo() {
        if (isSubpackage())
            return packageNo;
        return null;
    }
 
    public <T> T getExtData() {
        return (T) extData;
    }
 
    public int reflectMessageId() {
        if (messageId != 0)
            return messageId;
        return reflectMessageId(this.getClass());
    }
 
    public static int reflectMessageId(Class<?> clazz) {
        io.github.yezhihao.protostar.annotation.Message messageType = clazz.getAnnotation(io.github.yezhihao.protostar.annotation.Message.class);
        if (messageType != null && messageType.value().length > 0)
            return messageType.value()[0];
        return 0;
    }
 
    public boolean noBuffer() {
        return true;
    }
 
    private static final int BODY_LENGTH = 0b0000_0011_1111_1111;
    private static final int ENCRYPTION = 0b0001_1100_0000_0000;
    private static final int SUBPACKAGE = 0b0010_0000_0000_0000;
    private static final int VERSION = 0b0100_0000_0000_0000;
    private static final int RESERVED = 0b1000_0000_0000_0000;
 
    /** 消息体长度 */
    public int getBodyLength() {
        return this.properties & BODY_LENGTH;
    }
 
    public void setBodyLength(int bodyLength) {
        this.properties = (properties & ~BODY_LENGTH) | (bodyLength & BODY_LENGTH);
    }
 
    /** 加密方式 */
    public int getEncryption() {
        return (properties & ENCRYPTION) >> 10;
    }
 
    public void setEncryption(int encryption) {
        this.properties = (properties & ~ENCRYPTION) | (encryption & ENCRYPTION);
    }
 
    /** 是否分包 */
    public boolean isSubpackage() {
        return (properties & SUBPACKAGE) == SUBPACKAGE;
    }
 
    public void setSubpackage(boolean subpackage) {
        if (subpackage)
            this.properties |= SUBPACKAGE;
        else
            this.properties &= ~SUBPACKAGE;
    }
 
    /** 是否有版本 */
    public boolean isVersion() {
        return (properties & VERSION) == VERSION;
    }
 
    public void setVersion(boolean version) {
        if (version)
            this.properties |= VERSION;
        else
            this.properties &= ~VERSION;
    }
 
    /** 保留位 */
    public boolean isReserved() {
        return (properties & RESERVED) == RESERVED;
    }
 
    public void setReserved(boolean reserved) {
        if (reserved)
            this.properties |= RESERVED;
        else
            this.properties &= ~RESERVED;
    }
 
    protected StringBuilder toStringHead() {
        final StringBuilder sb = new StringBuilder(768);
        sb.append(MessageId.getName(messageId));
        sb.append('[');
        sb.append("cid=").append(clientId);
        sb.append(",msgId=").append(messageId);
        sb.append(",version=").append(protocolVersion);
        sb.append(",serialNo=").append(serialNo);
        sb.append(",props=").append(properties);
        sb.append(",verified=").append(verified);
        if (isSubpackage()) {
            sb.append(",pt=").append(packageTotal);
            sb.append(",pn=").append(packageNo);
        }
        sb.append(']');
        sb.append(',');
        return sb;
    }
 
    @Override
    public String toString() {
        String result = ToStringBuilder.toString(toStringHead(), this, false, "messageId", "clientId", "protocolVersion", "serialNo", "properties", "packageTotal", "packageNo");
        return result;
    }
}