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 { 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 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; } }