diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java index 4d39c869e..7a8f575f0 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java +++ b/jsowell-common/src/main/java/com/jsowell/common/util/YKCUtils.java @@ -2,14 +2,19 @@ package com.jsowell.common.util; import com.google.common.collect.ImmutableMap; import com.google.common.primitives.Bytes; +import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.Constants; +import com.jsowell.common.core.domain.ykc.YKCBaseMessage; +import com.jsowell.common.core.domain.ykc.YKCDataProtocol; import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode; +import com.jsowell.common.core.redis.StaticRedisCache; +import com.jsowell.common.enums.ykc.PileChannelEntity; import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.exception.BusinessException; +import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; -import java.util.Arrays; import java.util.Map; @Slf4j @@ -64,13 +69,116 @@ public class YKCUtils { if (sourceCRC.equalsIgnoreCase(targetCRC) || sourceCRC.equalsIgnoreCase(crc)) { return true; } - log.error("CRC校验不通过, 源crc:{}, 计算得出crc:{}, 老crc计算:{}, 高低位反转后crc:{}, 帧类型:{}, 帧名称:{},报文:{}, msg:{}" + log.error("CRC校验不通过, 源crc:{}, 计算得出crc:{}, 老crc计算:{}, 高低位反转后crc:{}, 帧类型:{}, 帧名称:{}, 报文:{}" , sourceCRC, targetCRC, oldTargetCRC, crc, YKCUtils.frameType2Str(frameType), - YKCFrameTypeCode.getFrameTypeStr(YKCUtils.frameType2Str(frameType)), - BytesUtil.binary(msg, 16), Arrays.toString(msg)); + YKCFrameTypeCode.getFrameTypeStr(YKCUtils.frameType2Str(frameType)), BytesUtil.binary(msg, 16)); return false; } + /** + * 获取结果报文 + * @param ykcDataProtocol + * @param messageBody + * @return + */ + public static byte[] getResult(YKCDataProtocol ykcDataProtocol, byte[] messageBody) { + // 起始标志 + byte[] head = ykcDataProtocol.getHead(); + + // 序列号域 + byte[] serialNumber = ykcDataProtocol.getSerialNumber(); + + // 加密标志 + byte[] encryptFlag = ykcDataProtocol.getEncryptFlag(); + + // 请求帧类型 + byte[] requestFrameType = ykcDataProtocol.getFrameType(); + + // 应答帧类型 + byte[] responseFrameType = YKCFrameTypeCode.PlatformAnswersRelation.getResponseFrameTypeBytes(requestFrameType); + + // 数据域 值为“序列号域+加密标志+帧类型标志+消息体”字节数之和 + byte[] dataFields = Bytes.concat(serialNumber, encryptFlag, responseFrameType, messageBody); + + // 计算crc: 从序列号域到数据域的 CRC 校验 + int crc16 = CRC16Util.calcCrc16(dataFields); + + return Bytes.concat(head, BytesUtil.intToBytes(dataFields.length, 1), dataFields, BytesUtil.intToBytes(crc16)); + } + + public static byte[] getResult(YKCBaseMessage message, byte[] messageBody) { + // 起始标志 + String header = message.getHeader(); + byte[] headBytes = BytesUtil.stringToHexBytes(header, 1); + + // 序列号域 + int serialNumber = message.getSerialNumber(); + byte[] serialNumberBytes = BytesUtil.intToBytesLittle(serialNumber, 2); + + // 加密标志 + int encryptFlag = message.getEncryptFlag(); + byte[] encryptFlagBytes = BytesUtil.intToBytesLittle(encryptFlag, 1); + + // 请求帧类型 + String frameType = message.getFrameType(); + byte[] requestFrameTypeBytes = BytesUtil.hexString2Bytes(frameType.replace("0x", "")); + + // 应答帧类型 + byte[] responseFrameTypeBytes = YKCFrameTypeCode.PlatformAnswersRelation.getResponseFrameTypeBytes(requestFrameTypeBytes); + + // 数据域 值为“序列号域+加密标志+帧类型标志+消息体”字节数之和 + byte[] dataFields = Bytes.concat(serialNumberBytes, encryptFlagBytes, responseFrameTypeBytes, messageBody); + + // 计算crc: 从序列号域到数据域的 CRC 校验 + int crc16 = CRC16Util.calcCrc16(dataFields); + + return Bytes.concat(headBytes, BytesUtil.intToBytes(dataFields.length, 1), dataFields, BytesUtil.intToBytes(crc16)); + } + + public static void main(String[] args) { + String type = "0x3B"; + System.out.println(type); + byte[] bytes = BytesUtil.hexString2Bytes(type.replace("0x", "")); + System.out.println(YKCUtils.frameType2Str(bytes)); + + } + + /** + * 保存桩最后链接到平台的时间 + * @param pileSn 桩编号 + */ + public static void saveLastTimeAndCheckChannel(String pileSn, ChannelHandlerContext ctx) { + String redisKey = CacheConstants.PILE_LAST_CONNECTION + pileSn; + StaticRedisCache.staticRedisCache.setCacheObject(redisKey, DateUtils.getDateTime(), CacheConstants.cache_expire_time_30d); + + // 保存桩号和channel的关系 + PileChannelEntity.checkChannel(pileSn, ctx); + } + + /** + * 阻止重复帧, 并返回是否重复 + * 判断逻辑:相同的channelId和序列号的请求,30秒内只允许一次 + * @return true 重复 + */ + public static boolean verifyTheDuplicateRequest(YKCDataProtocol ykcDataProtocol, ChannelHandlerContext ctx) { + // 获取序列号域 + int serialNumber = BytesUtil.bytesToIntLittle(ykcDataProtocol.getSerialNumber()); + // 获取channelId + String channelId = ctx.channel().id().asShortText(); + String redisKey = "Request_" + channelId + "_" + serialNumber; + Boolean result = StaticRedisCache.staticRedisCache.setnx(redisKey, ykcDataProtocol.getHEXString(), 30); + // result返回false说明没有设置成功,就是说已经有相同请求了,所以返回true重复 + return !result; + } + + /** + * 从消息中获取pileSn + */ + public static byte[] getPileSnBytes(String pileSn) { + // 通过pileSN转换为byte[] + return BytesUtil.hexStringToByteArray(pileSn); + } + /** * 转换电压电流以及起始soc * 精确到小数点后一位;待机置零 @@ -95,7 +203,7 @@ public class YKCUtils { * @return */ public static String convertDecimalPoint(byte[] bytes, int scale) { - // 转换为int + // 转换为int int i = BytesUtil.bytesToIntLittle(bytes); // 使用BigDecimal BigDecimal bigDecimal = new BigDecimal(i); @@ -229,12 +337,4 @@ public class YKCUtils { return map.get("connectorCode"); } - public static void main(String[] args) { - String pileConnectorCode = "8800000000000201"; - // pileConnectorCode = "1327388103"; - String pileSn = YKCUtils.getPileSn(pileConnectorCode); - System.out.println(pileSn); - String connectorCode = YKCUtils.getConnectorCode(pileConnectorCode); - System.out.println(connectorCode); - } }