#
luxiaotao1123
2024-08-12 1560f3063ca90d41c0717f8ed6e1fb00fde64776
#
7个文件已添加
529 ■■■■■ 已修改文件
app/src/main/java/com/example/agvcontroller/protocol/AGV_02_DOWN.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AgvPackage.java 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/CRCUtils.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/IMessageBody.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/PacHeader.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/ProtocolEncoder.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/ProtocolUtils.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/example/agvcontroller/protocol/AGV_02_DOWN.java
New file
@@ -0,0 +1,47 @@
package com.zy.acs.common.domain.protocol;
import com.zy.acs.common.utils.Utils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
/**
 * 动作命令包
 * Created by vincent on 2023/3/21
 */
@Data
public class AGV_02_DOWN implements IMessageBody, Serializable {
    private static final long serialVersionUID = 1664188062202647371L;
    @Override
    public byte[] writeToBytes() {
        String serialNo = Utils.zeroFill(this.serialNo, 16);
        byte[] serialNoBytes = Utils.reverse(serialNo.getBytes());
        byte cmdCodeByte = (byte) this.getCmdCode();
        byte valByte = (byte) this.getVal();
        byte[] cmdBodyBytes = commandBody.writeToBytes();
        return Utils.merge(serialNoBytes, cmdCodeByte, valByte, cmdBodyBytes);
    }
    @Override
    public void readFromBytes(byte[] messageBodyBytes) {
    }
    // 流水号 - 16
    private String serialNo;
    // 命令码
    private int cmdCode;
    // 属性值
    private int val;
    // 动作参数
    private ICommandBody commandBody;
}
app/src/main/java/com/example/agvcontroller/protocol/AgvPackage.java
New file
@@ -0,0 +1,157 @@
package com.zy.acs.gateway.domain;
import com.core.common.Cools;
import com.zy.acs.gateway.constant.AgvConstant;
import com.zy.acs.gateway.constant.PacErrorType;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import java.util.Objects;
/**
 * AGV报文模型
 * Created by vincent on 2023/3/10
 */
public class AgvPackage implements PackageSupport {
    /**
     * 源数据包缓冲区(引用)
     */
    private ByteBuf sourceBuff;
    /**
     * 原始消息对应的16进制字符串
     */
    private String sourceHexStr;
    /**
     * 消息头部
     */
    private PacHeader header;
    /**
     * 消息体
     */
    private PacBody body;
    /**
     * 消息的校正码
     */
    private int validCode;
    /**
     * 是否为校验异常包
     */
    private boolean errorPac;
    /**
     * 校验异常类型
     */
    private PacErrorType pacErrorType;
    public static AgvPackage valueOfEmpty() {
        AgvPackage agvPackage = new AgvPackage();
        agvPackage.setHeader(new PacHeader())
                .setBody(new PacBody())
                .setValidCode((short) 0)
                .setErrorPac(false);
        return agvPackage;
    }
    public String toLogString() {
        StringBuilder pacSb = new StringBuilder();
        pacSb.append("AGV(").append(getHeader().getUniqueNo()).append(")")
            .append("上传")
            .append("[").append(getHeader().getProtocolType().getDes()).append("]消息.")
            .append("原始消息[").append(getSourceHexStr()).append("]");
        return pacSb.toString();
    }
    public ByteBuf getSourceBuff() {
        // 因为处理buffer时,总是希望拿到一个重置了readerIndex的buf
        if (Objects.nonNull(this.sourceBuff)) {
            this.sourceBuff.resetReaderIndex();
        }
        return this.sourceBuff;
    }
    public AgvPackage setSourceBuff(ByteBuf sourceBuff) {
        this.sourceBuff = sourceBuff;
        if (Cools.isEmpty(this.sourceHexStr)) {
            this.sourceBuff.resetReaderIndex();
            this.sourceHexStr = ByteBufUtil.hexDump(this.sourceBuff).toUpperCase();
            this.sourceBuff.resetReaderIndex();
        }
        return this;
    }
    public PacHeader getHeader() {
        return header;
    }
    public AgvPackage setHeader(PacHeader header) {
        this.header = header;
        return this;
    }
    public PacBody getBody() {
        return body;
    }
    public AgvPackage setBody(PacBody body) {
        this.body = body;
        return this;
    }
    public int getValidCode() {
        return validCode;
    }
    public AgvPackage setValidCode(int validCode) {
        this.validCode = validCode;
        return this;
    }
    public boolean isErrorPac() {
        return errorPac;
    }
    public AgvPackage setErrorPac(boolean errorPac) {
        this.errorPac = errorPac;
        return this;
    }
    public String getSourceHexStr() {
        return sourceHexStr;
    }
    public AgvPackage setSourceHexStr(String sourceHexStr) {
        this.sourceHexStr = sourceHexStr;
        return this;
    }
    public PacErrorType getPacErrorType() {
        return pacErrorType;
    }
    public AgvPackage setPacErrorType(PacErrorType pacErrorType) {
        this.pacErrorType = pacErrorType;
        return this;
    }
    public ByteBuf convert(ByteBuf byteBuf){
        byteBuf.writeByte(this.getHeader().getStartSymbol())
                .writeShort(this.getHeader().getContentLength())
                .writeByte(this.getHeader().getProtocolType().getCode())
                .writeBytes(this.getHeader().getUniqueNo().getBytes(AgvConstant.CHARSET_GBK))
                .writeByte(this.getHeader().getEncryptType().getCode())
                .writeBytes(this.getBody().getContent())
                .writeByte(this.getValidCode());
        // 计算并设置校验码
//        this.setValidCode(ValidUtil.caculateValidByteFromBuff(byteBuf));
        byteBuf.resetReaderIndex();
        byteBuf.writerIndex(byteBuf.readableBytes() - 1).writeByte(this.getValidCode());
        return byteBuf;
    }
}
app/src/main/java/com/example/agvcontroller/protocol/CRCUtils.java
New file
@@ -0,0 +1,41 @@
package com.zy.acs.gateway.utils;
/**
 * CRC16循环冗余校验码
 * Created by vincent on 2023/3/13
 */
public class CRCUtils {
    /**
     * 一个字节占 8位
     */
    private static final int BITS_OF_BYTE = 8;
    /**
     * 多项式
     */
    private static final int POLYNOMIAL = 0XA001;
    /**
     * CRC寄存器默认初始值
     */
    private static final int INITIAL_VALUE = 0XFFFF;
    /**
     * CRC16 编码
     * @param bytes 编码内容
     * @return 编码结果
     */
    public static int crc16(byte[] bytes) {
        int res = INITIAL_VALUE;
        for (byte data : bytes) {
            // 把byte转换成int后再计算
            res = res ^ (data & 0XFF);
            for (int i = 0; i < BITS_OF_BYTE; i++) {
                res = (res & 0X0001) == 1 ? (res >> 1) ^ POLYNOMIAL : res >> 1;
            }
        }
        return res;
    }
}
app/src/main/java/com/example/agvcontroller/protocol/IMessageBody.java
New file
@@ -0,0 +1,11 @@
package com.zy.acs.common.domain.protocol;
import java.io.Serializable;
public interface IMessageBody extends Serializable {
    byte[] writeToBytes();
    void readFromBytes(byte[] messageBodyBytes);
}
app/src/main/java/com/example/agvcontroller/protocol/PacHeader.java
New file
@@ -0,0 +1,98 @@
package com.zy.acs.gateway.domain;
import com.zy.acs.gateway.constant.EncryType;
import com.zy.acs.gateway.constant.ProtocolType;
import lombok.Data;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
 * 协议头
 * Created by vincent on 2019-04-03
 */
@Data
public class PacHeader {
    /**
     * 起始符
     * 固定为"0xEE || 0xAA"
     */
    private byte startSymbol;
    /**
     * 数据单元长度
     */
    private int contentLength;
    /**
     * 唯一标识码
     */
    private String uniqueNo;
    /**
     * 时间戳
     */
    private int timestamp;
    /**
     * 命令标识
     */
    private ProtocolType protocolType;
    /**
     * 流水号
     */
    private String serialNum;
    /**
     * 数据单元加密方式
     */
    private EncryType encryptType;
    public PacHeader setStartSymbol(Byte startSymbol) {
        this.startSymbol = startSymbol;
        return this;
    }
    public PacHeader setProtocolType(ProtocolType protocolType) {
        this.protocolType = protocolType;
        return this;
    }
    public PacHeader setTimestamp(Integer timestamp) {
        this.timestamp = timestamp;
        return this;
    }
    public PacHeader setSerialNum(String serialNum) {
        this.serialNum = serialNum;
        return this;
    }
    public PacHeader setUniqueNo(String uniqueNo) {
        this.uniqueNo = uniqueNo;
        return this;
    }
    public PacHeader setEncryptType(EncryType encryptType) {
        this.encryptType = encryptType;
        return this;
    }
    public PacHeader setContentLength(int contentLength) {
        this.contentLength = contentLength;
        return this;
    }
    @Override
    public String toString() {
        return new ToStringBuilder(this)
                .append("startSymbol", startSymbol)
                .append("contentLength", contentLength)
                .append("uniqueNo", uniqueNo)
                .append("timestamp", timestamp)
                .append("protocolType", protocolType.getDes())
                .append("serialNum", serialNum)
                .toString();
    }
}
app/src/main/java/com/example/agvcontroller/protocol/ProtocolEncoder.java
New file
@@ -0,0 +1,89 @@
package com.zy.acs.gateway.handler.coder;
import com.core.common.RadixTools;
import com.zy.acs.common.utils.Utils;
import com.zy.acs.gateway.config.SystemProperties;
import com.zy.acs.gateway.constant.PackagePart;
import com.zy.acs.gateway.domain.AgvPackage;
import com.zy.acs.gateway.utils.ValidUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * 编码器
 * 此解码器将会生成校验码
 * 处理方式: 异或和
 * Created by vincent on 2019-04-02
 */
@Component
@ChannelHandler.Sharable
public class ProtocolEncoder extends MessageToByteEncoder<Object> {
    private static final Logger log = LoggerFactory.getLogger(ProtocolEncoder.class);
    @Autowired
    private SystemProperties systemProperties;
    @Override
    protected void encode(ChannelHandlerContext ctx, Object obj, ByteBuf out) {
        if (obj instanceof ByteBuf){
            out.writeBytes((ByteBuf) obj);
        } else if (obj instanceof byte[]){
            out.writeBytes((byte[]) obj);
        } else if (obj instanceof AgvPackage){
            AgvPackage pac = (AgvPackage)obj;
            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());
            if (systemProperties.isPrintPacLog()){
                log.info("Agv [{}] 下行 [{}] >>> {}", uniqueNo, pac.getHeader().getProtocolType().getDes(), ByteBufUtil.hexDump(out).toUpperCase());
            }
        }
    }
// EE | 11 00 | 01 00 00 00 | 0C AB 12 64 | F0  | 01 00 | 01 01 | 00 00 00 00 | 4C F7
// #  | len   | uniqueno    | timestamp   | cmd | content                     | crc
}
app/src/main/java/com/example/agvcontroller/protocol/ProtocolUtils.java
New file
@@ -0,0 +1,86 @@
package com.zy.acs.gateway.utils;
import com.zy.acs.common.domain.AgvProtocol;
import com.zy.acs.common.domain.protocol.IMessageBody;
import com.zy.acs.gateway.constant.ProtocolPojoType;
import com.zy.acs.gateway.constant.ProtocolType;
import com.zy.acs.gateway.domain.AgvPackage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * Created by vincent on 2019-04-03
 */
public class ProtocolUtils {
    private static final Logger log = LoggerFactory.getLogger(ProtocolUtils.class);
    // 下行协议报文组装
    public static AgvPackage installDownProtocol(AgvProtocol protocol){
        ProtocolPojoType protocolPojo = ProtocolPojoType.query(protocol.getMessageBody().getClass());
        assert protocolPojo !=   null;
        AgvPackage ackPackage = AgvPackage.valueOfEmpty();
        ackPackage.getHeader()
                .setStartSymbol((byte)0xEE)
                .setContentLength(0)
                .setUniqueNo(protocol.getAgvNo())
                .setTimestamp(protocol.getTimestamp())
                .setProtocolType(protocolPojo.protocolType)
        ;
        ackPackage.getBody().setMessageBody(protocol.getMessageBody());
        return ackPackage;
    }
    // 下行协议报文组装
    public static AgvPackage installDownProtocol(String uniqueNo, ProtocolType protocolType){
        AgvPackage ackPackage = AgvPackage.valueOfEmpty();
        ackPackage.getHeader()
                .setStartSymbol((byte)0xEE)
                .setContentLength(0)
                .setUniqueNo(uniqueNo)
                .setTimestamp((int)System.currentTimeMillis()/1000)
                .setProtocolType(protocolType)
        ;
        ProtocolPojoType protocolPojo = ProtocolPojoType.query(protocolType);
        assert protocolPojo != null;
        IMessageBody iMessageBody = null;
        try {
            iMessageBody = protocolPojo.clazz.newInstance();
        } catch (ReflectiveOperationException reflectiveOperationException) {
            log.error("MessageBodyHandler ReflectiveOperationException", reflectiveOperationException);
            log.error("java反射创建实例失败:{}", protocolPojo.clazz.getName());
            return null;
        }
        ackPackage.getBody().setMessageBody(iMessageBody);
        return ackPackage;
    }
}