content: package com.genersoft.iot.vmp.jt1078.codec.decode;
  
  import com.genersoft.iot.vmp.jt1078.proc.Header;
  import com.genersoft.iot.vmp.jt1078.proc.factory.CodecFactory;
  import com.genersoft.iot.vmp.jt1078.proc.request.Re;
  import com.genersoft.iot.vmp.jt1078.proc.response.Rs;
  import com.genersoft.iot.vmp.jt1078.service.Ijt1078Service;
  import com.genersoft.iot.vmp.jt1078.session.Session;
  import io.netty.buffer.ByteBuf;
  import io.netty.buffer.ByteBufUtil;
  import io.netty.buffer.CompositeByteBuf;
  import io.netty.buffer.UnpooledByteBufAllocator;
  import io.netty.channel.ChannelHandlerContext;
  import io.netty.handler.codec.ByteToMessageDecoder;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.context.ApplicationEvent;
  import org.springframework.context.ApplicationEventPublisher;
  import lombok.extern.slf4j.Slf4j;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.concurrent.ConcurrentHashMap;
  
  /**
   * @author QingtaiJiang
   * @date 2023/4/27 18:10
   * @email qingtaij@163.com
   */
  @Slf4j
  public class Jt808Decoder extends ByteToMessageDecoder {
  
      private ApplicationEventPublisher applicationEventPublisher = null;
      private Ijt1078Service service = null;
  
      public Jt808Decoder(ApplicationEventPublisher applicationEventPublisher, Ijt1078Service service ) {
          this.applicationEventPublisher = applicationEventPublisher;
          this.service = service;
      }
  
      @Override
      protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
          Session session = ctx.channel().attr(Session.KEY).get();
          log.info("> {} hex: 7e{}7e", session, ByteBufUtil.hexDump(in));
          try {
              // 按照部标定义执行校验和转义
              ByteBuf buf = unEscapeAndCheck(in);
              buf.retain();
              Header header = new Header();
              header.setMsgId(ByteBufUtil.hexDump(buf.readSlice(2)));
              header.setMsgPro(buf.readUnsignedShort());
              // 从消息属性中读取是否存在分包
              boolean isSubpackage = (header.getMsgPro() >>> 13 & 1) == 1;
              if (header.is2019Version()) {
                  header.setVersion(buf.readUnsignedByte());
                  String devId = ByteBufUtil.hexDump(buf.readSlice(10));
                  header.setPhoneNumber(devId.replaceFirst("^0*", ""));
              } else {
                  header.setPhoneNumber(ByteBufUtil.hexDump(buf.readSlice(6)).replaceFirst("^0*", ""));
              }
              header.setSn(buf.readUnsignedShort());
              if (isSubpackage) {
                  int packageCount = buf.readUnsignedShort();
                  int packageNumber = buf.readUnsignedShort();
                  log.debug("[分包消息] header: {}, 序号: {}, 总数: {}", header, packageNumber, packageCount);
                  // 缓存带合并的分包消息
                  ByteBuf intactBuf = MultiPacketManager.INSTANCE.add(header, packageCount, buf);
                  if (intactBuf == null) {
                      return;
                  }
                  buf = intactBuf;
              }
              Re handler = CodecFactory.getHandler(header.getMsgId());
              if (handler == null) {
                  log.error("get msgId is null {}", header.getMsgId());
                  buf.release();
                  return;
              }
  
              Rs decode = handler.decode(buf, header, session, service);
              ApplicationEvent applicationEvent = handler.getEvent();
              if (applicationEvent != null) {
                  applicationEventPublisher.publishEvent(applicationEvent);
              }
              if (decode != null) {
                  out.add(decode);
              }
          } finally {
              in.skipBytes(in.readableBytes());
          }
      }
  
  
      /**
       * 转义与验证校验码
       *
       * @param byteBuf 转义Buf
       * @return 转义好的数据
       */
      public ByteBuf unEscapeAndCheck(ByteBuf byteBuf) throws Exception {
          int low = byteBuf.readerIndex();
          int high = byteBuf.writerIndex();
          byte checkSum = 0;
          int calculationCheckSum = 0;
  
          byte aByte = byteBuf.getByte(high - 2);
          byte protocolEscapeFlag7d = 0x7d;
          //0x7d转义
          byte protocolEscapeFlag01 = 0x01;
          //0x7e转义
          byte protocolEscapeFlag02 = 0x02;
          if (aByte == protocolEscapeFlag7d) {
              byte b2 = byteBuf.getByte(high - 1);
              if (b2 == protocolEscapeFlag01) {
                  checkSum = protocolEscapeFlag7d;
              } else if (b2 == protocolEscapeFlag02) {
                  checkSum = 0x7e;
              } else {
                  log.error("转义1异常:{}", ByteBufUtil.hexDump(byteBuf));
                  throw new Exception("转义错误");
              }
              high = high - 2;
          } else {
              high = high - 1;
              checkSum = byteBuf.getByte(high);
          }
          List<ByteBuf> bufList = new ArrayList<>();
          int index = low;
          while (index < high) {
              byte b = byteBuf.getByte(index);
              if (b == protocolEscapeFlag7d) {
                  byte c = byteBuf.getByte(index + 1);
                  if (c == protocolEscapeFlag01) {
                      ByteBuf slice = slice0x01(byteBuf, low, index);
                      bufList.add(slice);
                      b = protocolEscapeFlag7d;
                  } else if (c == protocolEscapeFlag02) {
                      ByteBuf slice = slice0x02(byteBuf, low, index);
                      bufList.add(slice);
                      b = 0x7e;
                  } else {
                      log.error("转义2异常:{}", ByteBufUtil.hexDump(byteBuf));
                      throw new Exception("转义错误");
                  }
                  index += 2;
                  low = index;
              } else {
                  index += 1;
              }
              calculationCheckSum = calculationCheckSum ^ b;
          }
  
          if (calculationCheckSum == checkSum) {
              if (bufList.isEmpty()) {
                  return byteBuf.slice(low, high);
              } else {
                  bufList.add(byteBuf.slice(low, high - low));
                  return new CompositeByteBuf(UnpooledByteBufAllocator.DEFAULT, false, bufList.size(), bufList);
              }
          } else {
              log.info("{} 解析校验码:{}--计算校验码:{}", ByteBufUtil.hexDump(byteBuf), checkSum, calculationCheckSum);
              throw new Exception("校验码错误!");
          }
      }
  
  
      private ByteBuf slice0x01(ByteBuf buf, int low, int sign) {
          return buf.slice(low, sign - low + 1);
      }
  
      private ByteBuf slice0x02(ByteBuf buf, int low, int sign) {
          buf.setByte(sign, 0x7e);
          return buf.slice(low, sign - low + 1);
      }
  }
  