diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java index 00a5710..45fb908 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java @@ -6,7 +6,7 @@ */ public interface FixedPropertyEnum { - String FIXED_POSITION = "fixedPosition"; + String FIXED_POSITION = "fixedPosition"; String TOTAL_LENGTH = "totalLength"; diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java index 00a5710..45fb908 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java @@ -6,7 +6,7 @@ */ public interface FixedPropertyEnum { - String FIXED_POSITION = "fixedPosition"; + String FIXED_POSITION = "fixedPosition"; String TOTAL_LENGTH = "totalLength"; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java index 4886e8b..eacb937 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java @@ -13,6 +13,8 @@ * 按照字段评估进行字段解析 */ private String ruleJson; + + private String replyRule; /** * 起始位置(单位byte) */ diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java index 00a5710..45fb908 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java @@ -6,7 +6,7 @@ */ public interface FixedPropertyEnum { - String FIXED_POSITION = "fixedPosition"; + String FIXED_POSITION = "fixedPosition"; String TOTAL_LENGTH = "totalLength"; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java index 4886e8b..eacb937 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java @@ -13,6 +13,8 @@ * 按照字段评估进行字段解析 */ private String ruleJson; + + private String replyRule; /** * 起始位置(单位byte) */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java index 00b6e64..1b6ffaf 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java @@ -20,11 +20,6 @@ * 协议配置id */ private Long ruleId; - - /** - * 回复规则 - */ - private String replyRule; /** * 回复规则 */ diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java index 00a5710..45fb908 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java @@ -6,7 +6,7 @@ */ public interface FixedPropertyEnum { - String FIXED_POSITION = "fixedPosition"; + String FIXED_POSITION = "fixedPosition"; String TOTAL_LENGTH = "totalLength"; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java index 4886e8b..eacb937 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java @@ -13,6 +13,8 @@ * 按照字段评估进行字段解析 */ private String ruleJson; + + private String replyRule; /** * 起始位置(单位byte) */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java index 00b6e64..1b6ffaf 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java @@ -20,11 +20,6 @@ * 协议配置id */ private Long ruleId; - - /** - * 回复规则 - */ - private String replyRule; /** * 回复规则 */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java index 9547040..33b95c1 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java @@ -27,10 +27,6 @@ * 上传下发是否有变化, 没有变化,可以直接组装 */ private String isReplyFix; - /** - * 回复规则 - */ - private String replyRule; private String ownerId; private Date createTime; diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java index 00a5710..45fb908 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java @@ -6,7 +6,7 @@ */ public interface FixedPropertyEnum { - String FIXED_POSITION = "fixedPosition"; + String FIXED_POSITION = "fixedPosition"; String TOTAL_LENGTH = "totalLength"; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java index 4886e8b..eacb937 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java @@ -13,6 +13,8 @@ * 按照字段评估进行字段解析 */ private String ruleJson; + + private String replyRule; /** * 起始位置(单位byte) */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java index 00b6e64..1b6ffaf 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java @@ -20,11 +20,6 @@ * 协议配置id */ private Long ruleId; - - /** - * 回复规则 - */ - private String replyRule; /** * 回复规则 */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java index 9547040..33b95c1 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java @@ -27,10 +27,6 @@ * 上传下发是否有变化, 没有变化,可以直接组装 */ private String isReplyFix; - /** - * 回复规则 - */ - private String replyRule; private String ownerId; private Date createTime; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java b/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java index 6e80779..45c50eb 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java @@ -6,11 +6,13 @@ import com.googlecode.aviator.runtime.function.FunctionUtils; import com.googlecode.aviator.runtime.type.AviatorBigInt; import com.googlecode.aviator.runtime.type.AviatorObject; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import org.bouncycastle.util.encoders.Hex; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.nio.charset.Charset; +import java.util.*; public class AviatorUtil { @@ -23,16 +25,17 @@ // bytStrList.add(query[i]); // } //Original String -// String string = "hello world"; - List list =new ArrayList<>(); - Map env2 = new HashMap(); - for (int i = 0; i < 2; i++) { - list.add("2"); - } - env2.put("list",list); - AviatorEvaluator.addFunction(new MinFunction()); - Object values = String.valueOf(AviatorEvaluator.execute("sum(list)", env2)); - int i = 0; +// tring string = "hello world"; +// List list = new ArrayList<>(); +// Map env2 = new HashMap(); +// for (int i = 0; i < 2; i++) { +// list.add("2"); +// } +// env2.put("list", list); + + Object values = String.valueOf(AviatorEvaluator.execute("dateTime=date_to_string(sysdate(),'yyyyMMdd');string.replace_first(dateTime,\"2\",\"0\")")); + System.out.println(values); +// int i = 0; } static class MinFunction extends AbstractFunction { diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java index 00a5710..45fb908 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java @@ -6,7 +6,7 @@ */ public interface FixedPropertyEnum { - String FIXED_POSITION = "fixedPosition"; + String FIXED_POSITION = "fixedPosition"; String TOTAL_LENGTH = "totalLength"; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java index 4886e8b..eacb937 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java @@ -13,6 +13,8 @@ * 按照字段评估进行字段解析 */ private String ruleJson; + + private String replyRule; /** * 起始位置(单位byte) */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java index 00b6e64..1b6ffaf 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java @@ -20,11 +20,6 @@ * 协议配置id */ private Long ruleId; - - /** - * 回复规则 - */ - private String replyRule; /** * 回复规则 */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java index 9547040..33b95c1 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java @@ -27,10 +27,6 @@ * 上传下发是否有变化, 没有变化,可以直接组装 */ private String isReplyFix; - /** - * 回复规则 - */ - private String replyRule; private String ownerId; private Date createTime; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java b/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java index 6e80779..45c50eb 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java @@ -6,11 +6,13 @@ import com.googlecode.aviator.runtime.function.FunctionUtils; import com.googlecode.aviator.runtime.type.AviatorBigInt; import com.googlecode.aviator.runtime.type.AviatorObject; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import org.bouncycastle.util.encoders.Hex; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.nio.charset.Charset; +import java.util.*; public class AviatorUtil { @@ -23,16 +25,17 @@ // bytStrList.add(query[i]); // } //Original String -// String string = "hello world"; - List list =new ArrayList<>(); - Map env2 = new HashMap(); - for (int i = 0; i < 2; i++) { - list.add("2"); - } - env2.put("list",list); - AviatorEvaluator.addFunction(new MinFunction()); - Object values = String.valueOf(AviatorEvaluator.execute("sum(list)", env2)); - int i = 0; +// tring string = "hello world"; +// List list = new ArrayList<>(); +// Map env2 = new HashMap(); +// for (int i = 0; i < 2; i++) { +// list.add("2"); +// } +// env2.put("list", list); + + Object values = String.valueOf(AviatorEvaluator.execute("dateTime=date_to_string(sysdate(),'yyyyMMdd');string.replace_first(dateTime,\"2\",\"0\")")); + System.out.println(values); +// int i = 0; } static class MinFunction extends AbstractFunction { diff --git a/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java b/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java index b869201..690ff82 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java @@ -6,7 +6,10 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + /** * @author cz diff --git a/sensorhub-core/pom.xml b/sensorhub-core/pom.xml index 3a55d51..632d189 100644 --- a/sensorhub-core/pom.xml +++ b/sensorhub-core/pom.xml @@ -36,12 +36,6 @@ 0.0.1-SNAPSHOT - - org.bouncycastle - bcprov-jdk15to18 - 1.71 - - diff --git a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java index 9bbec83..3764c70 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/netty/handler/SensorhubServerChannelInitialHandler.java @@ -2,8 +2,8 @@ import com.casic.missiles.predecodec.AbstractPreProcessing; import com.casic.missiles.replier.SensorhubReplier; -import com.casic.missiles.util.ClassUtil; import com.casic.missiles.codec.SensorhubDecoder; +import com.casic.missiles.util.ClazzUtil; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -23,7 +23,7 @@ ChannelPipeline pipeline = socketChannel.pipeline(); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); //添加前置处理器 - List abstractPreProcessingList = ClassUtil.getSubClassList(AbstractPreProcessing.class, true); + List abstractPreProcessingList = ClazzUtil.getSubClassList(AbstractPreProcessing.class, true); for (AbstractPreProcessing abstractPreprocessing : abstractPreProcessingList) { pipeline.addLast(abstractPreprocessing); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java index 6c80b11..0619437 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/GenericProtocolParser.java @@ -37,9 +37,19 @@ @RequiredArgsConstructor public class GenericProtocolParser implements ProtocolParser, ReplyCommandEnum { - // 匹配首字母前导码=> 帧结构匹配前导码=> - // 1、如果没有该协议,会存在拆包问题,缓存数组重置,经过帧结构判断进行数据分发 - // 2、存在该协议,经过帧结构判断选定帧协议,进行数据报文的解析 + /** + * TO DO: 该集合用于数据报文的的数据解析 + * 1、前导码匹配报文协议 + * 2、构建协议工厂(初始化获取与协议有关的数据库配置) + * 3、规则匹配,获取相关的实例,报文的内容,进行报文的加解密 + * 4、检测帧结构是否完整 + * 5、进行帧业务数据的内容解析,分为组合字段解析、单个字段解析 + * 6、构建发送内容,进行发送 + * 7、构建回复需要的返回内容,为回复做准备 + * + * @param byteBuf 报文内容 + * @return 构建回复需要的返回内容,为回复做准备 + */ @Override public ParseResult doParseProtocol(ByteBuf byteBuf) { //匹配前导码 @@ -141,21 +151,28 @@ //数据构建,获取固定字段的store和业务字段store private List> buildStoreData(AbstractRuleConfigFactory ruleConfigFactory, AbstractProtocolConfigFactory protocolFactory) { - List> bizDataMap = new ArrayList<>(); + List> bizDataMapList = new ArrayList<>(); Map protocolStoreObjectMap = protocolFactory.getProtocolFieldConfigProvider().getStoreObjectMap(); Map ruleStoreObjectMap = ruleConfigFactory.getFieldConfigProvider().getStoreObjectMap(); List> combinedStoreObjectMap = ruleConfigFactory.getCombinedFieldConfigProvider().getStoreObjectMap(); + + if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { + bizDataMapList.addAll(combinedStoreObjectMap); + } //加上固定字段的数据 if (!CollectionUtils.isEmpty(ruleStoreObjectMap)) { - bizDataMap.add(ruleStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(ruleStoreObjectMap); + } } if (!CollectionUtils.isEmpty(protocolStoreObjectMap)) { - bizDataMap.add(protocolStoreObjectMap); + for (Map bizDataMap : bizDataMapList) { + bizDataMap.putAll(protocolStoreObjectMap); + } } - if (!CollectionUtils.isEmpty(combinedStoreObjectMap)) { - bizDataMap.addAll(combinedStoreObjectMap); - } - return bizDataMap; + + + return bizDataMapList; } private void invokeFieldPostProcessing(List> bizDataMap) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java new file mode 100644 index 0000000..0c63174 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRC16.java @@ -0,0 +1,26 @@ +package com.casic.missiles.parser.crc; + +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; + +public class CRC16 { + + public static byte[] getCRC(String toBeVerified) { + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + long crcCheckValue = crcUtil.calculateCRC(toBeVerifiedByte); + System.out.println(); + return Hex.decode(Long.toHexString(crcCheckValue)); + } + + + public static void main(String[] args) throws IOException { + String hexString = "a3200051312020040095c30095048401911775fa081beb555c07257ee0f09440126128ca60a48db09bd155a818fe29f0f7b5ebb9390a671b899aeb9fc736911217802da58fd248a4d952d9c6f18870339d1b9fe544cbfd10dfebeab8afd428d29863"; + String toBeVerified = hexString.substring(0, hexString.length() - 4); + byte[] toBeVerifiedByte = Hex.decode(toBeVerified); + CRCUtil crcUtil = new CRCUtil(CRCUtil.Parameters.CRC16MODBUS); + System.out.println(Long.toHexString(crcUtil.calculateCRC(toBeVerifiedByte))); + } + +} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java new file mode 100644 index 0000000..d88b413 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/crc/CRCUtil.java @@ -0,0 +1,242 @@ +package com.casic.missiles.parser.crc; + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// +public class CRCUtil { + private CRCUtil.Parameters crcParams; + private long initValue; + private long[] crctable; + private long mask; + + private static long reflect(long in, int count) { + long ret = in; + for(int idx = 0; idx < count; ++idx) { + long srcbit = 1L << idx; + long dstbit = 1L << count - idx - 1; + if ((in & srcbit) != 0L) { + ret |= dstbit; + } else { + ret &= ~dstbit; + } + } + return ret; + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data) { + return calculateCRC(crcParams, data, 0, data.length); + } + + public static long calculateCRC(CRCUtil.Parameters crcParams, byte[] data, int offset, int length) { + long curValue = crcParams.init; + long topBit = 1L << crcParams.width - 1; + long mask = (topBit << 1) - 1L; + int end = offset + length; + + for(int i = offset; i < end; ++i) { + long curByte = (long)data[i] & 255L; + if (crcParams.reflectIn) { + curByte = reflect(curByte, 8); + } + + for(int j = 128; j != 0; j >>= 1) { + long bit = curValue & topBit; + curValue <<= 1; + if ((curByte & (long)j) != 0L) { + bit ^= topBit; + } + + if (bit != 0L) { + curValue ^= crcParams.polynomial; + } + } + } + + if (crcParams.reflectOut) { + curValue = reflect(curValue, crcParams.width); + } + + curValue ^= crcParams.finalXor; + return curValue & mask; + } + + public long init() { + return this.initValue; + } + + public long update(long curValue, byte[] chunk, int offset, int length) { + int i; + byte v; + if (this.crcParams.reflectIn) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)curValue) ^ v) & 255] ^ curValue >>> 8; + } + } else if (this.crcParams.width < 8) { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue << 8 - this.crcParams.width)) ^ v) & 255] ^ curValue << 8; + } + } else { + for(i = 0; i < length; ++i) { + v = chunk[offset + i]; + curValue = this.crctable[((byte)((int)(curValue >>> this.crcParams.width - 8)) ^ v) & 255] ^ curValue << 8; + } + } + + return curValue; + } + + public long update(long curValue, byte[] chunk) { + return this.update(curValue, chunk, 0, chunk.length); + } + + public long finalCRC(long curValue) { + long ret = curValue; + if (this.crcParams.reflectOut != this.crcParams.reflectIn) { + ret = reflect(curValue, this.crcParams.width); + } + + return (ret ^ this.crcParams.finalXor) & this.mask; + } + + public long calculateCRC(byte[] data) { + return this.calculateCRC(data, 0, data.length); + } + + public long calculateCRC(byte[] data, int offset, int length) { + long crc = this.init(); + crc = this.update(crc, data, offset, length); + return this.finalCRC(crc); + } + + public CRCUtil(CRCUtil.Parameters crcParams) { + this.crcParams = new CRCUtil.Parameters(crcParams); + this.initValue = crcParams.reflectIn ? reflect(crcParams.init, crcParams.width) : crcParams.init; + this.mask = (crcParams.width >= 64 ? 0L : 1L << crcParams.width) - 1L; + this.crctable = new long[256]; + byte[] tmp = new byte[1]; + CRCUtil.Parameters tableParams = new CRCUtil.Parameters(crcParams); + tableParams.init = 0L; + tableParams.reflectOut = tableParams.reflectIn; + tableParams.finalXor = 0L; + + for(int i = 0; i < 256; ++i) { + tmp[0] = (byte)i; + this.crctable[i] = calculateCRC(tableParams, tmp); + } + + } + + /** + * 8位 + * @param curValue + * @return + */ + public byte finalCRC8(long curValue) { + if (this.crcParams.width != 8) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (byte)((int)this.finalCRC(curValue)); + } + } + + /** + * 16位 + * @param curValue + * @return + */ + public short finalCRC16(long curValue) { + if (this.crcParams.width != 16) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (short)((int)this.finalCRC(curValue)); + } + } + + /** + * 32位 + * @param curValue + * @return + */ + public int finalCRC32(long curValue) { + if (this.crcParams.width != 32) { + throw new RuntimeException("CRC width mismatch"); + } else { + return (int)this.finalCRC(curValue); + } + } + + public static class Parameters { + private int width; + private long polynomial; + private boolean reflectIn; + private boolean reflectOut; + private long init; + private long finalXor; + public static final CRCUtil.Parameters CCITT = new CRCUtil.Parameters(16, 4129L, 65535L, false, false, 0L); + public static final CRCUtil.Parameters CRC16 = new CRCUtil.Parameters(16, 32773L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC16MODBUS = new CRCUtil.Parameters(16, 32773L, 65535L, true, true, 0L); + public static final CRCUtil.Parameters XMODEM = new CRCUtil.Parameters(16, 4129L, 0L, false, false, 0L); + public static final CRCUtil.Parameters XMODEM2 = new CRCUtil.Parameters(16, 33800L, 0L, true, true, 0L); + public static final CRCUtil.Parameters CRC32 = new CRCUtil.Parameters(32, 79764919L, 4294967295L, true, true, 4294967295L); + public static final CRCUtil.Parameters IEEE; + public static final CRCUtil.Parameters Castagnoli; + public static final CRCUtil.Parameters CRC32C; + public static final CRCUtil.Parameters Koopman; + public static final CRCUtil.Parameters CRC64ISO; + public static final CRCUtil.Parameters CRC64ECMA; + + public Parameters(int width, long polynomial, long init, boolean reflectIn, boolean reflectOut, long finalXor) { + this.width = width; + this.polynomial = polynomial; + this.reflectIn = reflectIn; + this.reflectOut = reflectOut; + this.init = init; + this.finalXor = finalXor; + } + + public Parameters(CRCUtil.Parameters orig) { + this.width = orig.width; + this.polynomial = orig.polynomial; + this.reflectIn = orig.reflectIn; + this.reflectOut = orig.reflectOut; + this.init = orig.init; + this.finalXor = orig.finalXor; + } + + public int getWidth() { + return this.width; + } + + public long getPolynomial() { + return this.polynomial; + } + + public boolean isReflectIn() { + return this.reflectIn; + } + + public boolean isReflectOut() { + return this.reflectOut; + } + + public long getInit() { + return this.init; + } + + public long getFinalXor() { + return this.finalXor; + } + + static { + IEEE = CRC32; + Castagnoli = new CRCUtil.Parameters(32, 517762881L, 4294967295L, true, true, 4294967295L); + CRC32C = Castagnoli; + Koopman = new CRCUtil.Parameters(32, 1947962583L, 4294967295L, true, true, 4294967295L); + CRC64ISO = new CRCUtil.Parameters(64, 27L, -1L, true, true, -1L); + CRC64ECMA = new CRCUtil.Parameters(64, 4823603603198064275L, -1L, true, true, -1L); + } + } +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java index da1cdf9..5e17761 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParser.java @@ -21,7 +21,7 @@ Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer); - Integer getTotalFilterLength(ProtocolConfig protocolConfig, ByteBuf byteBuf, Map protocolFieldConfigMap); + Integer totalFilterLength(ProtocolConfig protocolConfig, Map protocolFieldConfigMap); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java index e2730bf..cf18ade 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/FieldParserSupport.java @@ -25,7 +25,7 @@ //找到最大值=> 根据最大值计算业务数据下标 protected Integer calculatePosition(List fieldConfigList) { - String rex = "[0-9]+"; +// String rex = "[0-9]+"; Integer max = -1; for (AbstractFieldConfig fieldConfig : fieldConfigList) { if (!ObjectUtils.isEmpty(fieldConfig.getOriginPositionByte()) diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java index 272d927..7380bf1 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/parser/resolver/fields/DefaultProtocolFieldParser.java @@ -6,7 +6,6 @@ import com.casic.missiles.parser.resolver.FieldParserSupport; import com.casic.missiles.pojo.*; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.ObjectUtils; @@ -50,8 +49,10 @@ return fixedPropertyMap; } - //** 获取业务内容的byteBuf - // 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + /** + * 获取业务内容的byteBuf + * 固定字段列表=> 计算固定字段长度=> 计算业务内容起始位置=>结合总长度,计算业务内容长度=>得到业务内容 + */ @Override public Map getFrameStructBuf(List protocolFieldConfigs, ByteBuf buffer) { Map frameStructBufMap = new HashMap<>(); @@ -63,9 +64,9 @@ //计算固定长度最大长度 Integer maxFixedPosition = calculatePosition(protocolFieldConfigs); //计算数据报文内容 - frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition-1)); - frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition - 1, (totalLength - fixedLength))); - frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition-1+totalLength - fixedLength, fixedLength+1-maxFixedPosition)); + frameStructBufMap.put(BEFORE_BUSINESS_CONTENT, buffer.slice(0, maxFixedPosition)); + frameStructBufMap.put(AROUND_BUSINESS_CONTENT, buffer.slice(maxFixedPosition , (totalLength - fixedLength))); + frameStructBufMap.put(AFTER_BUSINESS_CONTENT, buffer.slice(maxFixedPosition+ totalLength - fixedLength, fixedLength- maxFixedPosition)); return frameStructBufMap; } @@ -73,12 +74,8 @@ * 获取过滤字段的长度 */ @Override - public Integer getTotalFilterLength(ProtocolConfig protocolConfig, - ByteBuf byteBuf, - Map protocolFieldConfigMap) { - if (ByteBufUtil.hexDump(byteBuf).equals("")) { - return 0; - } + public Integer totalFilterLength(ProtocolConfig protocolConfig, + Map protocolFieldConfigMap) { int totalFilterLength = 0; String filterFields = protocolConfig.getTotalLengthFilterFields(); try { @@ -96,8 +93,8 @@ return totalFilterLength; } catch (Exception ex) { log.error("报文确认分发阶段,获取报文总长度过滤长度异常,协议内容{},异常信息{}", JSONObject.toJSON(protocolConfig), ex.getMessage()); + return 0; } - return totalFilterLength; } } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java b/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java deleted file mode 100644 index 6236302..0000000 --- a/sensorhub-core/src/main/java/com/casic/missiles/parser/safe/impl/CRCUtil.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.casic.missiles.parser.safe.impl; - -public class CRCUtil { - - /** - * 将十六进制的字符串 求出 CRC 8 的 CRC_H CRC_L - */ - public static String getCRC8(String msg) { - //十六进制的字符串转换成字节数组 - byte[] bytes = hexStrToBinaryStr(msg); - //计算CRC8 -// String crc8ToStr = "" + Integer.toHexString(0xff & crc8); -// return crc8ToStr; - return null; - } - - /** - * 将十六进制的字符串转换成字节数组 - */ - public static byte[] hexStrToBinaryStr(String hexString) { - hexString = hexString.replaceAll(" ", ""); - if ((hexString.length() % 2) != 0) { - throw new IllegalArgumentException("长度不是偶数"); - } - int len = hexString.length(); - int index = 0; - byte[] bytes = new byte[len / 2]; - while (index < len) { - String sub = hexString.substring(index, index + 2); - bytes[index / 2] = (byte) Integer.parseInt(sub, 16); - index += 2; - } - return bytes; - } - - -} \ No newline at end of file diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java index 59dd260..6876fea 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/CombinedFieldConfigProvider.java @@ -60,7 +60,7 @@ * @return */ public List prepareParseField(RuleConfig ruleConfig) { - if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { + if (StringUtils.isEmpty(ruleConfig.getCombinedFieldIds())) { return null; } Map dataFieldIdMap = new HashMap<>(); diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java index 3750799..c0897c9 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/FieldConfigProvider.java @@ -61,7 +61,7 @@ * * @return */ - private List prepareParseField(RuleConfig ruleConfig) { + public List prepareParseField(RuleConfig ruleConfig) { if (StringUtils.isEmpty(ruleConfig.getDataFieldIds())) { return null; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java index 69fd684..274296f 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProcessorInstanceProvider.java @@ -45,7 +45,7 @@ fieldConfigMap.get(processorInstance.getSafeFieldId()).getFieldName(); if (!StringUtils.isEmpty(safeName)) { //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); ByteBuf plain = safeStrategy.decryption(ByteBufUtil.hexDump(bizDataContent)); return clearComplementZero(plain); } @@ -64,7 +64,7 @@ if (!StringUtils.isEmpty(safeName)) { fillFrameStructZero(replyBytes); //需要加密 - SafeStrategy safeStrategy = (SafeStrategy) ApplicationContextUtil.getBean(safeName); + SafeStrategy safeStrategy = SpringContextUtil.getBean(safeName); //加密密文 ciphertextBuf = safeStrategy.encryption(ByteBufUtil.hexDump(replyBytes)); return ciphertextBuf; diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java index 854b66e..3c12109 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/ProtocolFieldConfigProvider.java @@ -27,6 +27,7 @@ private static final String FIXED_FIELD_DS = "fixedFieldDs"; private static final String CONTENT_FIELD_DS = "contentFieldDs"; private static final String PROTOCOL_LENGTH = "protocolLength"; + private static final String PROTOCOL_FILER_LENGTH = "protocolFilerLength"; private static final String PROTOCOL_FIELD_ID = "protocolFieldId"; private static final String PROTOCOL_POSITION = "protocolPosition"; @@ -98,6 +99,9 @@ return null; } + /** + * @return 帧结构map集合 + */ public Map getFrameStructMap() { return frameStructMap; } @@ -128,6 +132,26 @@ return fixedPropertyMap; } + + /** + * 获取过滤字段的长度 + */ + public Integer getTotalFilterLength(ProtocolConfig protocolConfig) { + if (showSkip()) { + return null; + } + //获取缓存 + String catchKey = PROTOCOL_FILER_LENGTH + protocolConfig.getId(); + if (this.singleObjects.containsKey(catchKey)) { + return (Integer) singleObjects.get(catchKey); + } + FieldParser fieldParser = new DefaultProtocolFieldParser(); + Integer totalFilterLength = fieldParser.totalFilterLength(protocolConfig, getFixFieldConfigMap()); + this.singleObjects.put(catchKey, totalFilterLength); + return totalFilterLength; + } + + /** * 获取帧结构应有的总长度 */ @@ -142,9 +166,7 @@ } Integer appointFrameLength = getProtocolFieldValue(protocolConfig.getTotalLengthId(), byteBuf); if (appointFrameLength != null) { - //获取过滤的字段集合总长度 - FieldParser fieldParser = new DefaultProtocolFieldParser(); - Integer totalFilterLength = fieldParser.getTotalFilterLength(protocolConfig, byteBuf, getFixFieldConfigMap()); + Integer totalFilterLength = getTotalFilterLength(protocolConfig); //计算总长度 Integer totalLength = appointFrameLength + totalFilterLength; //加入缓存 @@ -204,6 +226,8 @@ } /** + * 对解密的内容进行尾部清零操作 + *

* 根据解析后的业务内容,通过存储的帧结构,创建完整完整的数据报文, * 这里对帧结构的可变报文没有处理,只是简单的组装,保证提前解密,为帧结构检验做准备 * @@ -236,7 +260,11 @@ return optionalProtocolFieldConfig.isPresent() ? optionalProtocolFieldConfig.get() : null; } - + /** + * list 转map + * + * @return + */ private Map getFixFieldConfigMap() { Map fixDataFieldMap = protocolFieldConfigs.stream() .collect( diff --git a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java index 13bbb09..1cb5514 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/provider/RuleConfigProvider.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; /** * @author cz @@ -23,9 +24,10 @@ } public RuleConfig getSendRuleConfig() { - return ruleConfigs.stream().filter( - ruleConfig -> ruleConfig.getScene().equals("1") - ).findFirst().get(); + Optional optionalRuleConfig=ruleConfigs.stream().filter( + ruleConfig -> ruleConfig.getScene() != null && ruleConfig.getScene().equals("1")).findFirst(); + + return optionalRuleConfig.isPresent()?optionalRuleConfig.get():null; } public RuleConfigProvider(Long protocolId) { diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java index 385bed0..f821a85 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/SensorhubReplier.java @@ -5,6 +5,7 @@ import com.casic.missiles.replier.command.AbstractBuildReplyCommand; import com.casic.missiles.util.ClazzUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import org.springframework.stereotype.Component; @@ -26,10 +27,10 @@ System.out.println("Client->Server:" + obj.toString()); if (obj instanceof ParseResult) { ParseResult parseResult = (ParseResult) obj; - System.out.println("Client->Server:" + JSON.toJSONString(parseResult)); //构建指令 AbstractBuildReplyCommand abstractBuildReplyCommand = ClazzUtil.getSubClassByOrder(AbstractBuildReplyCommand.class, parseResult.getReplyCommand()); ByteBuf replyByteBuf = abstractBuildReplyCommand.excute(parseResult); + System.out.println("返回的报文内容为" + ByteBufUtil.hexDump(replyByteBuf)); //进行回复 ctx.write(replyByteBuf); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java index 5205c62..f251156 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/DataReplyCommand.java @@ -1,6 +1,7 @@ package com.casic.missiles.replier.command; import cn.hutool.core.util.ObjectUtil; +import com.casic.missiles.parser.crc.CRC16; import com.casic.missiles.pojo.FieldConfig; import com.casic.missiles.pojo.ParseResult; import com.casic.missiles.pojo.ProtocolFieldConfig; @@ -8,6 +9,7 @@ import com.casic.missiles.provider.RuleConfigProvider; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -40,22 +42,24 @@ Map frameStructMap = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getFrameStructMap(); List protocolFieldConfigs = parseResult.getProtocolFactory().getProtocolFieldConfigProvider().getProtocolFieldConfigs(); Map fieldConfigsMap = parseResult.getRuleConfigFactory().getFieldConfigProvider().getFieldConfigsMap(); - if (ObjectUtil.isEmpty(frameStructMap)) { + RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); + //反构配置初始化,获取协议配置反构规则 + RuleConfig sendRuleConfig = ruleConfigProvider.getSendRuleConfig(); + if (ObjectUtil.isEmpty(frameStructMap) || sendRuleConfig == null) { return null; } - //反构配置初始化暂时不做,还不知道需要什么内容,默认的时间配置 - RuleConfigProvider ruleConfigProvider = parseResult.getProtocolFactory().getRuleConfigProvider(); - RuleConfig ruleConfig = ruleConfigProvider.getSendRuleConfig(); //填充时间内容 - buildBizFrameField(ruleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + buildBizFrameField(sendRuleConfig, replyBytes, fieldConfigsMap, parseResult.getRuleConfigFactory()); //判断是否有下发配置,获取内容,组建配置,通过设备编号去拿数据 - Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory().getCombinedFieldConfigProvider()); + Integer contentLength = buildBizConfigFieldFrame(replyBytes, fieldConfigsMap, parseResult.getDevcode(), parseResult.getRuleConfigFactory()); //加密分为,补零 加密报文 parseResult.getRuleConfigFactory().getDatagramEventProvider().buildSafeDatagram(replyBytes, fieldConfigsMap); +// pareFrameBuild + Map fixMap = calculatedFrameLength(contentLength, parseResult.getProtocolFactory()); //帧结构计算 - buildAfterFrameFixedField(frameStructMap.get(AFTER_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); - //帧结构计算 - buildPreFrameFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes); + replyBytes = buildFrameBeforeFixedField(frameStructMap.get(BEFORE_BUSINESS_CONTENT), protocolFieldConfigs, replyBytes, fixMap); + //组建CRC校验位 + replyBytes.writeBytes(CRC16.getCRC(ByteBufUtil.hexDump(replyBytes))); //返回对象 return replyBytes; } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java index fe2af11..d8c5ba4 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/command/ReplyCommandSupport.java @@ -7,11 +7,9 @@ import com.casic.missiles.enums.EngineExceptionEnum; import com.casic.missiles.enums.FixedPropertyEnum; import com.casic.missiles.exception.EngineException; -import com.casic.missiles.pojo.CombinedFieldConfig; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.ProtocolFieldConfig; -import com.casic.missiles.pojo.RuleConfig; -import com.casic.missiles.provider.CombinedFieldConfigProvider; +import com.casic.missiles.factory.AbstractProtocolConfigFactory; +import com.casic.missiles.factory.AbstractRuleConfigFactory; +import com.casic.missiles.pojo.*; import com.casic.missiles.replier.decorator.FieldReverseDecorator; import com.casic.missiles.util.RedisCommon; import com.casic.missiles.util.SpringContextUtil; @@ -20,9 +18,11 @@ import io.netty.buffer.ByteBufUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.dao.DataAccessException; +import org.bouncycastle.util.encoders.Hex; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,128 +36,190 @@ /** - * 根据配置,进行业务字段的反构 - * 根据字段配置,进行字段oid业务编号的字节组装。 - */ - private ByteBuf bizFieldByteBuf(Map fieldConfigsMap, - CombinedFieldConfig combinedFieldConfig, String filedValue) { - ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); - //先构建oid编号 - fragmentByte.writeBytes(combinedFieldConfig.getPrefixCode().getBytes(Charset.forName("ISO-8859-1"))); - //在构建长度,长度固定 - fragmentByte.writeByte(0x00); - //在构建长度,长度固定 - fragmentByte.writeByte(combinedFieldConfig.getLength()); - //然后构建业务值内容 - String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); - for (String dataFieldId : dataFieldIds) { - String currentConfigValue = ""; - //值的划分 - if (StringUtils.isNotEmpty(filedValue)) { - currentConfigValue = filedValue; - } - //长度单位划分 - FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); - if(ObjectUtils.isEmpty(fieldConfig)){continue;} - try { - FieldReverseDecorator.buildBuf(fieldConfig, currentConfigValue, fragmentByte); - } catch (DataAccessException dax) { - log.error("消息回复,反构业务内容出现异常,字段配置为{},异常信息{}", JSON.toJSON(fieldConfig), dax.getMessage()); - } - } - return fragmentByte; - } - - /** * 组合字段解析,单字段解析 * 构建业务字段的byteBuf * 关于多个业务意义的键拼接为一个字节 */ protected void buildBizFrameField(RuleConfig ruleConfig, ByteBuf replyBytes, Map fieldConfigsMap, - CombinedFieldConfigProvider combinedFieldConfigProvider) { + AbstractRuleConfigFactory configFactory) { String combinedFieldIds = ruleConfig.getCombinedFieldIds(); Assert.isFalse(StringUtils.isEmpty(combinedFieldIds), () -> { throw new EngineException(EngineExceptionEnum.COMBINED_LENGTH_FIELD_NULL); }); - List combinedFieldConfigs = combinedFieldConfigProvider.prepareParseField(ruleConfig); + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().prepareParseField(ruleConfig); + List fieldConfigs = configFactory.getFieldConfigProvider().prepareParseField(ruleConfig); for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, null)); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, null)); } + FieldReverseDecorator.simpleField(fieldConfigs, null, replyBytes); } /** - * 构建redis配置报文 + * 取redis相关配置的值,查询相关的配置进行构建返回的帧业务内容 * * @return */ - protected Integer buildBizConfigFieldFrame(ByteBuf - replyBytes, Map fieldConfigsMap, String devcode, CombinedFieldConfigProvider - combinedFieldConfigProvider) { + protected Integer buildBizConfigFieldFrame(ByteBuf replyBytes, Map fieldConfigsMap, String devcode, + AbstractRuleConfigFactory configFactory) { RedisCommon redisCommon = SpringContextUtil.getBean(RedisCommon.class); //通过设备编号获取查询对应的下发配置 - Map bizDataMap = redisCommon.getMsg(devcode); + Map bizDataMap = redisCommon.getMsg(devcode); // 配置为空则直接返回值 if (ObjectUtils.isEmpty(bizDataMap)) { return ByteBufUtil.hexDump(replyBytes).length() / 2; } - //配置不为空,则进行查询配置 - List combinedFieldConfigs = combinedFieldConfigProvider.getCombinedFieldConfigList().stream().filter( + //配置不为空,则进行查询组合字段配置 + List combinedFieldConfigs = configFactory.getCombinedFieldConfigProvider().getCombinedFieldConfigList().stream().filter( e -> bizDataMap.containsKey(e.getDataFieldName())).collect(Collectors.toList()); + //配置不为空,则进行查询简单字段配置 + List fieldConfigs = configFactory.getFieldConfigProvider().getFieldConfigs().stream().filter( + e -> bizDataMap.containsKey(e.getFieldName())).collect(Collectors.toList()); // 根据配置填充,返回数据长度 for (CombinedFieldConfig combinedFieldConfig : combinedFieldConfigs) { - replyBytes.writeBytes(bizFieldByteBuf(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); + replyBytes.writeBytes(FieldReverseDecorator.combinedField(fieldConfigsMap, combinedFieldConfig, bizDataMap.get(combinedFieldConfig.getDataFieldName()))); } + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, replyBytes); return ByteBufUtil.hexDump(replyBytes).length() / 2; } - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildPreFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> !ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); - } - - // 1、以起始字段解析 时间,内容解析字段 - // 关于多个业务意义的键拼接为一个字节的暂不处理 - protected void buildAfterFrameFixedField(ByteBuf - frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { - List preFixFieldList = protocolFieldConfigs.stream() - .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) - .collect(Collectors.toList()); - buildFixedFieldCommand(frameStructByeBuf, replyBytes, preFixFieldList); + /** + * 计算帧长度 + */ + protected Map calculatedFrameLength(Integer contentLength, AbstractProtocolConfigFactory protocolFactory) { + Integer totalFilterLength = protocolFactory.getProtocolFieldConfigProvider().getTotalFilterLength(protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig()); + Integer frameLength = contentLength + totalFilterLength; + Long totalLengthId = protocolFactory.getProtocolConfigProvider().getCurrentProtocolConfig().getTotalLengthId(); + ProtocolFieldConfig protocolFieldConfig = protocolFactory.getProtocolFieldConfigProvider().getFieldConfigById(totalLengthId); + Map fixMap = new HashMap(); + fixMap.put(protocolFieldConfig.getFieldName(), frameLength.toString()); + return fixMap; } - private void buildFixedFieldCommand(ByteBuf frameStructByeBuf, ByteBuf - replyBytes, List fixFieldList) { - String dynamicContent = ""; - Integer dynamicBitData = 0; - String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); - for (ProtocolFieldConfig fieldConfig : fixFieldList) { - if (StringUtils.isNotEmpty(fieldConfig.getIsReplyFix())) { - //前后没有变化,直接截取填充 - String fieldContent = fixContent.substring(fieldConfig.getOriginPositionByte(), fieldConfig.getOriginPositionByte() + fieldConfig.getOffsetLength()); - replyBytes.writeBytes(fieldContent.getBytes(Charset.forName("ISO-8859-1"))); - } else { - //前后发生变化,根据规则和字典表进行数据的构建 - String fieldChangeContent = null; - if (fieldConfig.getOffsetUnit().equals("bit")) { - dynamicBitData += fieldConfig.getOffsetLength(); - if (dynamicBitData % 8 == 0) { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - dynamicBitData = 0; - dynamicContent = ""; - } else { - } - } else { - replyBytes.writeBytes(fieldChangeContent.getBytes(Charset.forName("ISO-8859-1"))); - } + /** + * 构建业务前固定内容 + * 1、筛选业务内容前固定配置 + * 2、 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected ByteBuf buildFrameBeforeFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes, Map fixMap) { + //通过起始位置byte不为空进行前固定配置的筛选 + List preFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isNotEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + //根据起始位置点进行排序 + List sortPreFixFieldList = preFixFieldList + .stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + List protocolFieldConfigList = null; + int index = 0; + //设置组合配置,以byte为整依据设置 + while (index < sortPreFixFieldList.size()) { + protocolFieldConfigList = new ArrayList<>(); + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + while (++index < sortPreFixFieldList.size() && !checkIsWholeByte(protocolFieldConfigList)) { + protocolFieldConfigList.add(sortPreFixFieldList.get(index)); + } + sortPreFixFieldLists.add(protocolFieldConfigList); + } + //进行构建下发名称,构建内容 + ByteBuf headBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, fixMap); + //写入已经存在的回复的业务内容 + headBuf.writeBytes(replyBytes); + //将组合得到的帧作为结果进行返回 + return headBuf; + } + + /** + * 判断该协议集合的偏移量bit组合是否是完整的以byte为整数的数据集合 + * + * @param protocolFieldConfigList 预处理集合 + * @return 真假 + */ + private boolean checkIsWholeByte(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); } } + return bitFixedLength % 8 == 0; } + + /** + * 构建crc校验位,暂时不处理 + * + * @param frameStructByeBuf + * @param protocolFieldConfigs + * @param replyBytes + */ + protected void buildFrameTailFixedField(ByteBuf frameStructByeBuf, List protocolFieldConfigs, ByteBuf replyBytes) { + //筛选 + List tailFixFieldList = protocolFieldConfigs.stream() + .filter(fieldConfig -> ObjectUtil.isEmpty(fieldConfig.getOriginPositionByte())) + .collect(Collectors.toList()); + List> sortPreFixFieldLists = new ArrayList<>(); + sortPreFixFieldLists.add(tailFixFieldList); + //构建内容 + ByteBuf tailBuf = buildFixedFieldCommand(frameStructByeBuf, sortPreFixFieldLists, null); + //填充 + replyBytes.writeBytes(tailBuf); + } + + /** + * 1、判断配置的协议字段是否有变化, + * (1)没有变化则直接使用 + * (2)有变化则进行运算求值组合 + */ + private ByteBuf buildFixedFieldCommand(ByteBuf frameStructByeBuf, List> sortPreFixFieldLists, Map bizDataMap) { + ByteBuf fixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + frameStructByeBuf.resetReaderIndex(); + String fixContent = ByteBufUtil.hexDump(frameStructByeBuf); + //前后发生变化,根据规则和字典表进行数据的构建 + for (List fieldConfigs : sortPreFixFieldLists) { + ByteBuf combinedFixedByteBuf = ByteBufAllocator.DEFAULT.buffer(); + try { + String fieldContent = fixContent.substring(fieldConfigs.get(0).getOriginPositionByte() * 2, fieldConfigs.get(0).getOriginPositionByte() * 2 + calculateOffset(fieldConfigs) * 2); + combinedFixedByteBuf.writeBytes(Hex.decode(fieldContent)); + for (ProtocolFieldConfig fieldConfig : fieldConfigs) { + if (StringUtils.isEmpty(fieldConfig.getIsReplyFix()) || !"1".equals(fieldConfig.getIsReplyFix())) { + fieldConfigs = new ArrayList<>(); + fieldConfigs.add(fieldConfig); + + FieldReverseDecorator.simpleField(fieldConfigs, bizDataMap, fixedByteBuf); + } + } + } catch (Exception ex) { + log.error("异常,异常配置{},异常信息{}", JSON.toJSON(fieldConfigs), ex); + } + fixedByteBuf.writeBytes(combinedFixedByteBuf); + } + fixedByteBuf.writeBytes(Hex.decode(fixContent)); + return fixedByteBuf; + } + + /** + * 计算完整的组合byte集合的偏移值,以byte为单位 + */ + private Integer calculateOffset(List protocolFieldConfigList) { + Integer bitFixedLength = 0; + Integer byteFixedLength = 0; + for (ProtocolFieldConfig fieldConfig : protocolFieldConfigList) { + if ("bit".equals(fieldConfig.getOffsetUnit())) { + bitFixedLength += fieldConfig.getOffsetLength(); + } else { + byteFixedLength += fieldConfig.getOffsetLength(); + } + } + return byteFixedLength + bitFixedLength / 8; + } + + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java new file mode 100644 index 0000000..eeb7783 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/AbstractValueTypeResolver.java @@ -0,0 +1,12 @@ +package com.casic.missiles.replier.decorator; + +import io.netty.buffer.ByteBuf; + +/** + * @author cz + */ +public interface AbstractValueTypeResolver { + + void invoke(Integer totalLength,Object currentValue, ByteBuf byteBuf); + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java index e041dd8..21fe14c 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/BitFieldDecorator.java @@ -1,20 +1,15 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.casic.missiles.parser.resolver.ByteResolver; -import com.casic.missiles.pojo.ByteResolverParam; -import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.util.SpringContextUtil; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -23,7 +18,7 @@ @Slf4j public class BitFieldDecorator { - public static void buildBitBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildBitBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { Object fieldValue = new Object(); try { Integer originPosition = Integer.valueOf(fieldConfig.getOriginPositionByte()); @@ -31,56 +26,62 @@ Map env2 = new HashMap(); String replyRuleExpression = fieldConfig.getReplyRule(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); } - //bit - - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); - } - dynamicContent.writeBytes(keyBytes); - - byte fields = 0x00; - //计算字节所占的比例位置 - Integer offsetByte = (fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) / 8; - if ((fieldConfig.getOffsetLength() + fieldConfig.getOriginPositionBit()) % 8 != 0) { - offsetByte++; - } - //将所需的bit字段转换成二进制,然后截取计算 - int visitIndex = offsetByte; + //进行填充赋值 + String severBinary = Integer.toBinaryString(Integer.valueOf(String.valueOf(currentConfigValue))); String binaryStr = ""; - //下标是由0开始,所以先- - while (--visitIndex > -1) { - fields = byteBuf.getByte(originPosition + visitIndex); - binaryStr = getBinaryStrFromByte(fields) + binaryStr; + //取关键的值byteBuf + if (originPosition != 0) { + Byte fields = dynamicContent.getByte(dynamicContent.writerIndex()); + binaryStr = getBinaryStrFromByte(fields); + binaryStr = binaryStr.substring(0, originPosition); } - binaryStr = binaryStr.substring(fieldConfig.getOriginPositionBit(), fieldConfig.getOriginPositionBit() + fieldConfig.getOffsetLength()); - fieldValue = Integer.parseInt(binaryStr, 2); - if (StringUtils.isEmpty(fieldConfig.getRuleJson())) { - return fieldValue; + binaryStr += severBinary; + while (binaryStr.length() % 8 != 0) { + binaryStr += "0"; } - List ruleMapList = JSONArray.parseArray(fieldConfig.getRuleJson(), Map.class); - int i = 0; - //字节归并到一起=>继续根据规则进行判断 - while (i < ruleMapList.size()) { - String vaildRange = String.valueOf(ruleMapList.get(i).get("vaildRange")); - ByteResolver byteResolverBean = SpringContextUtil.getBean(vaildRange); - String ruletypeId = String.valueOf(ruleMapList.get(i).get("ruleTypeId")); - ByteResolverParam byteResolverParam = ByteResolverParam.builder() - .index(null) - .value(fieldValue) - .ruletypeId(ruletypeId).build(); - fieldValue = byteResolverBean.resolveOperationRule(byteResolverParam); - i++; - } + byte[] bytes = getBytesFromBinaryStr(binaryStr); + //string 转化成byte + dynamicContent.writeBytes(bytes, dynamicContent.writerIndex() - 1, binaryStr.length() % 8); System.out.println(JSON.toJSON(fieldValue)); } catch (RuntimeException ex) { log.error("字段解析bit位出现异常,解析内容为{},解析规则内容为{},异常信息为{}", fieldValue, JSONObject.toJSON(fieldConfig), ex.getMessage()); } } + + + private static byte[] getBytesFromBinaryStr(String binaryStr) { + byte[] bytes = new byte[binaryStr.length() / 8]; + for (int i = 0; i < binaryStr.length() / 8; i++) { + byte currentStrByte = Byte.parseByte(binaryStr.substring(i * 8, (i + 1) * 8), 2); + bytes[i] = currentStrByte; + } + return bytes; + } + + /** + * 把byte转化成2进制字符串 + */ + private static String getBinaryStrFromByte(byte value) { + String result = ""; + byte a = value; + for (int i = 0; i < 8; i++) { + byte c = a; + a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。 + a = (byte) (a << 1); + if (a == c) { + result = "0" + result; + } else { + result = "1" + result; + } + a = (byte) (a >> 1); + } + return result; + } + } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java index fdc2187..9b8c0aa 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/ByteFieldDecorator.java @@ -1,12 +1,12 @@ package com.casic.missiles.replier.decorator; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; -import com.casic.missiles.pojo.FieldConfig; +import com.casic.missiles.pojo.AbstractFieldConfig; import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; import java.util.HashMap; import java.util.Map; @@ -25,35 +25,35 @@ * @param currentConfigValue * @param dynamicContent */ - public static void buildByteBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + public static void buildByteBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { if (StringUtils.isEmpty(fieldConfig.getReplyRule())) { defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } else { - customizeDecorator(fieldConfig, currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); + customizeDecorator(fieldConfig,currentConfigValue, dynamicContent, fieldConfig.getReplyRule()); } } - private static void defaultDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { - byte[] keyBytes = Hex.decode(currentConfigValue); - while (fieldConfig.getOffsetLength() > keyBytes.length) { - dynamicContent.writeByte(0); + private static void defaultDecorator(AbstractFieldConfig fieldConfig, Object currentValue, ByteBuf dynamicContent) { + AbstractValueTypeResolver valueTypeResolver = new DefaultValueTypeResolver(); + if (currentValue instanceof Long) { + System.out.println("增添Long类别"); } - dynamicContent.writeBytes(keyBytes); + valueTypeResolver.invoke(fieldConfig.getOffsetLength(), currentValue, dynamicContent); } //字段解析构建器(针对字节单位的) //转化数组=>去查询规则=> 获取bean,规则语句id,对范围进行过滤 =>直到规则结束或者遇到字节归并规则进行字节数据统一 // 字节归并结束或者规则结束=>继续根据规则进行判断 - private static void customizeDecorator(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { + private static void customizeDecorator(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent, String replyRuleExpression) { try { Map env2 = new HashMap(); //如果当前实际的值不存在的时候,直接进行rule执行,不需要 - if (StringUtils.isNotEmpty(currentConfigValue)) { + if (ObjectUtils.isNotEmpty(currentConfigValue)) { String targetStr = replyRuleExpression.substring(replyRuleExpression.indexOf("(") + 1, replyRuleExpression.indexOf(")")); env2.put(targetStr, currentConfigValue); } - currentConfigValue = String.valueOf(AviatorEvaluator.execute(replyRuleExpression, env2)); - buildByteBuf(fieldConfig, currentConfigValue, dynamicContent); + currentConfigValue = AviatorEvaluator.execute(replyRuleExpression, env2); + defaultDecorator(fieldConfig, currentConfigValue, dynamicContent); } catch (RuntimeException ex) { log.error("自定义字段解析byte位出现异常,配置为为{},解析表达式为{},异常信息为{}", JSONObject.toJSON(fieldConfig), replyRuleExpression, ex.getMessage()); } diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java new file mode 100644 index 0000000..15cfd62 --- /dev/null +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/DefaultValueTypeResolver.java @@ -0,0 +1,33 @@ +package com.casic.missiles.replier.decorator; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import io.netty.buffer.ByteBuf; +import org.bouncycastle.util.encoders.Hex; + +/** + * 默认处理器,处理的是String 字符串类型的 + * + * @author cz + */ +public class DefaultValueTypeResolver implements AbstractValueTypeResolver { + + @Override + public void invoke(Integer totalLength, Object currentObjectValue, ByteBuf byteBuf) { + String currentValue = (String) currentObjectValue; + byte[] keyBytes = null; + Integer fillIndex = 0; + if (StringUtils.isNotEmpty(currentValue)) { + keyBytes = Hex.decode(currentValue); + fillIndex = currentValue.length() / 2; + } + if (fillIndex != 0) { + while (totalLength > fillIndex) { + byteBuf.writeByte(0); + fillIndex++; + } + byteBuf.writeBytes(keyBytes); + } + } + + +} diff --git a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java index 256b156..fdb6c81 100644 --- a/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java +++ b/sensorhub-core/src/main/java/com/casic/missiles/replier/decorator/FieldReverseDecorator.java @@ -1,27 +1,99 @@ package com.casic.missiles.replier.decorator; -import cn.hutool.core.util.ObjectUtil; -import com.alibaba.fastjson.JSONArray; -import com.casic.missiles.parser.resolver.fields.BitFieldParser; -import com.casic.missiles.parser.resolver.fields.ByteFieldParser; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; +import com.casic.missiles.pojo.AbstractFieldConfig; +import com.casic.missiles.pojo.CombinedFieldConfig; import com.casic.missiles.pojo.FieldConfig; -import com.casic.missiles.pojo.NodeDecoratorParm; -import com.casic.missiles.util.SpringContextUtil; +import com.googlecode.aviator.AviatorEvaluator; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** + * 把业务内容输出到准确的报文字段 + * * @author cz */ +@Slf4j public class FieldReverseDecorator { + + /** + * 完整的数组操作 + * 根据配置,进行业务字段的反构 + * 根据字段配置,进行字段oid业务编号的字节组装。 + */ + public static ByteBuf combinedField(Map fieldConfigsMap, + CombinedFieldConfig combinedFieldConfig, Object filedValue) { + if(ObjectUtils.isEmpty(combinedFieldConfig)){ + return null; + } + ByteBuf fragmentByte = ByteBufAllocator.DEFAULT.buffer(); + //先构建oid编号 + fragmentByte.writeBytes(Hex.decode(combinedFieldConfig.getPrefixCode())); + //在构建长度,长度固定 + fragmentByte.writeByte(0x00); + //在构建长度,长度固定 + fragmentByte.writeByte(combinedFieldConfig.getLength()); + //然后构建业务值内容 + String[] dataFieldIds = combinedFieldConfig.getDataFieldIds().split(","); + Map bizDataMap = new HashMap<>(); + List fieldConfigs = new ArrayList<>(); + for (String dataFieldId : dataFieldIds) { + FieldConfig fieldConfig = fieldConfigsMap.get(Long.valueOf(dataFieldId)); + fieldConfigs.add(fieldConfig); + bizDataMap.put(fieldConfig.getFieldName(), filedValue); + } + simpleField(fieldConfigs, bizDataMap, fragmentByte); + return fragmentByte; + } + + + public static ByteBuf simpleField(List fieldConfigs, Map bizDataMap, ByteBuf fragmentByte) { + if(CollectionUtils.isEmpty(fieldConfigs)){ + return null; + } + //根据起始点排序 + List sortFieldConfigs = fieldConfigs.stream() + .sorted((e1, e2) -> e1.getOriginPositionByte().compareTo(e2.getOriginPositionByte())).collect(Collectors.toList()); + Object prepareData = null; + //校验是不是一个完整ByteBuf数组 + if (checkOutFrame(sortFieldConfigs)) { + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (bizDataMap != null && bizDataMap.containsKey(sortFieldConfig.getFieldName())) { + prepareData = bizDataMap.get(sortFieldConfig.getFieldName()); + } + buildBuf(sortFieldConfig, prepareData, fragmentByte); + } + } + return fragmentByte; + } + + private static String ruleValue(String filedValue, String ruleExpression) { + Map env2 = new HashMap(); + //如果当前实际的值不存在的时候,直接进行rule执行,不需要 + if (StringUtils.isNotEmpty(filedValue)) { + String targetStr = ruleExpression.substring(ruleExpression.indexOf("(") + 1, ruleExpression.indexOf(")")); + env2.put(targetStr, filedValue); + } + String currentConfigValue = String.valueOf(AviatorEvaluator.execute(ruleExpression, env2)); + return currentConfigValue; + } + // 处理非完整的字节字段处理方式,动态的业务字段和静态的业务字段 // (1)静态的业务字段是字典里面可以配置的 // (2)动态的业务字段是通过规则生成的 - public static void buildBuf(FieldConfig fieldConfig, String currentConfigValue, ByteBuf dynamicContent) { + private static void buildBuf(AbstractFieldConfig fieldConfig, Object currentConfigValue, ByteBuf dynamicContent) { //待优化 if (fieldConfig.getOffsetUnit().equals("bit")) { BitFieldDecorator.buildBitBuf(fieldConfig, currentConfigValue, dynamicContent); @@ -30,13 +102,20 @@ } } - private static NodeDecoratorParm initNodeDecoratorRuleParam(String sceneConent, String dynamicContent, String ruletypeId) { - NodeDecoratorParm nodeDecoratorParm = NodeDecoratorParm.builder() - .contents(sceneConent) - .dynamicContent(dynamicContent) - .ruletypeId(ruletypeId) - .build(); - return nodeDecoratorParm; + /** + * 校验是一个完整的操作 + * + * @param sortFieldConfigs + * @return + */ + private static Boolean checkOutFrame(List sortFieldConfigs) { + Integer bitFixedLength = 0; + for (AbstractFieldConfig sortFieldConfig : sortFieldConfigs) { + if (sortFieldConfig.getOffsetUnit().equals("bit")) { + bitFixedLength += sortFieldConfig.getOffsetLength(); + } + } + return bitFixedLength % 8 == 0; } } diff --git a/sensorhub-support/pom.xml b/sensorhub-support/pom.xml index 5ceecfe..3b69a91 100644 --- a/sensorhub-support/pom.xml +++ b/sensorhub-support/pom.xml @@ -49,6 +49,13 @@ 0.9.10 + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + \ No newline at end of file diff --git a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java index 00a5710..45fb908 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/enums/FixedPropertyEnum.java @@ -6,7 +6,7 @@ */ public interface FixedPropertyEnum { - String FIXED_POSITION = "fixedPosition"; + String FIXED_POSITION = "fixedPosition"; String TOTAL_LENGTH = "totalLength"; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java index 4886e8b..eacb937 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/AbstractFieldConfig.java @@ -13,6 +13,8 @@ * 按照字段评估进行字段解析 */ private String ruleJson; + + private String replyRule; /** * 起始位置(单位byte) */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java index 00b6e64..1b6ffaf 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/FieldConfig.java @@ -20,11 +20,6 @@ * 协议配置id */ private Long ruleId; - - /** - * 回复规则 - */ - private String replyRule; /** * 回复规则 */ diff --git a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java index 9547040..33b95c1 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/pojo/ProtocolFieldConfig.java @@ -27,10 +27,6 @@ * 上传下发是否有变化, 没有变化,可以直接组装 */ private String isReplyFix; - /** - * 回复规则 - */ - private String replyRule; private String ownerId; private Date createTime; diff --git a/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java b/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java index 6e80779..45c50eb 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/util/AviatorUtil.java @@ -6,11 +6,13 @@ import com.googlecode.aviator.runtime.function.FunctionUtils; import com.googlecode.aviator.runtime.type.AviatorBigInt; import com.googlecode.aviator.runtime.type.AviatorObject; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import org.bouncycastle.util.encoders.Hex; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.nio.charset.Charset; +import java.util.*; public class AviatorUtil { @@ -23,16 +25,17 @@ // bytStrList.add(query[i]); // } //Original String -// String string = "hello world"; - List list =new ArrayList<>(); - Map env2 = new HashMap(); - for (int i = 0; i < 2; i++) { - list.add("2"); - } - env2.put("list",list); - AviatorEvaluator.addFunction(new MinFunction()); - Object values = String.valueOf(AviatorEvaluator.execute("sum(list)", env2)); - int i = 0; +// tring string = "hello world"; +// List list = new ArrayList<>(); +// Map env2 = new HashMap(); +// for (int i = 0; i < 2; i++) { +// list.add("2"); +// } +// env2.put("list", list); + + Object values = String.valueOf(AviatorEvaluator.execute("dateTime=date_to_string(sysdate(),'yyyyMMdd');string.replace_first(dateTime,\"2\",\"0\")")); + System.out.println(values); +// int i = 0; } static class MinFunction extends AbstractFunction { diff --git a/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java b/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java index b869201..690ff82 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/util/ClazzUtil.java @@ -6,7 +6,10 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + /** * @author cz diff --git a/sensorhub-support/src/main/java/com/casic/missiles/util/RedisCommon.java b/sensorhub-support/src/main/java/com/casic/missiles/util/RedisCommon.java index 99ba2e6..68e2481 100644 --- a/sensorhub-support/src/main/java/com/casic/missiles/util/RedisCommon.java +++ b/sensorhub-support/src/main/java/com/casic/missiles/util/RedisCommon.java @@ -26,7 +26,7 @@ private String configPrefix; - public HashMap getMsg(String key) { + public HashMap getMsg(String key) { // 判断上次保存时间,如果到期(key失效),再保存新的 String timeStampKey = configPrefix + key; Object dataJson = redisTemplate.opsForValue().get(timeStampKey);