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