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.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 java.util.ArrayList; 
 | 
import java.util.List; 
 | 
  
 | 
/** 
 | 
 * @author QingtaiJiang 
 | 
 * @date 2023/4/27 18:10 
 | 
 * @email qingtaij@163.com 
 | 
 */ 
 | 
public class Jt808Decoder extends ByteToMessageDecoder { 
 | 
    private final static Logger log = LoggerFactory.getLogger(Jt808Decoder.class); 
 | 
  
 | 
    @Override 
 | 
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { 
 | 
        Session session = ctx.channel().attr(Session.KEY).get(); 
 | 
        log.info("> {} hex:{}", session, ByteBufUtil.hexDump(in)); 
 | 
  
 | 
        try { 
 | 
            ByteBuf buf = unEscapeAndCheck(in); 
 | 
  
 | 
            Header header = new Header(); 
 | 
            header.setMsgId(ByteBufUtil.hexDump(buf.readSlice(2))); 
 | 
            header.setMsgPro(buf.readUnsignedShort()); 
 | 
            if (header.is2019Version()) { 
 | 
                header.setVersion(buf.readUnsignedByte()); 
 | 
                String devId = ByteBufUtil.hexDump(buf.readSlice(10)); 
 | 
                header.setDevId(devId.replaceFirst("^0*", "")); 
 | 
            } else { 
 | 
                header.setDevId(ByteBufUtil.hexDump(buf.readSlice(6)).replaceFirst("^0*", "")); 
 | 
            } 
 | 
            header.setSn(buf.readUnsignedShort()); 
 | 
  
 | 
            Re handler = CodecFactory.getHandler(header.getMsgId()); 
 | 
            if (handler == null) { 
 | 
                log.error("get msgId is null {}", header.getMsgId()); 
 | 
                return; 
 | 
            } 
 | 
            Rs decode = handler.decode(buf, header, session); 
 | 
            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.size() == 0) { 
 | 
                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); 
 | 
    } 
 | 
} 
 |