#
vincentlu
2025-11-17 e34324dfdbd779bbd03d8b49727b7845d70fb1d0
#
1个文件已添加
2个文件已修改
310 ■■■■■ 已修改文件
zy-acs-gateway/src/main/java/com/zy/acs/gateway/job/PacTask.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-gateway/src/main/java/com/zy/acs/gateway/utils/PacCoder.java 306 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-gateway/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-acs-gateway/src/main/java/com/zy/acs/gateway/job/PacTask.java
@@ -34,6 +34,8 @@
                        , uniqueNo
                        ,  String.format("%02x", agvPackage.getHeader().getProtocolType().getCode()).toUpperCase()
                );
                // log.info("Agv [{}] 下行 [{}] >>> {}", uniqueNo, agvPackage.getHeader().getProtocolType().getDes(), PacCoder.encode(agvPackage));
                return;
            }
            channel.writeAndFlush(pac);
zy-acs-gateway/src/main/java/com/zy/acs/gateway/utils/PacCoder.java
New file
@@ -0,0 +1,306 @@
package com.zy.acs.gateway.utils;
import com.alibaba.fastjson.JSON;
import com.zy.acs.common.constant.RedisConstant;
import com.zy.acs.common.domain.protocol.IMessageBody;
import com.zy.acs.common.utils.RedisSupport;
import com.zy.acs.common.utils.Utils;
import com.zy.acs.framework.common.Cools;
import com.zy.acs.framework.common.RadixTools;
import com.zy.acs.gateway.constant.DirectionType;
import com.zy.acs.gateway.constant.PacErrorType;
import com.zy.acs.gateway.constant.PackagePart;
import com.zy.acs.gateway.constant.ProtocolType;
import com.zy.acs.gateway.domain.AgvPackage;
import com.zy.acs.gateway.domain.PacHeader;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class PacCoder {
    // {@link com.zy.acs.gateway.job.PacTask#run()}
    // log.info("Agv [{}] 下行 [{}] >>> {}", uniqueNo, agvPackage.getHeader().getProtocolType().getDes(), PacCoder.encode(agvPackage));
    public static void main(String[] args) {
        // 上线
        String agvNo = "18";
        RedisSupport redis = RedisSupport.defaultRedisSupport;
        redis.setObject(RedisConstant.AGV_ONLINE_FLAG, agvNo, 1, 1000);
        // 解码 ------------------------------------------------------------------------------
//        String hexStr = "AA3000660000006709C5671287000000FFFF06005C2F33430300B1C7C05C2F3343000000000000000000000000A6FF40020C03FD0AAA4000660000006709C56711323332373631373236303834353530360387000000B4000000000000000000000000000000000000000000000000000000000000000000E83B";
        String hexStr = "AA30000E0000006709C56712E600000001000000BCC9B24200808971C0BCC9B2420000000000000000000000005A0000020C0070B3";
        AgvPackage pac = decode(hexStr);
        System.out.println(JSON.toJSONString(pac));
        // 编码 ------------------------------------------------------------------------------
        String encodeHex = encode(pac);
        System.out.println("编码报文 ===>> " + encodeHex);
    }
    public static int maxFrameLength = 4096;
    public static AgvPackage decode(String hex) {
        System.out.println("解码报文 ===>> " + hex.toUpperCase());
        byte[] bytes = RadixTools.hexStringToBytes(hex);
//        ByteBuf in = Unpooled.buffer();
        ByteBuf in = Unpooled.wrappedBuffer(bytes);
        int startMark = indexOfStartMark(in);
        if (startMark == -1){
            in.skipBytes(in.readableBytes());
            return null;
        }
        if (in.readableBytes() > maxFrameLength) {
            in.skipBytes(in.readableBytes());
            return null;
        }
        // 去除无用前缀报文
        if (startMark != 0){
            in.readerIndex(startMark);
            in.discardReadBytes();
        }
        // 粘包处理
        in.markReaderIndex();
        in.readerIndex(PackagePart.CONTENT_LENGTH.getStartIndex());
        int pacTotalLen = PackagePart.START_SYMBOL.getLen()
                + PackagePart.CONTENT_LENGTH.getLen()
                + in.readShortLE()
                + PackagePart.VALIDE_CODE.getLen()
                ;
        in.resetReaderIndex();
        ByteBuf byteBuf = in.readSlice(pacTotalLen);
        // 生成和初始化消息包装类
        AgvPackage pac = AgvPackage.valueOfEmpty();
        pac.setSourceBuff(byteBuf);
        pac = analyzeProtocol(pac);
        in.resetReaderIndex();
        parseIMessageBody(pac);
        return pac;
    }
    public static AgvPackage analyzeProtocol(AgvPackage pac){
        ByteBuf byteBuf = pac.getSourceBuff();
        PacHeader pacHeader = pac.getHeader();
        // 唯一标识码
        byteBuf.readerIndex(PackagePart.UNIQUENO.getStartIndex());
        byte[] bytes = new byte[PackagePart.UNIQUENO.getLen()];
        byteBuf.readBytes(bytes);
        Utils.reverse(bytes);
        String uniqueno = String.valueOf(RadixTools.bytesToInt(bytes));
        if (!Cools.isEmpty(uniqueno)) {
            pacHeader.setUniqueNo(uniqueno);
            byteBuf.resetReaderIndex();
        } else {
            return pac.setErrorPac(Boolean.TRUE).setPacErrorType(PacErrorType.PAC_ANALYZE_ERROR);
        }
        // 获取标识符
        byte startSymbol = byteBuf.readByte();
        DirectionType direction = null;
        if ((0xEE&0xFF) == (startSymbol&0xFF)) {
            pacHeader.setStartSymbol(startSymbol);
            direction = DirectionType.DOWN;
        } else if ((0xAA&0xFF) == (startSymbol&0xFF)) {
            pacHeader.setStartSymbol(startSymbol);
            direction = DirectionType.UP;
        } else {
            return pac.setErrorPac(Boolean.TRUE).setPacErrorType(PacErrorType.PAC_ANALYZE_ERROR);
        }
        // 获取协议体长度
        int contentLength = byteBuf.readShortLE();
        if (contentLength >= 0) {
            pacHeader.setContentLength(contentLength);
        } else {
            return pac.setErrorPac(Boolean.TRUE).setPacErrorType(PacErrorType.PAC_ANALYZE_ERROR);
        }
        // skip uniqueNo
        byteBuf.readerIndex(byteBuf.readerIndex() + PackagePart.UNIQUENO.getLen());
        // 获取时间戳
        byteBuf.readerIndex(PackagePart.TIMESTAMP.getStartIndex());
        int timestamp = byteBuf.readIntLE();
        if (timestamp > 0) {
            pacHeader.setTimestamp(timestamp);
        } else {
            return pac.setErrorPac(Boolean.TRUE).setPacErrorType(PacErrorType.PAC_ANALYZE_ERROR);
        }
        // 获取命令标识
        int commandByte = byteBuf.readByte() & 0xFF;
        ProtocolType protocolType = ProtocolType.getByCode(commandByte, direction);
        if (null != protocolType) {
            pacHeader.setProtocolType(protocolType);
        } else {
            return pac.setErrorPac(Boolean.TRUE).setPacErrorType(PacErrorType.PAC_ANALYZE_ERROR);
        }
        // 获取协议体
        if (contentLength > 0) {
            ByteBuf body = byteBuf.readSlice(pac.getHeader().getContentLength() - (
                    + PackagePart.UNIQUENO.getLen()
                            + PackagePart.TIMESTAMP.getLen()
                            + PackagePart.COMMAND_MARK.getLen()
            ));
            if (null != body && body.readableBytes() >= 0) {
                pac.getBody().setContent(body);
            } else {
                return pac.setErrorPac(Boolean.TRUE).setPacErrorType(PacErrorType.PAC_ANALYZE_ERROR);
            }
        }
        // 校验码
        if(byteBuf.readableBytes() == 2) {
            pac.setValidCode(byteBuf.readUnsignedShortLE());
        } else {
            return pac.setErrorPac(Boolean.TRUE).setPacErrorType(PacErrorType.PAC_ANALYZE_ERROR);
        }
        return pac;
    }
    public static Boolean parseIMessageBody(AgvPackage pac){
        String namespace = IMessageBody.class.getPackage().getName();
        ProtocolType protocolType = pac.getHeader().getProtocolType();
        if (null == protocolType) {
            // 未知包
            return Boolean.FALSE;
        }
        String className =  namespace +  ".AGV_" + Utils.zeroFill(Integer.toHexString(protocolType.getCode()).toUpperCase(), 2)
                +"_"
                +  pac.getHeader().getProtocolType().getDirection().toString().toUpperCase();
        Class<?> cls = null;
        try {
            cls  =   Class.forName(className);;
        } catch (ClassNotFoundException e) {
            log.error("MessageBodyHandler ClassNotFoundException", e);log.error("找不到指定类:{}", className);
            return Boolean.FALSE;
        }
        Object obj = null;
        if (null != cls) {
            try {
                obj = cls.newInstance();
            } catch (ReflectiveOperationException reflectiveOperationException) {
                log.error("MessageBodyHandler ReflectiveOperationException", reflectiveOperationException);
                log.error("java反射创建实例失败:{}", className);
                // 。。。
                return Boolean.FALSE;
            }
        }
        ByteBuf contentBuf = pac.getBody().getContent();           contentBuf.markReaderIndex();   // sign
        // body.buf 属于切片获取, slice 与 channel中的缓冲区 为同一 refenec
        contentBuf.resetReaderIndex();
        int len= contentBuf.readableBytes();
        byte[] bytes = new byte[len];
        pac.getBody().getContent().readBytes(bytes);
        // 读取字节数组 ===>>     实际报文类型
        IMessageBody iMessageBody = null;
        if (null != obj) {
            if ( obj  instanceof IMessageBody) {
                iMessageBody = (IMessageBody) obj;
                iMessageBody.readFromBytes(bytes);
            }
        }
        pac.getBody().setMessageBody(iMessageBody);     contentBuf.resetReaderIndex();
        return true;
    }
    public static String encode(AgvPackage pac) {
        ByteBuf out = Unpooled.buffer();
        byte[] bodyBytes = pac.getBody().getMessageBody().writeToBytes();   // body
        String uniqueNo = pac.getHeader().getUniqueNo();
        byte[] uniquenoBytes = RadixTools.intToBytes(Integer.parseInt(pac.getHeader().getUniqueNo()));   // uniqueno
        int len = PackagePart.UNIQUENO.getLen()     // len
                + PackagePart.TIMESTAMP.getLen()
                + PackagePart.COMMAND_MARK.getLen()
                + bodyBytes.length;
        out.writeByte(pac.getHeader().getStartSymbol())         // symbol
                .writeShortLE(len)
                .writeBytes(Utils.reverse(uniquenoBytes))       // uniqueno
                .writeIntLE((int) (System.currentTimeMillis() / 1000))   // timestamp
                .writeByte(pac.getHeader().getProtocolType().getCode()) // type
                .writeBytes(bodyBytes)                          // body
                .writeShort(pac.getValidCode())                 // valid
        ;
        pac.setValidCode(ValidUtil.calculateValidByteFromBuff(out));
        out.resetReaderIndex();
        out.writerIndex(out.readableBytes() - 2);
        out.writeShortLE(pac.getValidCode());
        String hexStr = ByteBufUtil.hexDump(out).toUpperCase();
//        log.info("Agv [{}] 下行 [{}] >>> {}", uniqueNo, pac.getHeader().getProtocolType().getDes(), hexStr);
        return hexStr;
    }
    // 获取标识位下标
    public static int indexOfStartMark(ByteBuf inputBuffer){
        int length = inputBuffer.writerIndex();
        // 报文长度至少大于2
        if (length < 2) {
            return -1;
        }
        int readerIndex = inputBuffer.readerIndex();
        for(int i = readerIndex; i < length - 1; i ++) {
            byte b1 = inputBuffer.getByte(i);
            if ((0xEE&0xFF) == (b1&0xFF) || (0xAA&0xFF) == (b1&0xFF)) {
                return i;
            }
        }
        return -1;
    }
}
zy-acs-gateway/src/main/resources/application.yml
@@ -28,7 +28,7 @@
logging:
  file:
    path: /stock/out/rcs-gateway/logs
    path: stock/out/rcs-gateway/logs
agv-tcp:
  #tcp/ip协议端口