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