package com.genersoft.iot.vmp.jt1078.codec.encode;
|
|
import com.genersoft.iot.vmp.jt1078.annotation.MsgId;
|
import com.genersoft.iot.vmp.jt1078.proc.Header;
|
import com.genersoft.iot.vmp.jt1078.proc.entity.Cmd;
|
import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
|
import com.genersoft.iot.vmp.jt1078.session.Session;
|
import com.genersoft.iot.vmp.jt1078.util.Bin;
|
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.CompositeByteBuf;
|
import io.netty.buffer.Unpooled;
|
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.util.ByteProcessor;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.util.StringUtils;
|
|
import java.util.LinkedList;
|
|
/**
|
* @author QingtaiJiang
|
* @date 2023/4/27 18:25
|
* @email qingtaij@163.com
|
*/
|
public class Jt808EncoderCmd extends MessageToByteEncoder<Cmd> {
|
private final static Logger log = LoggerFactory.getLogger(Jt808EncoderCmd.class);
|
|
@Override
|
protected void encode(ChannelHandlerContext ctx, Cmd cmd, ByteBuf out) throws Exception {
|
Session session = ctx.channel().attr(Session.KEY).get();
|
Rs msg = cmd.getRs();
|
ByteBuf encode = encode(msg, session, cmd.getPackageNo().intValue());
|
if (encode != null) {
|
log.info("< {} hex:{}", session, ByteBufUtil.hexDump(encode));
|
out.writeBytes(encode);
|
}
|
}
|
|
|
public static ByteBuf encode(Rs msg, Session session, Integer packageNo) {
|
String id = msg.getClass().getAnnotation(MsgId.class).id();
|
if (!StringUtils.hasLength(id)) {
|
log.error("Not find msgId");
|
return null;
|
}
|
|
ByteBuf byteBuf = Unpooled.buffer();
|
|
byteBuf.writeBytes(ByteBufUtil.decodeHexDump(id));
|
|
ByteBuf encode = msg.encode();
|
|
Header header = msg.getHeader();
|
if (header == null) {
|
header = session.getHeader();
|
}
|
|
if (header.is2019Version()) {
|
// 消息体属性
|
byteBuf.writeShort(encode.readableBytes() | 1 << 14);
|
|
// 版本号
|
byteBuf.writeByte(header.getVersion());
|
|
// 终端手机号
|
byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 20)));
|
} else {
|
// 消息体属性
|
byteBuf.writeShort(encode.readableBytes());
|
|
byteBuf.writeBytes(ByteBufUtil.decodeHexDump(Bin.strHexPaddingLeft(header.getDevId(), 12)));
|
}
|
|
// 消息体流水号
|
byteBuf.writeShort(packageNo);
|
|
// 写入消息体
|
byteBuf.writeBytes(encode);
|
|
// 计算校验码,并反转义
|
byteBuf = escapeAndCheck0(byteBuf);
|
return byteBuf;
|
}
|
|
|
private static final ByteProcessor searcher = value -> !(value == 0x7d || value == 0x7e);
|
|
//转义与校验
|
public static ByteBuf escapeAndCheck0(ByteBuf source) {
|
|
sign(source);
|
|
int low = source.readerIndex();
|
int high = source.writerIndex();
|
|
LinkedList<ByteBuf> bufList = new LinkedList<>();
|
int mark, len;
|
while ((mark = source.forEachByte(low, high - low, searcher)) > 0) {
|
|
len = mark + 1 - low;
|
ByteBuf[] slice = slice(source, low, len);
|
bufList.add(slice[0]);
|
bufList.add(slice[1]);
|
low += len;
|
}
|
|
if (bufList.size() > 0) {
|
bufList.add(source.slice(low, high - low));
|
} else {
|
bufList.add(source);
|
}
|
|
ByteBuf delimiter = Unpooled.buffer(1, 1).writeByte(0x7e).retain();
|
bufList.addFirst(delimiter);
|
bufList.addLast(delimiter);
|
|
CompositeByteBuf byteBufLs = Unpooled.compositeBuffer(bufList.size());
|
byteBufLs.addComponents(true, bufList);
|
return byteBufLs;
|
}
|
|
public static void sign(ByteBuf buf) {
|
byte checkCode = bcc(buf);
|
buf.writeByte(checkCode);
|
}
|
|
public static byte bcc(ByteBuf byteBuf) {
|
byte cs = 0;
|
while (byteBuf.isReadable())
|
cs ^= byteBuf.readByte();
|
byteBuf.resetReaderIndex();
|
return cs;
|
}
|
|
protected static ByteBuf[] slice(ByteBuf byteBuf, int index, int length) {
|
byte first = byteBuf.getByte(index + length - 1);
|
|
ByteBuf[] byteBufList = new ByteBuf[2];
|
byteBufList[0] = byteBuf.retainedSlice(index, length);
|
|
if (first == 0x7d) {
|
byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x01);
|
} else {
|
byteBuf.setByte(index + length - 1, 0x7d);
|
byteBufList[1] = Unpooled.buffer(1, 1).writeByte(0x02);
|
}
|
return byteBufList;
|
}
|
}
|