byte[10-11] 消息流水号 word(16)
按发送顺序从 0 开始循环累加
byte[12-15] 消息包封装项
byte[0-1] 消息包总数(word(16))
该消息分包后得总包数
byte[2-3] 包序号(word(16))
从 1 开始
如果消息体属性中相关标识位确定消息分包处理,则该项有内容
否则无该项
2 解析
整个消息体结构中最复杂的就是消息头了。
2.1 消息体实体类
以下是对整个消息体抽象出来的一个java实体类。
import java.nio.channels.Channel;
public class PackageData {
/**
* 16byte 消息头
*/
protected MsgHeader msgHeader;
// 消息体字节数组
protected byte[] msgBodyBytes;
/**
* 校验码 1byte
*/
protected int checkSum;
//记录每个客户端的channel,以便下发信息给客户端
protected Channel channel;
public MsgHeader getMsgHeader() {
return msgHeader;
}
//TODO set 和 get 方法在此处省略
//消息头
public static class MsgHeader {
// 消息ID
protected int msgId;
/////// ========消息体属性
// byte[2-3]
protected int msgBodyPropsField;
// 消息体长度
protected int msgBodyLength;
// 数据加密方式
protected int encryptionType;
// 是否分包,true==>有消息包封装项
protected boolean hasSubPackage;
// 保留位[14-15]
protected String reservedBit;
/////// ========消息体属性
// 终端手机号
protected String terminalPhone;
// 流水号
protected int flowId;
//////// =====消息包封装项
// byte[12-15]
protected int packageInfoField;
// 消息包总数(word(16))
protected long totalSubPackage;
// 包序号(word(16))这次发送的这个消息包是分包中的第几个消息包, 从 1 开始
protected long subPackageSeq;
//////// =====消息包封装项
//TODO set 和 get 方法在此处省略
}
}
2.2 字节数组到消息体实体类的转换
2.2.1 消息转换器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.hylexus.jt808.util.BCD8421Operater;
import cn.hylexus.jt808.util.BitOperator;
import cn.hylexus.jt808.vo.PackageData;
import cn.hylexus.jt808.vo.PackageData.MsgHeader;
public class MsgDecoder {
private static final Logger log = LoggerFactory.getLogger(MsgDecoder.class);
private BitOperator bitOperator;
private BCD8421Operater bcd8421Operater;
public MsgDecoder() {
this.bitOperator = new BitOperator();
this.bcd8421Operater = new BCD8421Operater();
}
//字节数组到消息体实体类
public PackageData queueElement2PackageData(byte[] data) {
PackageData ret = new PackageData();
// 1. 16byte 或 12byte 消息头
MsgHeader msgHeader = this.parseMsgHeaderFromBytes(data);
ret.setMsgHeader(msgHeader);
int msgBodyByteStartIndex = 12;
// 2. 消息体
// 有子包信息,消息体起始字节后移四个字节:消息包总数(word(16))+包序号(word(16))
if (msgHeader.isHasSubPackage()) {
msgBodyByteStartIndex = 16;
}
byte[] tmp = new byte[msgHeader.getMsgBodyLength()];
System.arraycopy(data, msgBodyByteStartIndex, tmp, 0, tmp.length);
ret.setMsgBodyBytes(tmp);
// 3. 去掉分隔符之后,最后一位就是校验码
// int checkSumInPkg =
// this.bitOperator.oneByteToInteger(data[data.length - 1]);
int checkSumInPkg = data[data.length - 1];
int calculatedCheckSum = this.bitOperator.getCheckSum4JT808(data, 0, data.length - 1);
ret.setCheckSum(checkSumInPkg);
if (checkSumInPkg != calculatedCheckSum) {
log.warn("检验码不一致,msgid:{},pkg:{},calculated:{}", msgHeader.getMsgId(), checkSumInPkg, calculatedCheckSum);
}
return ret;
}
private MsgHeader parseMsgHeaderFromBytes(byte[] data) {
MsgHeader msgHeader = new MsgHeader();
// 1. 消息ID word(16)
// byte[] tmp = new byte[2];
// System.arraycopy(data, 0, tmp, 0, 2);
// msgHeader.setMsgId(this.bitOperator.twoBytesToInteger(tmp));
msgHeader.setMsgId(this.parseIntFromBytes(data, 0, 2));
// 2. 消息体属性 word(16)=================>
// System.arraycopy(data, 2, tmp, 0, 2);
// int msgBodyProps = this.bitOperator.twoBytesToInteger(tmp);
int msgBodyProps = this.parseIntFromBytes(data, 2, 2);
msgHeader.setMsgBodyPropsField(msgBodyProps);
// [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度)
msgHeader.setMsgBodyLength(msgBodyProps & 0x1ff);
// [10-12] 0001,1100,0000,0000(1C00)(加密类型)
msgHeader.setEncryptionType((msgBodyProps & 0xe00) >> 10);
// [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包)
msgHeader.setHasSubPackage(((msgBodyProps & 0x2000) >> 13) == 1);
// [14-15] 1100,0000,0000,0000(C000)(保留位)
msgHeader.setReservedBit(((msgBodyProps & 0xc000) >> 14) + "");
// 消息体属性 word(16)<=================
// 3. 终端手机号 bcd[6]
// tmp = new byte[6];
// System.arraycopy(data, 4, tmp, 0, 6);
// msgHeader.setTerminalPhone(this.bcd8421Operater.bcd2String(tmp));
msgHeader.setTerminalPhone(this.parseBcdStringFromBytes(data, 4, 6));
// 4. 消息流水号 word(16) 按发送顺序从 0 开始循环累加
// tmp = new byte[2];
// System.arraycopy(data, 10, tmp, 0, 2);
// msgHeader.setFlowId(this.bitOperator.twoBytesToInteger(tmp));
msgHeader.setFlowId(this.parseIntFromBytes(data, 10, 2));
// 5. 消息包封装项
// 有子包信息
if (msgHeader.isHasSubPackage()) {
// 消息包封装项字段
msgHeader.setPackageInfoField(this.parseIntFromBytes(data, 12, 4));
// byte[0-1] 消息包总数(word(16))
// tmp = new byte[2];
// System.arraycopy(data, 12, tmp, 0, 2);
// msgHeader.setTotalSubPackage(this.bitOperator.twoBytesToInteger(tmp));
msgHeader.setTotalSubPackage(this.parseIntFromBytes(data, 12, 2));
// byte[2-3] 包序号(word(16)) 从 1 开始
// tmp = new byte[2];
// System.arraycopy(data, 14, tmp, 0, 2);
// msgHeader.setSubPackageSeq(this.bitOperator.twoBytesToInteger(tmp));
msgHeader.setSubPackageSeq(this.parseIntFromBytes(data, 12, 2));
}
return msgHeader;
}
protected String parseStringFromBytes(byte[] data, int startIndex, int lenth) {
return this.parseStringFromBytes(data, startIndex, lenth, null);
}
private String parseStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) {
try {
byte[] tmp = new byte[lenth];
System.arraycopy(data, startIndex, tmp, 0, lenth);
return new String(tmp, "UTF-8");
} catch (Exception e) {
log.error("解析字符串出错:{}", e.getMessage());
e.printStackTrace();
return defaultVal;
}
}
private String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth) {
return this.parseBcdStringFromBytes(data, startIndex, lenth, null);
}
private String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) {
try {
byte[] tmp = new byte[lenth];
System.arraycopy(data, startIndex, tmp, 0, lenth);
return this.bcd8421Operater.bcd2String(tmp);
} catch (Exception e) {
log.error("解析BCD(8421码)出错:{}", e.getMessage());
e.printStackTrace();
return defaultVal;
}
}
private int parseIntFromBytes(byte[] data, int startIndex, int length) {
return this.parseIntFromBytes(data, startIndex, length, 0);
}
private int parseIntFromBytes(byte[] data, int startIndex, int length, int defaultVal) {
try {
// 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃
final int len = length > 4 ? 4 : length;
byte[] tmp = new byte[len];
System.arraycopy(data, startIndex, tmp, 0, len);
return bitOperator.byteToInteger(tmp);
} catch (Exception e) {
log.error("解析整数出错:{}", e.getMessage());
e.printStackTrace();
return defaultVal;
}
}
}










