Protocol.java
4.27 KB
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
177
178
package com.sunvote.protocal;
import com.sunvote.cmd.BaseCmd;
import com.sunvote.cmd.ICmd;
import com.sunvote.utils.ConvertUtils;
import com.sunvote.utils.Crc16;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Created by Elvis on 2017/8/8.
* Email:Eluis@psunsky.com
* Description:
* 1.1数据包的格式
* F5 AA AA LEN 有效数据 CRC1 CRC2
* 协议头自动安装和自动拆卸
*/
public class Protocol<C extends ICmd> implements IProtocal {
public final static byte[] HEADER = new byte[]{(byte) 0xF5, (byte) 0xAA, (byte) 0xAA};
/**
* F5 AA AA
*/
protected byte[] header = HEADER;
/**
* 消息体长度
*/
protected byte length;
/**
* 消息体内容
* !! 不能超过126个字节
*/
protected byte[] messageBody;
/**
* crc校验码
*/
protected byte[] crcs = new byte[]{0x00, 0x00};
public void setHeader(byte[] header) {
this.header = header;
}
public void setCrcs(byte[] crcs) {
this.crcs = crcs;
}
public void setCmd(C cmd) {
this.cmd = cmd;
}
public C getCmd() {
if (cmd == null) {
if (messageBody != null) {
cmd = (C) BaseCmd.parse(messageBody, messageBody.length);
}
}
return cmd;
}
private boolean enableMatchCode = false;
public void setEnableMatchCode(boolean enableMatchCode) {
this.enableMatchCode = enableMatchCode;
}
private byte[] matchCode = new byte[]{0x00, 0x00, 0x00, 0x00};
private byte[] getMessageBody() {
messageBody = cmd.toBytes();
return messageBody;
}
private byte getLength() {
length = 0;
length += getMessageBody().length;
length += 2;
return length;
}
private C cmd;
/**
* 由协议转化成字节码,可以直接用来发送
*
* @return
*/
public byte[] toBytes() {
length = getLength();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
// 头信息
// 包头
byteArrayOutputStream.write(header);
//长度
byteArrayOutputStream.write(length);
if (enableMatchCode) {
byteArrayOutputStream.write(matchCode);
}
//内容
byteArrayOutputStream.write(getMessageBody());
byte[] res = byteArrayOutputStream.toByteArray();
//CRC校验码
roundCrc(res);
byteArrayOutputStream.write(crcs);
} catch (IOException e) {
e.printStackTrace();
}
return byteArrayOutputStream.toByteArray();
}
/**
* 自动补充协议里面的CRC值
*
* @param data
*/
public void roundCrc(byte[] data) {
int crcValue = Crc16.getUnsignedShort(Crc16.crc16(data, data.length - 4));
crcs[0] = (byte) (crcValue >> 8);
crcs[1] = (byte) (crcValue);
}
/**
* 检查外来数据包的头是否正确
*
* @param datas
* @return
*/
public static boolean checkHeader(byte[] datas) {
if (datas != null && datas.length >= 3) {
return datas[0] == HEADER[0] && datas[1] == HEADER[1] && datas[2] == HEADER[2];
}
return false;
}
/**
* @param datas 数据
* @return
*/
public static boolean checkCRC(byte[] datas) {
if (datas.length > 6) {
return Crc16.crc16Check(datas);
}
return false;
}
/**
* 解析协议里面的数据长度
*
* @param datas
* @return
*/
public static int parseLength(byte[] datas) {
if (datas != null && datas.length >= 4) {
return datas[3] & 0xFF;
}
return 0;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("header:").append(ConvertUtils.bytes2HexString(header)).append("\n");
// stringBuilder.append("length:").append(ConvertUtils.bytes2HexString(new byte[]{getLength()})).append("\n");
stringBuilder.append("message:").append(ConvertUtils.bytes2HexString(getMessageBody())).append("\n");
return stringBuilder.toString();
}
}