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; // AA 2500 88000000 9C675F69 06 30363733333731353730333735353838 74050000 C4 00 AD02 00000000 642F // EE 1F00 88000000 C8675F69 06 30363733333731353730333735353838 C401000000000BCE @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; } }