gps/src/main/java/com/njzscloud/jt808/protocol/JT808Encoder.java

147 lines
4.2 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.njzscloud.jt808.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* JT808协议编码器
* 将JT808Message对象编码为符合协议规范的字节流
*/
public class JT808Encoder extends MessageToByteEncoder<JT808Message> {
// 消息起始符和结束符
private static final byte MSG_DELIMITER = 0x7e;
@Override
protected void encode(ChannelHandlerContext ctx, JT808Message msg, ByteBuf out) throws Exception {
// 1. 创建缓冲区存储消息内容(不含起始符和结束符)
ByteBuf contentBuf = ctx.alloc().buffer();
try {
// 2. 写入消息ID
contentBuf.writeShort(msg.getMessageId());
// 3. 写入消息体属性
contentBuf.writeShort(msg.getMessageBodyProps());
// 4. 写入终端手机号BCD编码
byte[] phoneBytes = stringToBcd(msg.getTerminalPhone(), 6);
contentBuf.writeBytes(phoneBytes);
// 5. 写入消息流水号
contentBuf.writeShort(msg.getFlowId());
// 6. 写入消息包封装项(如果需要)
if (msg.isPackaged() && msg.getPackageInfo() != null) {
contentBuf.writeShort(msg.getPackageInfo().getTotalPackages());
contentBuf.writeShort(msg.getPackageInfo().getCurrentPackageNo());
}
// 7. 写入消息体
byte[] messageBody = msg.getMessageBody();
if (messageBody != null && messageBody.length > 0) {
contentBuf.writeBytes(messageBody);
}
// 8. 计算并写入校验码
byte checkCode = calculateCheckCode(contentBuf);
contentBuf.writeByte(checkCode);
msg.setCheckCode(checkCode);
// 9. 处理转义
ByteBuf escapedBuf = handleEscape(contentBuf);
// 10. 写入起始符
out.writeByte(MSG_DELIMITER);
// 11. 写入转义后的内容
out.writeBytes(escapedBuf);
// 12. 写入结束符
out.writeByte(MSG_DELIMITER);
} finally {
// 释放缓冲区
if (contentBuf.refCnt() > 0) {
contentBuf.release();
}
}
}
/**
* 处理转义字符
*/
private ByteBuf handleEscape(ByteBuf buf) {
ByteBuf out = buf.alloc().buffer(buf.readableBytes() * 2); // 预留足够空间
buf.resetReaderIndex();
while (buf.readableBytes() > 0) {
byte b = buf.readByte();
if (b == MSG_DELIMITER) {
out.writeByte(0x7d);
out.writeByte(0x01);
} else if (b == 0x7d) {
out.writeByte(0x7d);
out.writeByte(0x02);
} else {
out.writeByte(b);
}
}
return out;
}
/**
* 计算校验码
* 校验码 = 消息头 + 消息体 中所有字节的异或
*/
private byte calculateCheckCode(ByteBuf buf) {
byte checkCode = 0;
int readerIndex = buf.readerIndex();
while (buf.readableBytes() > 0) {
checkCode ^= buf.readByte();
}
buf.readerIndex(readerIndex);
return checkCode;
}
/**
* 字符串转BCD码
*/
private byte[] stringToBcd(String str, int length) {
if (str == null || str.length() == 0) {
return new byte[length];
}
// 补0至偶数长度
int strLen = str.length();
if (strLen % 2 != 0) {
str = "0" + str;
}
// 确保不超过指定长度
if (str.length() > length * 2) {
str = str.substring(0, length * 2);
}
byte[] bcd = new byte[length];
int index = 0;
for (int i = 0; i < str.length(); i += 2) {
if (index >= length) {
break;
}
// 高4位
byte high = (byte) (Character.digit(str.charAt(i), 16) << 4);
// 低4位
byte low = (byte) Character.digit(str.charAt(i + 1), 16);
bcd[index++] = (byte) (high | low);
}
return bcd;
}
}