文章目录
- 一、消息头 数据
- 1、消息头拼接
- 2、消息 ID 字段
- 3、消息体属性 字段
- 4、终端手机号 字段
- 5、终端流水号 字段
- 二、消息体 数据
- 三、校验码计算
- 四、最终计算结果
- 五、终端注册应答
- 1、分解终端应答数据
- 2、终端应答 消息体 数据
- 六、字符编码转换网站
一、消息头 数据
1、消息头拼接
808 协议的消息头结构如下 :
+----------+-------------+----------------+--------+------------+----------------+
| 消息ID | 消息体属性 | 终端手机号 | 流水号 | 总包数 | 包序号 |
| 2字节 | 2字节 | 6字节(BCD) | 2字节 | 2字节(可选)| 2字节(可选) |
+----------+-------------+----------------+--------+------------+----------------+
这是生成的 终端注册 消息头数据 :
消息头数据 :
01 00 00 36 01 85 11 88 88 88 00 01
参考 下图进行解析 :
2、消息 ID 字段
0 ~ 1 字节 是消息 ID , " 01 00 00 36 01 85 11 88 88 88 00 01 "
0x0100 是 终端注册的 消息 ID ;
3、消息体属性 字段
2 ~ 3 字节 是消息体属性 , " 01 00 00 36 01 85 11 88 88 88 00 01 " , 也就是 00 36
,
将其拆解成二进制形式 为
0000 0000 0011 0110
参考下面的 位数 进行对应 ,
保留位 是 00
, 分包位 是 0
, 数据加密方式是 000
,
消息体长度是 00 0011 0110
, 对应的十六进制为 0x36 , 十进制为 54 , 消息体长度 54 字节 ;
4、终端手机号 字段
4 ~ 9 字节 是 终端手机号 , " 01 00 00 36 01 85 11 88 88 88 00 01 " , 也就是 18511888888
十一位手机号 , 前面加上一个 0 ;
这是 BCD 编码 , 每个字节 高四位 表示一个数字 , 第四位表示一个数字 ;
使用 如下代码 , 可以实现 BCD 编码 到 数字字符串 之间的转换 ;
/**
* 读入数据时通过按位与操作将bcd编码转换成设备编号devId
*
* @param bcd
* @return
*/
public static String bcdToString(byte[] bcd) {
// 存储转码后的字符串
StringBuilder sb = new StringBuilder();
// 循环数组解码 先将每个位上的
for (int i = 0; i < bcd.length; i++) {
// 转换低字节 十六进制的 0x0f 等于十进制的 15,二进制表示为00001111,直接取到低4位
int low = (bcd[i] & 0x0f);
// 转换高字节 十六进制的 0xf0 等于十进制的 240,二进制表示为11110000,右移4位的意思是取高4位
int high = ((bcd[i] & 0xf0) >> 4);
// 如果高字节等于0xf(二进制1111)说明是补的字节,直接抛掉
if (high != 0xf) {
sb.append(high);
}
sb.append(low);
}
// 返回解码字符串
return sb.toString();
}
/**
* 写出数据时将我们业务中的devId转换成bcd编码
*
* @param bcd
* @return
*/
public static byte[] strToBcd(String bcd) {
// 获取字节数组长度
int size = bcd.length() / 2;
int remainder = bcd.length() % 2;
// 存储BCD码字节
byte[] bcdByte = new byte[size + remainder];
// 转BCD码
for (int i = 0; i < size; i++) {
int high = Integer.parseInt(bcd.substring(2 * i, 2 * i + 1));
int low = Integer.parseInt(bcd.substring(2 * i + 1, 2 * i + 2));
bcdByte[i] = (byte) ((high << 4) | low);
}
// 如果存在余数,需要填F
if (remainder > 0) {
int low = Integer.parseInt(bcd.substring(bcd.length() - 1));
bcdByte[bcdByte.length - 1] = (byte) ((0xf << 4) | low);
}
// 返回BCD码字节数组
return bcdByte;
}
5、终端流水号 字段
10 ~ 11 字节 是 终端流水号 , " 00 00 00 36 01 85 11 88 88 88 00 01 " ,
终端流水号 , 每次发送数据后 , 自增 1 ;
二、消息体 数据
终端注册 消息体 数据如下 :
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 ....BYD..2......
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0048 - 0063: 00 00 00 00 00 00 ......
参考下图进行解析 :
-
0 ~ 1 字节 : 是 省域 ID , short 双字节整型 , 下面 蓝色部分是 省域 ID 数据 ;
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0048 - 0063: 00 00 00 00 00 00 … -
2 ~ 3 字节 : 市县域 ID , short 整型 , 下面蓝色部分对应数据 ;
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0048 - 0063: 00 00 00 00 00 00 -
4 ~ 8 字节 : 5 字节数据 , 制造商编码 , 下面蓝色部分是 " BYD " 字符串对应的 ASCII 码 , 后面是 两个 0 ;
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0048 - 0063: 00 00 00 00 00 00 -
9 ~ 28 字节 : 20 字节的数据 , 终端型号 , 字符 2 对应的 ASCII 码 ; 下面蓝色字体部分 ;
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0048 - 0063: 00 00 00 00 00 00 -
29 ~ 35 字节 : 7 字节的 二进制数据 , 这里设置的是 0 ;
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0048 - 0063: 00 00 00 00 00 00 -
36 ~ 36 字节 : 1 字节的 二进制数据 , 颜色代码 ;
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0048 - 0063: 00 00 00 00 00 00 -
37 ~ 53 字节 : 17 字节的 二进制数据 , VIN 码 , 车架号 , 这里设置默认 0 ;
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 …BYD…2…
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 …
0048 - 0063: 00 00 00 00 00 00
三、校验码计算
终端注册
- 消息头 :
0000 - 0015: 01 00 00 36 01 85 11 88 88 88 00 01
- 消息体 :
0000 - 0015: 00 00 00 00 42 59 44 00 00 32 00 00 00 00 00 00 ....BYD..2......
0016 - 0031: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0048 - 0063: 00 00 00 00 00 00 ...... ....~
- 校验位 :
0000 - 0015: E4
将 消息头 + 消息体 两个字节数组 合并后 进行校验 , 使用如下函数 从第一字节开始 进行校验 直到最后一位 ,
/**
* 校验位 校验码指从消息头开始,同后一字节异或,直到校验码前一个字节,占用一个字节。
*
* @return
*/
public static byte crc(ByteBuf byteBuf) {
ByteBuf buf = byteBuf.copy();
byte checksum = 0;
while (buf.readableBytes() > 0) {
checksum ^= buf.readUnsignedByte();
}
return checksum;
}
四、最终计算结果
将上述 消息头 + 消息体 + 校验位 拼装起来 ,
查看 数据中是否有 0x7e 和 0x7d , 进行转义替换 ;
出现 0x7e 的转义处理 : 0x7e <————> 0x7d 后紧跟一个 0x02;
出现 0x7d 的转义处理 : 0x7d <————> 0x7d 后紧跟一个 0x01。
最终的 终端注册数据包为 :
0000 - 0015: 7E 01 00 00 36 01 85 11 88 88 88 00 01 00 00 00 ~...6.6.........
0016 - 0031: 00 42 59 44 00 00 32 00 00 00 00 00 00 00 00 00 .BYD..2.........
0032 - 0047: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0048 - 0063: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0064 - 0079: 00 00 00 E4 7E ....~
五、终端注册应答
返回 终端注册应答 数据 :
0000 - 0015: 7E 81 00 00 10 01 36 00 10 10 89 00 02 00 01 00 ~.....6.........
0016 - 0031: BB CE CE D6 88 E2 47 AC BB 21 30 CE 39 48 7E ..........089H~
1、分解终端应答数据
前后的 0x7E 是 标识位 ;
倒数第二位 0x48
是 校验位 ;
消息头的结构 :
+----------+-------------+----------------+--------+------------+----------------+
| 消息ID | 消息体属性 | 终端手机号 | 流水号 | 总包数 | 包序号 |
| 2字节 | 2字节 | 6字节(BCD) | 2字节 | 2字节(可选)| 2字节(可选) |
+----------+-------------+----------------+--------+------------+----------------+
消息头提取出来 :
81 00 00 10 01 36 00 10 10 89 00 02
消息体数据提取出来 :
00 01 00 BB CE CE D6 88 E2 47 AC BB 21 30 CE 39 48 7E
参考下图进行解析 ;
2、终端应答 消息体 数据
消息体数据 :
00 01 00 BB CE CE D6 88 E2 47 AC BB 21 30 CE 39 48 7E
00 01
是 应答 流水号 ;00
表示 终端注册 成功 ;BB CE CE D6 88 E2 47 AC BB 21 30 CE 39
是 鉴权码 字符串对应的 二进制数据 ;
六、字符编码转换网站
字符编码转换网站 :
- GBK 编码转换
- UTF-8 编码转换
- URL 编码转换