Browse Source

1. 完善字节处理工具类
2. 新增CRC校验工具
3. 新增分包工具类

王育民 5 years ago
parent
commit
716367dc7e

+ 76 - 0
serialport/src/main/java/cn/minbb/serialport/utils/ByteUtil.java

@@ -1,7 +1,11 @@
 package cn.minbb.serialport.utils;
 
+import java.nio.ByteBuffer;
+
 public class ByteUtil {
 
+    private static ByteBuffer byteBuffer = ByteBuffer.allocate(8);
+
     /**
      * 拼接两个 Byte 数组
      *
@@ -15,4 +19,76 @@ public class ByteUtil {
         System.arraycopy(data2, 0, data3, data1.length, data2.length);
         return data3;
     }
+
+    public static byte intToByte(int intValue) {
+        return (byte) intValue;
+    }
+
+    public static int byteToInt(byte byteValue) {
+        // Java 总是把 byte 当做有符处理;我们可以通过将其和 0xFF 进行二进制与得到它的无符值
+        return byteValue & 0xFF;
+    }
+
+    public static int byteArrayToInt(byte[] byteArray) {
+        return byteArray[3] & 0xFF | (byteArray[2] & 0xFF) << 8 | (byteArray[1] & 0xFF) << 16 | (byteArray[0] & 0xFF) << 24;
+    }
+
+    public static byte[] intToByteArray(int intValue) {
+        return new byte[]{(byte) ((intValue >> 24) & 0xFF), (byte) ((intValue >> 16) & 0xFF), (byte) ((intValue >> 8) & 0xFF), (byte) (intValue & 0xFF)};
+    }
+
+    public static byte[] longToBytes(long longValue) {
+        byte[] b = new byte[8];
+        for (int i = 0; i < 8; i++) {
+            b[i] = (byte) (longValue >>> (56 - i * 8));
+        }
+        return b;
+    }
+
+    public static byte[] longToByteArray(long longValue) {
+        byteBuffer.putLong(0, longValue);
+        return byteBuffer.array();
+    }
+
+    public static long byteArrayToLong(byte[] byteArray) {
+        byteBuffer.put(byteArray, 0, byteArray.length);
+        byteBuffer.flip();
+        return byteBuffer.getLong();
+    }
+
+    /**
+     * Hex 字符串转 byte
+     *
+     * @param inHex Hex 字符串
+     * @return byte
+     */
+    public static byte hexToByte(String inHex) {
+        return (byte) Integer.parseInt(inHex, 16);
+    }
+
+    /**
+     * Hex 字符串转 byte 数组
+     *
+     * @param inHex Hex 字符串
+     * @return byte 数组
+     */
+    public static byte[] hexToByteArray(String inHex) {
+        int hexLength = inHex.length();
+        byte[] result;
+        if (hexLength % 2 == 1) {
+            // 奇数
+            hexLength++;
+            result = new byte[(hexLength / 2)];
+            inHex = "0" + inHex;
+        } else {
+            // 偶数
+            result = new byte[(hexLength / 2)];
+        }
+        int j = 0;
+        for (int i = 0; i < hexLength; i += 2) {
+            result[j] = hexToByte(inHex.substring(i, i + 2));
+            j++;
+        }
+        return result;
+    }
 }

+ 72 - 0
serialport/src/main/java/cn/minbb/serialport/utils/CRCUtil.java

@@ -0,0 +1,72 @@
+package cn.minbb.serialport.utils;
+
+public class CRCUtil {
+
+    static byte[] crc16_tab_h = {(byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0,
+            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
+            (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
+            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
+            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40};
+
+    static byte[] crc16_tab_l = {(byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04, (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8, (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC, (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12,
+            (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10, (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4, (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38, (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C, (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7,
+            (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0, (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4, (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68, (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C, (byte) 0xB4, (byte) 0x74,
+            (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0, (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54, (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98, (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D,
+            (byte) 0x4C, (byte) 0x8C, (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40};
+
+    /**
+     * 计算CRC16校验  对外的接口
+     *
+     * @param data 需要计算的数组
+     * @return CRC16校验值
+     */
+    public static int getCrc16(byte[] data) {
+        return getCrc16(data, 0, data.length);
+    }
+
+    /**
+     * 计算CRC16校验
+     *
+     * @param data   需要计算的数组
+     * @param offset 起始位置
+     * @param len    长度
+     * @return CRC16校验值
+     */
+    public static int getCrc16(byte[] data, int offset, int len) {
+        return getCrc16(data, offset, len, 0xffff);
+    }
+
+    /**
+     * 计算CRC16校验
+     *
+     * @param data   需要计算的数组
+     * @param offset 起始位置
+     * @param len    长度
+     * @param preval 之前的校验值
+     * @return CRC16校验值
+     */
+    public static int getCrc16(byte[] data, int offset, int len, int preval) {
+        int ucCRCHi = (preval & 0xff00) >> 8;
+        int ucCRCLo = preval & 0x00ff;
+        int iIndex;
+        for (int i = 0; i < len; ++i) {
+            iIndex = (ucCRCLo ^ data[offset + i]) & 0x00ff;
+            ucCRCLo = ucCRCHi ^ crc16_tab_h[iIndex];
+            ucCRCHi = crc16_tab_l[iIndex];
+        }
+        return ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
+    }
+
+    /**
+     * 将计算的CRC值 转换为加空格的 比如  : crc值为 A30A -> A3 0A
+     *
+     * @param value
+     * @return
+     */
+    public static String getCrcString(int value) {
+        String format = String.format("%04x", value);
+        String substring = format.substring(0, 2);
+        String substring1 = format.substring(2, 4);
+        return substring.concat(" ").concat(substring1).concat(" ");
+    }
+}

+ 12 - 12
serialport/src/main/java/cn/minbb/serialport/utils/DataUtil.java

@@ -15,32 +15,32 @@ public class DataUtil {
 
     //-------------------------------------------------------
     // Hex字符串转int
-    public static int HexToInt(String inHex) {
+    public static int hexToInt(String inHex) {
         return Integer.parseInt(inHex, 16);
     }
 
-    public static String IntToHex(int intHex){
+    public static String intToHex(int intHex){
         return Integer.toHexString(intHex);
     }
 
     //-------------------------------------------------------
     // Hex字符串转byte
-    public static byte HexToByte(String inHex) {
+    public static byte hexToByte(String inHex) {
         return (byte) Integer.parseInt(inHex, 16);
     }
 
     //-------------------------------------------------------
     // 1字节转2个Hex字符
-    public static String Byte2Hex(Byte inByte) {
+    public static String byteToHex(Byte inByte) {
         return String.format("%02x", new Object[]{inByte}).toUpperCase();
     }
 
     //-------------------------------------------------------
     // 字节数组转转hex字符串
-    public static String ByteArrToHex(byte[] inBytArr) {
+    public static String byteArrayToHex(byte[] inBytArr) {
         StringBuilder strBuilder = new StringBuilder();
         for (byte valueOf : inBytArr) {
-            strBuilder.append(Byte2Hex(Byte.valueOf(valueOf)));
+            strBuilder.append(byteToHex(Byte.valueOf(valueOf)));
             strBuilder.append(" ");
         }
         return strBuilder.toString();
@@ -48,18 +48,18 @@ public class DataUtil {
 
     //-------------------------------------------------------
     // 字节数组转转hex字符串,可选长度
-    public static String ByteArrToHex(byte[] inBytArr, int offset, int byteCount) {
+    public static String byteArrayToHex(byte[] inBytArr, int offset, int byteCount) {
         StringBuilder strBuilder = new StringBuilder();
         int j = byteCount;
         for (int i = offset; i < j; i++) {
-            strBuilder.append(Byte2Hex(Byte.valueOf(inBytArr[i])));
+            strBuilder.append(byteToHex(Byte.valueOf(inBytArr[i])));
         }
         return strBuilder.toString();
     }
 
     //-------------------------------------------------------
     // 转hex字符串转字节数组
-    public static byte[] HexToByteArr(String inHex) {
+    public static byte[] hexToByteArray(String inHex) {
         byte[] result;
         int hexlen = inHex.length();
         if (isOdd(hexlen) == 1) {
@@ -71,7 +71,7 @@ public class DataUtil {
         }
         int j = 0;
         for (int i = 0; i < hexlen; i += 2) {
-            result[j] = HexToByte(inHex.substring(i, i + 2));
+            result[j] = hexToByte(inHex.substring(i, i + 2));
             j++;
         }
         return result;
@@ -128,9 +128,9 @@ public class DataUtil {
         List<String> cmdList = DataUtil.getDivLines(cmd, 2);
         int sumInt = 0;
         for (String c : cmdList) {
-            sumInt += DataUtil.HexToInt(c);
+            sumInt += DataUtil.hexToInt(c);
         }
-        String sum = DataUtil.IntToHex(sumInt);
+        String sum = DataUtil.intToHex(sumInt);
         sum = DataUtil.twoByte(sum);
         cmd += sum;
         return cmd.toUpperCase();

+ 77 - 0
serialport/src/main/java/cn/minbb/serialport/utils/PackageUtil.java

@@ -0,0 +1,77 @@
+package cn.minbb.serialport.utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.zip.CRC32;
+
+public class PackageUtil {
+
+    private static final int PACKAGE_SIZE = 64;
+
+    /**
+     * Header: 4 字节。固定为 0x7349AB01。
+     * CMD: 1 字节。
+     * ARG: 1 字节,表示命令的参数。
+     * Reserved: 2 字节。保留字节。
+     * Data Length: 4 字节。指出数据区的长度。可以为0。
+     * CRC-1: 4 字节,对CMD 到 data Length 部分做 CRC 校验。
+     * Data: 数据部分。
+     * CRC-2: 4 字节,对Data 部分做 CRC 校验。
+     *
+     * @param payload 载荷
+     * @return 分包列表
+     */
+    public static List<byte[]> distribute(byte[] payload) {
+        List<byte[]> bytesList = new ArrayList<>();
+        // 负载长度
+        int payloadLength = payload.length;
+        // 完整数据长度
+        int dataFullLength = PACKAGE_SIZE - 20;
+        // 尾部数据长度
+        int dataTailLength = payloadLength % dataFullLength;
+        // 负载分包总组数
+        int group = dataTailLength == 0 ? payloadLength / dataFullLength : payloadLength / dataFullLength + 1;
+        byte[] bytesHeader = DataUtil.hexToByteArray("7349AB01");
+        byte[] bytesCmd = new byte[1];
+        byte[] bytesArg = new byte[1];
+        byte[] bytesReserved = new byte[2];
+        byte[] bytesDataLength = new byte[4];
+        byte[] bytesCrc1 = new byte[4];
+        byte[] bytesCrc2 = new byte[4];
+        // 遍历有效负载,分包,添加包头等数据
+        for (int index = 1; index <= group; index++) {
+            byte[] bytes = new byte[0];
+            byte[] bytesData = new byte[dataFullLength];
+            if (index < group) {
+                bytesDataLength = ByteUtil.intToByteArray(dataFullLength);
+                System.arraycopy(payload, (index - 1) * dataFullLength, bytesData, 0, dataFullLength);
+            } else {
+                // 最后一组 - 可能是非完整
+                bytesDataLength = ByteUtil.intToByteArray(dataTailLength);
+                bytesData = new byte[dataTailLength];
+                System.arraycopy(payload, (index - 1) * dataFullLength, bytesData, 0, dataTailLength);
+            }
+            // 组装头部
+            bytesCmd[0] = 1;
+            bytesArg[0] = 1;
+            bytesReserved[0] = 1;
+            bytesReserved[1] = 1;
+            bytes = ByteUtil.addBytes(bytes, bytesHeader);
+            bytes = ByteUtil.addBytes(bytes, bytesCmd);
+            bytes = ByteUtil.addBytes(bytes, bytesArg);
+            bytes = ByteUtil.addBytes(bytes, bytesReserved);
+            bytes = ByteUtil.addBytes(bytes, bytesDataLength);
+            // 校验数据
+            bytesCrc1 = ByteUtil.intToByteArray(CRCUtil.getCrc16(bytes, 4, 8));
+            bytesCrc2 = ByteUtil.intToByteArray(CRCUtil.getCrc16(bytesData));
+            // 组装校验结果和数据部分
+            bytes = ByteUtil.addBytes(bytes, bytesCrc1);
+            bytes = ByteUtil.addBytes(bytes, bytesData);
+            bytes = ByteUtil.addBytes(bytes, bytesCrc2);
+            bytesList.add(bytes);
+            // LogUtil.setAppendFile("组装报文" + index + "组,共" + group + "组" + Arrays.toString(bytesData));
+        }
+        return bytesList;
+    }
+}