Modbus工具类

package com.tigeriot.globalcommonservice.model.productmanagerservice.modbusManager.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.NumberUtil;
import com.tigeriot.globalcommonservice.global.dto.devMessage.TigerIotMessage;
import com.tigeriot.globalcommonservice.global.exception.CodeException;
import com.tigeriot.globalcommonservice.importConfig.i18n.I18nUtil;
import com.tigeriot.globalcommonservice.model.productmanagerservice.iot.rundev.DevConst;
import com.tigeriot.globalcommonservice.model.productmanagerservice.modbusManager.vo.UniversalReadAndWriteReturn;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;


/**
 * modbus常用工具类
 */
@Slf4j
public class ModbusManagerUtils {

    /**
     * 一个寄存器 两个字节
     */
    public static final int RegisterAddressByteLength = 2;
    /**
     * 一个寄存器16比特
     */
    public static final int RegisterAddressBitLength = 16;
    /**
     * 一个字节 8 比特长度
     */
    public static final int ByteToBitLength = 8;

    /**
     * 默认广播地址
     */
    public static final String boardCastModbusAddress = "00";


    /**
     * 是否是广播命令
     *
     * @param hex
     * @return
     */
    public static boolean isBoardCastCommand(String hex) {
        return hex.startsWith(boardCastModbusAddress);
    }

    /**
     * 快速发送消息
     *
     * @param deviceCommId
     * @param content
     * @return
     * @throws CodeException
     */
    public static TigerIotMessage sendCommonUrgentModbusTigerIotMessage(String deviceCommId, String content) throws CodeException {
        try {
            DevConst.MessageType messageType;
            content = content.replace(" ", "");
            if (content.length() >= 4) {
                String function = content.substring(2, 4);
                DevConst.FunctionCode functionCode = DevConst.FunctionCode.create(function);
                if (functionCode != null) {
                    if (functionCode == DevConst.FunctionCode.ReadTheCoil ||
                            functionCode == DevConst.FunctionCode.ReadDiscreteInputs
                            || functionCode == DevConst.FunctionCode.ReadHoldRegisters
                            || functionCode == DevConst.FunctionCode.ReadTheInputRegister
                    ) {
                        messageType = DevConst.MessageType.read;
                    } else {
                        messageType = DevConst.MessageType.write;
                    }
                } else {
                    messageType = DevConst.MessageType.read;
                }
            } else {
                messageType = DevConst.MessageType.read;
            }
            return TigerIotMessage.sendUrgent(deviceCommId, messageType, content, DevConst.ProtocolType.MODBUS_RTU, DevConst.TransportProtocol.TCP);
        } catch (Exception e) {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("消息不合法", "globalcommonservice.error.invalid.message"), e);
        }

    }


    /**
     * int转化为寄存器地址16进制补充2字节长度字符串 安全 转不成功会抛异常
     *
     * @param registerAddressDec
     * @throws CodeException
     */
    public static String safeDecToRegisterAddressHex(Integer registerAddressDec) throws CodeException {
        if (registerAddressDec == null) {
            log.trace("寄存器地址为空");
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("寄存器地址为空", "globalcommonservice.error.register.address.empty"));
        }
        String registerAddressHex = ModbusManagerUtils.intToHex(registerAddressDec);
        return ModbusManagerUtils.supplyByteLength(registerAddressHex, ModbusManagerUtils.RegisterAddressByteLength);
    }


    /**
     * 校验数据终端类型
     *
     * @param dataTerminalType
     * @throws CodeException
     */
    public static DevConst.DataTerminalType validateDataTerminalType(String dataTerminalType, int byteLength) throws CodeException {
        dataTerminalType = dataTerminalType.replace(" ", "");
        DevConst.DataTerminalType validate = DevConst.DataTerminalType.validate(dataTerminalType);
        if (dataTerminalType.length() != byteLength) {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("数据端类型与字节长度不匹配,必须为" + dataTerminalType.length() + "位", "globalcommonservice.error.data.terminal.type.byte.length.mismatch", dataTerminalType.length()));
        }
        return validate;
    }

    /**
     * 校验数据类型和字节长度
     *
     * @param dataType
     * @param byteLength
     * @throws CodeException
     */
    public static void validateDataTypeAndByteLength(byte dataType, int byteLength) throws CodeException {
        log.trace("validateDataTypeAndByteLength dataType:{} byteLength:{}", dataType, byteLength);
        if (DevConst.DataType.STRING.value == dataType) {
            if (byteLength % 2 != 0 && byteLength > 0) {
                throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("字节长度必须是偶数", "globalcommonservice.error.byte.length.must.be.even"));
            }
        } else if (DevConst.DataType.INTEGER.value == dataType) {
            //整数
            if (byteLength > 8 || byteLength < 2) {
                throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("字节长度不合法", "globalcommonservice.error.invalid.byte.length"));
            }
            if (byteLength % 2 != 0) {
                throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("字节长度必须是偶数", "globalcommonservice.error.byte.length.must.be.even"));
            }
        } else if (DevConst.DataType.DOUBLE.value == dataType) {
            if (byteLength != 4 && byteLength != 8) {
                throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("字节长度不合法", "globalcommonservice.error.invalid.byte.length"));
            }
        } else {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("数据类型不合法", "globalcommonservice.error.invalid.data.type.simple"));
        }
    }

    /**
     * 校验modbus参数基本参数与数据类型校验 数据校验
     *
     * @param dataType
     * @param byteLength
     * @throws CodeException
     */
    public static void validateModbusDataTypeParam(Byte dataType,
                                                   Integer byteLength,
                                                   String registerAddressHex,
                                                   Float conversionFactor,
                                                   Integer accuracy

    ) throws CodeException {
        log.trace("validateModbusDataTypeParam registerAddressHex:{} dataType:{} byteLength:{} conversionFactor:{} accuracy:{} ", registerAddressHex, dataType, byteLength, conversionFactor, accuracy);
        //!!判断都不能为空
        if (dataType == null || byteLength == null || registerAddressHex == null || conversionFactor == null || accuracy == null) {
            log.error("validateModbusDataTypeParam 参数不能为空 registerAddressHex:{} dataType:{}  byteLength:{} conversionFactor:{} accuracy:{} ", registerAddressHex, dataType, byteLength, conversionFactor, accuracy);
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("参数不能为空", "globalcommonservice.error.param.not.empty"));
        }
        // 校验数据类型和字节长度 是否合法
        validateDataTypeAndByteLength(dataType, byteLength);


        //校验寄存器地址
        if (!HexUtil.isHexNumber(registerAddressHex)) {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("寄存器地址不属于16进制!!!", "globalcommonservice.error.register.address.not.hex"));
        }
        if (HexUtil.decodeHex(registerAddressHex).length != 2) {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("寄存器地址必须为2字节!!!", "globalcommonservice.error.register.address.must.be.2bytes"));
        }

        //校验转换因子
        if (conversionFactor < 0) {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("转换因子不能小于0", "globalcommonservice.error.conversion.factor.not.negative"));
        }

        //精度
        if (accuracy < 0) {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("精度不能小于0", "globalcommonservice.error.precision.not.negative"));
        }

        //校验通过
    }


    //region modbus 指令相关

    /**
     * 计算 Modbus RTU CRC16 校验值
     *
     * @param buffer 要计算校验值的字节数组
     * @return 包含两个字节的 CRC 校验值的字节数组,低位在前,高位在后
     */
    public static byte[] calculateCRC16(byte[] buffer) {
        int crc = 0xFFFF;
        for (byte b : buffer) {
            crc ^= (b & 0xFF);
            for (int i = 0; i < 8; i++) {
                if ((crc & 0x0001) != 0) {
                    crc >>= 1;
                    crc ^= 0xA001;
                } else {
                    crc >>= 1;
                }
            }
        }
        // 将 CRC 结果拆分为两个字节
        byte[] crcBytes = new byte[2];
        crcBytes[0] = (byte) (crc & 0xFF);
        crcBytes[1] = (byte) ((crc >> 8) & 0xFF);
        return crcBytes;
    }

    /**
     * 校验字节数组的 CRC 是否正确
     *
     * @param buffer 包含数据和 CRC 校验码的字节数组
     * @return 如果 CRC 校验通过返回 true,否则返回 false
     */
    public static boolean verifyCRC16(byte[] buffer) {
        if (buffer.length < 2) {
            return false;
        }
        // 提取原始数据部分(去除最后两个字节的 CRC 校验码)
        byte[] data = new byte[buffer.length - 2];
        System.arraycopy(buffer, 0, data, 0, data.length);

        // 重新计算 CRC 校验码
        byte[] calculatedCRC = calculateCRC16(data);

        // 提取接收到的 CRC 校验码
        byte[] receivedCRC = new byte[2];
        System.arraycopy(buffer, buffer.length - 2, receivedCRC, 0, 2);

        // 比较重新计算的 CRC 校验码和接收到的 CRC 校验码
        return calculatedCRC[0] == receivedCRC[0] && calculatedCRC[1] == receivedCRC[1];
    }


    /**
     * 生成 Modbus-RTU 报文命令 基础
     *
     * @param rs485              设备 ID
     * @param functionCode       功能码
     * @param registerAddressDec 起始寄存器地址
     * @param dataValues         数据值
     * @return 生成的 Modbus-RTU 报文命令字节数组
     */
    public static String generateModbusRTUCommand(byte rs485,
                                                  DevConst.FunctionCode functionCode,
                                                  int registerAddressDec, byte[] dataValues) {

        int commandLength = 4 + dataValues.length;
        //指令内容
        byte[] commandContent = new byte[commandLength];
        commandContent[0] = rs485;// 设备ID号
        commandContent[1] = HexUtil.decodeHex(functionCode.getValue())[0];//功能码
        byte[] registerAddressBytes = intToTwoBytes(registerAddressDec);//寄存器地址
        commandContent[2] = registerAddressBytes[0];
        commandContent[3] = registerAddressBytes[1];
        //将内容赋值进来
        System.arraycopy(dataValues, 0, commandContent, 4, dataValues.length);

        // 计算 CRC16 校验码
        byte[] crcBytes = calculateCRC16(commandContent);
        // 将 CRC 校验码添加到报文中
        byte[] finalCommand = new byte[commandLength + 2];
        System.arraycopy(commandContent, 0, finalCommand, 0, commandLength);
        System.arraycopy(crcBytes, 0, finalCommand, commandLength, 2);

        //将生成报文转化为16进制
        return HexUtil.encodeHexStr(finalCommand).toUpperCase();
    }

    /**
     * 生成读取寄存器指令
     *
     * @param rs485              485地址
     * @param registerAddressDec 寄存器起始地址
     * @param readByteLength     读取字节长度
     * @return
     */
    public static String generateReadRegisterCommand(byte rs485,
                                                     int registerAddressDec,
                                                     int readByteLength) {
        return generateModbusRTUCommand(rs485, DevConst.FunctionCode.ReadHoldRegisters, registerAddressDec, intToTwoBytes(readByteLength / 2));
    }

    /**
     * 写入读取寄存器指令
     *
     * @param rs485              485地址
     * @param registerAddressDec 起始寄存器地址
     * @param data               写入多字节长度
     * @return
     */
    public static String generateMultiWriteRegisterCommand(byte rs485,
                                                           int registerAddressDec,
                                                           byte[] data
    ) {
        int writeByteLength = data.length;
        byte[] writeRegisterNum = intToTwoBytes(writeByteLength / 2);
        byte writeByteLengthBytes = (byte) writeByteLength;
        data = ArrayUtil.addAll(writeRegisterNum, new byte[]{writeByteLengthBytes}, data);
        return generateModbusRTUCommand(rs485, DevConst.FunctionCode.WriteMultipleRegisters, registerAddressDec, data);
    }

    /**
     * 写入单个寄存器
     *
     * @param rs485              485地址
     * @param registerAddressDec 起始寄存器地址
     * @param highByte           高字节
     * @param lowByte            低字节
     * @return
     */
    public static String generateSingleWriteRegisterCommand(byte rs485,
                                                            int registerAddressDec,
                                                            byte highByte, byte lowByte
    ) {
        return generateModbusRTUCommand(rs485, DevConst.FunctionCode.WriteASingleRegister, registerAddressDec, new byte[]{highByte, lowByte});
    }

    //endregion


    //region 16进制相关 工具


    /**
     * 补充长度 hex字节长度必须不超过byteLength
     *
     * @param hex        hex字符串值
     * @param byteLength 补齐字符串长度
     * @return
     */
    public static String supplyByteLength(String hex, int byteLength) {
        int strLength = byteLength * 2;
        int hexLength = hex.length();
        if (hexLength > strLength) {
            throw new IllegalArgumentException(I18nUtil.getMessage("hex的字节长度大于byteLength=" + byteLength, "globalcommonservice.error.hex.byte.length.exceeds", byteLength));
        }
        int supplyNum = strLength - hexLength;
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < supplyNum; i++) {
            result.append('0');
        }
        result.append(hex);
        return result.toString();
    }


    /**
     * 偏移16进制 暂时寄存器地址偏移用
     * 注意:计算起始地址是属于自己值范围 计算最终地址是自己所在值范围寄存器地址+1
     *
     * @param hex         被偏移16进制
     * @param offsetUnits 偏移单位
     * @param offset      偏移值 必须大于0 以偏移单位偏移多少 字节或者位
     * @return 10进制 后面自行处理 可自己转16进制 返回的是寄存器的地址
     */
    public static int offsetHex(String hex, DevConst.OffsetUnits offsetUnits, int offset) {
        if (offset < 0) {
            throw new IllegalArgumentException(I18nUtil.getMessage("偏移值必须大于0", "globalcommonservice.error.offset.value.must.be.greater.than.zero"));
        }
        int startRegisterAddressDec = Integer.parseInt(hex, 16);
        return offsetDec(startRegisterAddressDec, offsetUnits, offset);
    }

    /**
     * 偏移10进制 暂时寄存器用 暂时寄存器地址偏移用
     * 注意:计算起始地址是属于自己值范围 计算最终地址是自己所在值范围寄存器地址+1
     *
     * @param dec         被偏移10进制
     * @param offsetUnits 偏移单位
     * @param offset      偏移值 必须大于0 必须大于0 以偏移单位偏移多少 字节或者位
     * @return 10进制 后面自行处理 可自己转16进制 返回的是寄存器的地址
     */
    public static int offsetDec(int dec, DevConst.OffsetUnits offsetUnits, int offset) {
        if (offset < 0) {
            throw new IllegalArgumentException(I18nUtil.getMessage("偏移值必须大于等于0", "globalcommonservice.error.offset.value.must.be.greater.than.or.equal.to.zero"));
        }

        if (offsetUnits == DevConst.OffsetUnits.BYTE) {
            //最终寄存器地址
            return dec + offset / 2;
        } else {
            //偏移位
            return dec + offset / 16;
        }
    }


    public static String logHexCommand(String command) {
        StringBuilder sb = new StringBuilder();

        if (command.length() % 2 != 0) {
            //如果不等于0
            command = "0" + command;
        }

        char[] charArray = command.toCharArray();

        for (int i = 0; i < charArray.length; i++) {
            if (i % 2 != 0 && i != charArray.length - 1) {
                sb.append(charArray[i]);
                sb.append(" ");
            } else {
                sb.append(charArray[i]);
            }
        }
        return sb.toString();
    }

    //endregion


    //region String

    /**
     * 二进制字符串转字节数组 从后截取8位开始
     * 举例子
     * 11 00000001
     * [3,1]
     *
     * @param binaryString
     * @return
     */
    public static byte[] binaryStringToByteArrayPost(String binaryString) {
        int length = (binaryString.length() + 7) / 8;
        byte[] byteArray = new byte[length];

        int startIndex = binaryString.length();
        for (int i = length - 1; i >= 0; i--) {
            int endIndex = startIndex;
            startIndex = Math.max(0, startIndex - 8);
            StringBuilder byteStr = new StringBuilder(binaryString.substring(startIndex, endIndex));

            while (byteStr.length() < 8) {
                byteStr.insert(0, "0");
            }

            byteArray[i] = (byte) Integer.parseInt(byteStr.toString(), 2);
        }
        return byteArray;
    }

    /**
     * 二进制字符串转字节数组 从前截取8位开始
     * 举例子
     * 11 00000001
     * 11000000 01
     * [192,1]
     *
     * @param binaryStr
     * @return
     */
    public static byte[] binaryStringToByteArrayFront(String binaryStr) {
        int length = binaryStr.length();
        // 计算需要的字节数
        int byteCount = (length + 7) / 8;
        byte[] byteArray = new byte[byteCount];

        for (int i = 0; i < byteCount; i++) {
            int startIndex = i * 8;
            int endIndex = Math.min(startIndex + 8, length);
            StringBuilder byteBinary = new StringBuilder(binaryStr.substring(startIndex, endIndex));
            // 不足 8 位时,前面补 0
            while (byteBinary.length() < 8) {
                byteBinary.insert(0, "0");
            }
            byteArray[i] = (byte) Integer.parseInt(byteBinary.toString(), 2);
        }
        return byteArray;
    }

    /**
     * 字节数组转二进制字符串
     *
     * @param bytes
     * @return
     */
    public static String bytesToBinaryStr(byte[] bytes) {
        StringBuilder binaryString = new StringBuilder();
        for (byte b : bytes) {
            for (int i = 7; i >= 0; i--) {
                binaryString.append((b >> i) & 1);
            }
        }
        return binaryString.toString();
    }

    //endregion


    //region double 转 8 字节
    public static String doubleToHex(double value) {
        // 将 double 转换为 long 类型的位表示
        long bits = Double.doubleToLongBits(value);
        // 将 long 类型的位表示转换为十六进制字符串
        return Long.toHexString(bits);
    }

    public static double hexToDouble(String hex) {
        // 将十六进制字符串转换为 long 类型的整数
        long bits = Long.parseLong(hex, 16);
        // 将 long 类型的整数转换为 double 类型的值
        return Double.longBitsToDouble(bits);
    }

    public static byte[] doubleToEightBytes(double value) {
        // 创建一个容量为 8 字节的 ByteBuffer
        ByteBuffer buffer = ByteBuffer.allocate(8);
        // 将 double 值放入 ByteBuffer
        buffer.putDouble(value);
        // 返回 ByteBuffer 中的字节数组
        return buffer.array();
    }

    public static double eightBytesToDouble(byte[] bytes) {
        // 创建一个容量为 8 字节的 ByteBuffer
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        // 从 ByteBuffer 中读取 double 类型的值
        return buffer.getDouble();
    }

    public static double binaryStringToDouble(String binary) {
        // 将二进制字符串转换为长整型
        long longValue = Long.parseLong(binary, 2);
        // 使用 Double.longBitsToDouble 方法将长整型转换为 double 类型
        return Double.longBitsToDouble(longValue);
    }
    //endregion

    //region long 转 8 字节
    public static byte[] longToEightBytes(long value) {
        ByteBuffer buffer = ByteBuffer.allocate(8);
        buffer.putLong(value);
        return buffer.array();
    }

    public static long eightBytesToLong(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        return buffer.getLong();
    }

    public static String longToHex(long value) {
        return Long.toHexString(value);
    }

    public static long hexToLong(String hex) {
        return Long.parseLong(hex, 16);
    }

    //endregion


    //region float 转 4 字节
    public static String floatToHex(float value) {
        // 将 float 转换为 int 类型的位表示
        int bits = Float.floatToIntBits(value);
        // 将 int 类型的位表示转换为十六进制字符串
        return Integer.toHexString(bits);
    }

    public static float hexToFloat(String hex) {
        // 将十六进制字符串转换为 int 类型的整数
        int bits = Integer.parseInt(hex, 16);
        // 将 int 类型的整数转换为 float 类型的值
        return Float.intBitsToFloat(bits);
    }


    public static byte[] floatToFourBytes(float value) {
        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.putFloat(value);
        return buffer.array();
    }

    public static float fourBytesToFloat(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        return buffer.getFloat();
    }
    //endregion

    //region int 转4字节
    public static byte[] intToFourBytes(int value) {
        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.putInt(value);
        return buffer.array();
    }

    public static int fourBytesToInt(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        return buffer.getInt();
    }

    public static int hexToInt(String hex) {
        return Integer.parseInt(hex, 16);
    }

    public static String intToHex(int value) {
        return Integer.toHexString(value);
    }

    /**
     * 将 int 类型转换为 2 字节的字节数组 大端
     *
     * @param value 要转换的 int 值
     * @return 包含 2 个字节的字节数组
     */
    public static byte[] intToTwoBytes(int value) {
        byte[] result = new byte[2];
        // 提取低 8 位
        result[1] = (byte) (value & 0xFF);
        // 提取高 8 位
        result[0] = (byte) ((value >> 8) & 0xFF);
        return result;
    }

    /**
     * 一字节转无符号Int
     *
     * @return
     */
    public static int oneByteToInt(byte b) throws CodeException {
        return b & 0xFF;
    }

    /**
     * 两字节转Int
     *
     * @return
     */
    public static int twoBytesToInt(byte[] bytes) throws CodeException {
        if (bytes.length != 2) {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), "字节数组长度必须为2");
        }
        return ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getShort() & 0xFFFF;
    }

    /**
     * 两字节转Int 按照short的格式转的 无符号
     *
     * @param highByte
     * @param lowByte
     * @return
     */
    public static int twoBytesToShortInt(byte highByte, byte lowByte) {
        // 将高字节左移 8 位,然后与低字节进行按位或操作
        return ((highByte << 8) | (lowByte & 0xFF)) &  0xFFFF;
    }

    //endregion


    //region short

    public static byte[] shortToTwoBytes(short value) {
        ByteBuffer buffer = ByteBuffer.allocate(2);
        buffer.putShort(value);
        return buffer.array();
    }

    public static short twoBytesToShort(byte[] bytes) {
        ByteBuffer buffer = ByteBuffer.wrap(bytes);
        return buffer.getShort();
    }

    public static String shortToHex(short value) {
        return Integer.toHexString(value & 0xFFFF);
    }

    public static short hexToShort(String hex) {
        return Short.parseShort(hex, 16);
    }
    //endregion

    //region byte

    /**
     * 必定两位字符串 1字节对应两个16进制字符串
     *
     * @param b
     * @return
     */
    public static String byteToHex(byte b) {
        //这里与操作是因为 转化为 int的时候 需要变成无符号的 字节 所以与 是把符号位去除,最后转化为16进制
        String hex = Integer.toHexString(b & 0xFF);
        if (hex.length() == 1) {
            hex = "0" + hex;
        }
        return hex;
    }

    public static byte hexToByte(String hex) {
        return (byte) Integer.parseInt(hex, 16);
    }


    /**
     * 将大端序双向转化自定义顺序 负负得正 返回新数字
     *
     * @param bytes
     * @param endianType
     * @return
     * @throws CodeException
     */
    public static byte[] convertBigEndianSwapCustomOrder(byte[] bytes, String endianType) throws CodeException {
        int byteLength = bytes.length;
        if (byteLength <= 1) {
            return bytes;
        }
        DevConst.DataTerminalType dataTerminalType = validateDataTerminalType(endianType, byteLength);
        byte[] newByte = null;
        char[] order = null;
        if (dataTerminalType == DevConst.DataTerminalType.AB
                ||
                dataTerminalType == DevConst.DataTerminalType.AB_CD
                ||
                dataTerminalType == DevConst.DataTerminalType.AB_CD_EF_GH
        ) {
            //无需排序
            return bytes;
        } else if (dataTerminalType == DevConst.DataTerminalType.BA
                ||
                dataTerminalType == DevConst.DataTerminalType.DC_BA
                ||
                dataTerminalType == DevConst.DataTerminalType.HG_FE_DC_BA

        ) {
            return ArrayUtil.reverse(bytes);
        } else if (byteLength == 4) {
            newByte = new byte[4];
            order = DevConst.DataTerminalType.order4;

        } else {
            newByte = new byte[8];
            order = DevConst.DataTerminalType.order8;
        }
        char[] charArray = dataTerminalType.value.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            //二分查找查询 自定义顺序 在大端序的某个索引
            int index = Arrays.binarySearch(order, charArray[i]);
            //将当前索引的值 赋予  传入数组自定义序在大端序中索引的值
            newByte[i] = bytes[index];
        }
        return newByte;
    }


    //endregion

    //region bean 字段类型

    /**
     * 将解析出的Pair 赋值到 update 中
     *
     * @param update
     * @param pairs
     */
    public static void fieldMappingValue(Object update, Map<String, Object> pairs) {
        if (pairs != null && !pairs.isEmpty() && update != null) {
            BeanUtil.copyProperties(pairs, update);
        }
    }

    /**
     * 从字节数组中读取寄存器的值或字节的值解析出来 根据数据类型(字节索引版本)
     *
     * @param data                  源数据字节数组
     * @param dataStartByteIndex    数据起始字节索引
     * @param readStartByteIndex    参数起始字节索引
     * @param offsetStartIndex      参数起始下标
     * @param offsetNum             参数偏移数量
     * @param offsetUnits           参数偏移单位
     * @param dataType              参数类型
     * @param dataTerminalType      数据终端类型
     * @param conversionFactor      转换因子
     * @param accuracy              精度
     * @return
     * @throws CodeException
     */
    public static UniversalReadAndWriteReturn readModbusByteArrayParamValueByByteIndex(
            byte[] data,
            int dataStartByteIndex,
            int readStartByteIndex,
            int offsetStartIndex,
            int offsetNum,
            DevConst.OffsetUnits offsetUnits,
            DevConst.DataType dataType,
            String dataTerminalType,
            double conversionFactor,
            int accuracy
    ) throws CodeException {

        if (offsetUnits == DevConst.OffsetUnits.BYTE) {
            //字节读取模式:支持负数索引
            //计算参数字节索引相对于数据起始位置的字节偏移
            int byteOffset = readStartByteIndex - dataStartByteIndex;
            
            //计算实际的字节起始索引(支持负数)
            int actualByteStartIndex = byteOffset + offsetStartIndex;
            
            //检查边界
            if (actualByteStartIndex < 0) {
                throw new IllegalArgumentException(I18nUtil.getMessage("字节起始索引不能小于0,计算结果:" + actualByteStartIndex, 
                    "globalcommonservice.error.byte.start.index.negative", actualByteStartIndex));
            }
            
            int actualByteEndIndex = actualByteStartIndex + offsetNum;
            if (actualByteEndIndex > data.length) {
                throw new IllegalArgumentException(I18nUtil.getMessage("字节结束索引超出数据范围,结束索引:" + actualByteEndIndex + ",数据总字节数:" + data.length, 
                    "globalcommonservice.error.byte.end.index.overflow", actualByteEndIndex, data.length));
            }
            
            //提取指定字节范围的数据
            byte[] sub = Arrays.copyOfRange(data, actualByteStartIndex, actualByteEndIndex);
            
            //根据数据类型解析
            if (dataType == DevConst.DataType.INTEGER) {
                //整数类型
                Object originalValue;
                if (offsetNum == 1) {
                    originalValue = (long) sub[0];
                } else if (offsetNum == 2) {
                    sub = convertBigEndianSwapCustomOrder(sub, dataTerminalType);
                    originalValue = (long) twoBytesToShort(sub);
                } else if (offsetNum == 4) {
                    sub = convertBigEndianSwapCustomOrder(sub, dataTerminalType);
                    originalValue = (long) fourBytesToInt(sub);
                } else if (offsetNum == 8) {
                    sub = convertBigEndianSwapCustomOrder(sub, dataTerminalType);
                    originalValue = eightBytesToLong(sub);
                } else {
                    throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的整数类型,字节长度:" + offsetNum, 
                        "globalcommonservice.error.unparseable.integer.type.with.length", offsetNum));
                }
                
                // 计算处理后的值:原始值 * 转换因子,并按精度四舍五入
                double processedValue = NumberUtil.round(NumberUtil.mul(originalValue.toString(), String.valueOf(conversionFactor)), accuracy).doubleValue();
                
                UniversalReadAndWriteReturn result = new UniversalReadAndWriteReturn();
                result.setOriginalValue(originalValue);
                result.setProcessedValue(processedValue);
                return result;

            } else if (dataType == DevConst.DataType.DOUBLE) {
                //浮点类型
                Object originalValue;
                if (offsetNum == 4) {
                    sub = convertBigEndianSwapCustomOrder(sub, dataTerminalType);
                    originalValue = fourBytesToFloat(sub);
                } else if (offsetNum == 8) {
                    sub = convertBigEndianSwapCustomOrder(sub, dataTerminalType);
                    originalValue = eightBytesToDouble(sub);
                } else {
                    throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的浮点类型,字节长度:" + offsetNum, 
                        "globalcommonservice.error.unparseable.float.type.with.length", offsetNum));
                }
                
                // 计算处理后的值:原始值 * 转换因子,并按精度四舍五入
                double processedValue = NumberUtil.round(NumberUtil.mul(originalValue.toString(), String.valueOf(conversionFactor)), accuracy).doubleValue();
                
                UniversalReadAndWriteReturn result = new UniversalReadAndWriteReturn();
                result.setOriginalValue(originalValue);
                result.setProcessedValue(processedValue);
                return result;

            } else if (dataType == DevConst.DataType.STRING) {
                //字符串类型
                String originalValue;
                if (dataTerminalType.equalsIgnoreCase(DevConst.DataTerminalType.AB.getValue())) {
                    originalValue = new String(sub, StandardCharsets.UTF_8);
                } else {
                    sub = ArrayUtil.reverse(sub);
                    originalValue = new String(sub, StandardCharsets.UTF_8);
                }
                // 只返回有效字符:去除末尾的空字符(\0)和空白字符
                String trimmedValue = trimTrailingNullAndWhitespace(originalValue);
                
                // 字符串类型,原始值和处理值相同
                UniversalReadAndWriteReturn result = new UniversalReadAndWriteReturn();
                result.setOriginalValue(trimmedValue);
                result.setProcessedValue(trimmedValue);
                return result;
            } else {
                throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的数据类型", "globalcommonservice.error.unparseable.data.type"));
            }

        } else {
            //位读取模式:支持负数索引
            //将整个数据源转换为二进制字符串
            String fullBinaryStr = ModbusManagerUtils.bytesToBinaryStr(data);
            
            //计算参数字节索引相对于数据起始位置的位偏移(1个字节=8位)
            int bitOffset = (readStartByteIndex - dataStartByteIndex) * ByteToBitLength;
            
            //计算实际的位起始索引(支持负数)
            int actualBitStartIndex = bitOffset + offsetStartIndex;
            
            //检查边界
            if (actualBitStartIndex < 0) {
                throw new IllegalArgumentException(I18nUtil.getMessage("位起始索引不能小于0,计算结果:" + actualBitStartIndex, 
                    "globalcommonservice.error.bit.start.index.negative", actualBitStartIndex));
            }
            
            int actualBitEndIndex = actualBitStartIndex + offsetNum;
            if (actualBitEndIndex > fullBinaryStr.length()) {
                throw new IllegalArgumentException(I18nUtil.getMessage("位结束索引超出数据范围,结束索引:" + actualBitEndIndex + ",数据总位数:" + fullBinaryStr.length(), 
                    "globalcommonservice.error.bit.end.index.overflow", actualBitEndIndex, fullBinaryStr.length()));
            }
            
            //提取指定位范围的二进制字符串
            String binaryValue = fullBinaryStr.substring(actualBitStartIndex, actualBitEndIndex);
            
            //根据数据类型解析
            if (dataType == DevConst.DataType.INTEGER) {
                Long originalValue = Long.parseLong(binaryValue, 2);
                
                // 计算处理后的值:原始值 * 转换因子,并按精度四舍五入
                double processedValue = NumberUtil.round(NumberUtil.mul(originalValue.toString(), String.valueOf(conversionFactor)), accuracy).doubleValue();
                
                UniversalReadAndWriteReturn result = new UniversalReadAndWriteReturn();
                result.setOriginalValue(originalValue);
                result.setProcessedValue(processedValue);
                return result;
                
            } else if (dataType == DevConst.DataType.DOUBLE) {
                Double originalValue = binaryStringToDouble(binaryValue);
                
                // 计算处理后的值:原始值 * 转换因子,并按精度四舍五入
                double processedValue = NumberUtil.round(NumberUtil.mul(originalValue.toString(), String.valueOf(conversionFactor)), accuracy).doubleValue();
                
                UniversalReadAndWriteReturn result = new UniversalReadAndWriteReturn();
                result.setOriginalValue(originalValue);
                result.setProcessedValue(processedValue);
                return result;
                
            } else if (dataType == DevConst.DataType.STRING) {
                String originalValue;
                if (dataTerminalType.equalsIgnoreCase("AB")) {
                    byte[] bytes = binaryStringToByteArrayPost(binaryValue);
                    originalValue = new String(bytes, StandardCharsets.UTF_8);
                } else {
                    byte[] bytes = binaryStringToByteArrayPost(binaryValue);
                    bytes = ArrayUtil.reverse(bytes);
                    originalValue = new String(bytes, StandardCharsets.UTF_8);
                }
                // 只返回有效字符:去除末尾的空字符(\0)和空白字符
                String trimmedValue = trimTrailingNullAndWhitespace(originalValue);
                
                // 字符串类型,原始值和处理值相同
                UniversalReadAndWriteReturn result = new UniversalReadAndWriteReturn();
                result.setOriginalValue(trimmedValue);
                result.setProcessedValue(trimmedValue);
                return result;
            } else {
                throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的数据类型", "globalcommonservice.error.unparseable.data.type"));
            }
        }
    }


    /**
     * 从字节数组中读取寄存器的值或字节的值解析出来 根据数据类型
     *
     * @param data                     源数据字节数组
     * @param dataStartRegisterAddrDec 指令起始寄存器地址  10进制
     * @param readStartRegisterAddrDec 参数起始寄存器地址  10进制
     * @param offsetStartIndex         参数起始下标
     * @param offsetNum                参数偏移数量
     * @param offsetUnits              参数偏移单位
     * @param dataType                 参数类型
     * @param dataTerminalType         数据终端类型
     * @param conversionFactor         转换因子
     * @param accuracy                 精度
     * @return
     * @throws CodeException
     */
    public static UniversalReadAndWriteReturn readModbusByteArrayParamValue(
            byte[] data,
            int dataStartRegisterAddrDec,
            int readStartRegisterAddrDec,
            int offsetStartIndex,
            int offsetNum,
            DevConst.OffsetUnits offsetUnits,
            DevConst.DataType dataType,
            String dataTerminalType,
            double conversionFactor,
            int accuracy
    ) throws CodeException {
        // 将寄存器地址转换为字节索引(1个寄存器=2字节)
        int dataStartByteIndex = dataStartRegisterAddrDec * RegisterAddressByteLength;
        int readStartByteIndex = readStartRegisterAddrDec * RegisterAddressByteLength;
        
        // 复用字节索引版本的方法
        return readModbusByteArrayParamValueByByteIndex(
                data,
                dataStartByteIndex,
                readStartByteIndex,
                offsetStartIndex,
                offsetNum,
                offsetUnits,
                dataType,
                dataTerminalType,
                conversionFactor,
                accuracy
        );
    }


    /**
     * 从字节数组写入字节或者位或者字符 根据数据类型(字节索引版本)
     *
     * @param data                  源数据字节数组
     * @param dataStartByteIndex    数据起始字节索引
     * @param readStartByteIndex    参数起始字节索引
     * @param offsetStartIndex      参数起始下标
     * @param offsetNum             参数偏移数量
     * @param offsetUnits           参数偏移单位
     * @param dataType              参数类型
     * @param dataTerminalType      数据终端类型
     * @param value                 写入的值
     * @param conversionFactor      转换因子
     * @param accuracy              精度
     * @return                      包含原始值和处理值的对象
     * @throws CodeException
     */
    public static UniversalReadAndWriteReturn writeModbusByteArrayParamValueByByteIndex(
            byte[] data,
            int dataStartByteIndex,
            int readStartByteIndex,
            int offsetStartIndex,
            int offsetNum,
            DevConst.OffsetUnits offsetUnits,
            DevConst.DataType dataType,
            String dataTerminalType,
            Object value,
            double conversionFactor,
            int accuracy
    ) throws CodeException {
        
        // 创建返回对象
        UniversalReadAndWriteReturn result = new UniversalReadAndWriteReturn();
        result.setOriginalValue(value);

        if (offsetUnits == DevConst.OffsetUnits.BYTE) {
            //字节写入模式:支持负数索引
            //计算参数字节索引相对于数据起始位置的字节偏移
            int byteOffset = readStartByteIndex - dataStartByteIndex;
            
            //计算实际的字节起始索引(支持负数)
            int actualByteStartIndex = byteOffset + offsetStartIndex;
            
            //检查边界
            if (actualByteStartIndex < 0) {
                throw new IllegalArgumentException(I18nUtil.getMessage("字节起始索引不能小于0,计算结果:" + actualByteStartIndex, 
                    "globalcommonservice.error.byte.start.index.negative", actualByteStartIndex));
            }
            
            int actualByteEndIndex = actualByteStartIndex + offsetNum;
            if (actualByteEndIndex > data.length) {
                throw new IllegalArgumentException(I18nUtil.getMessage("字节结束索引超出数据范围,结束索引:" + actualByteEndIndex + ",数据总字节数:" + data.length, 
                    "globalcommonservice.error.byte.end.index.overflow", actualByteEndIndex, data.length));
            }
            
            //准备写入的字节数组
            byte[] writeBytes = null;

            if (dataType == DevConst.DataType.STRING && value instanceof String str) {
                //字符串类型
                byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
                if (bytes.length > offsetNum) {
                    throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("字符串长度不能大于写入长度,字符串字节数:" + bytes.length + ",允许写入:" + offsetNum, 
                        "globalcommonservice.error.string.length.exceeds.write.length.detail", bytes.length, offsetNum));
                } else if (bytes.length < offsetNum) {
                    //如果长度小于偏移量,则用0填充
                    byte[] newBytes = new byte[offsetNum];
                    System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
                    writeBytes = newBytes;
                } else {
                    //如果长度等于偏移量,则直接赋值
                    writeBytes = bytes;
                }
                // 字符串类型,原始值和处理值相同
                result.setProcessedValue(str);

            } else if (dataType == DevConst.DataType.INTEGER && value instanceof Number num) {
                //整数类型
                double v = num.doubleValue();
                double processedValue = NumberUtil.div(v, conversionFactor, accuracy);

                if (offsetNum == 1) {
                    writeBytes = new byte[1];
                    writeBytes[0] = (byte) processedValue;
                } else if (offsetNum == 2) {
                    writeBytes = shortToTwoBytes((short) processedValue);
                } else if (offsetNum == 4) {
                    writeBytes = intToFourBytes((int) processedValue);
                } else if (offsetNum == 8) {
                    writeBytes = longToEightBytes((long) processedValue);
                } else {
                    throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的整数类型,字节长度:" + offsetNum, 
                        "globalcommonservice.error.unparseable.integer.type.with.length", offsetNum));
                }
                // 记录处理后的值
                result.setProcessedValue(processedValue);

            } else if (dataType == DevConst.DataType.DOUBLE && value instanceof Number num) {
                //浮点类型
                double v = num.doubleValue();
                double processedValue = NumberUtil.div(v, conversionFactor, accuracy);

                if (offsetNum == 4) {
                    writeBytes = floatToFourBytes((float) processedValue);
                } else if (offsetNum == 8) {
                    writeBytes = doubleToEightBytes(processedValue);
                } else {
                    throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的浮点类型,字节长度:" + offsetNum, 
                        "globalcommonservice.error.unparseable.float.type.with.length", offsetNum));
                }
                // 记录处理后的值
                result.setProcessedValue(processedValue);

            } else {
                throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的类型或值类型不匹配", "globalcommonservice.error.unparseable.type.or.mismatch"));
            }

            //转换字节序并写入到原数组中(不改变引用)
            if (dataType == DevConst.DataType.STRING) {
                // 字符串类型:根据数据端类型判断正序还是倒序
                if (dataTerminalType.equalsIgnoreCase(DevConst.DataTerminalType.AB.getValue())) {
                    // AB类型:保持正序,不需要转换
                    // writeBytes 保持不变
                } else {
                    // 其他类型:倒序
                    writeBytes = ArrayUtil.reverse(writeBytes);
                }
            } else {
                // 非字符串类型:使用原有的字节序转换逻辑
                writeBytes = convertBigEndianSwapCustomOrder(writeBytes, dataTerminalType);
            }
            System.arraycopy(writeBytes, 0, data, actualByteStartIndex, writeBytes.length);

        } else {
            //位写入模式:支持负数索引
            //将整个数据源转换为二进制字符串
            String fullBinaryStr = ModbusManagerUtils.bytesToBinaryStr(data);
            char[] fullBinaryChars = fullBinaryStr.toCharArray();
            
            //计算参数字节索引相对于数据起始位置的位偏移(1个字节=8位)
            int bitOffset = (readStartByteIndex - dataStartByteIndex) * ByteToBitLength;
            
            //计算实际的位起始索引(支持负数)
            int actualBitStartIndex = bitOffset + offsetStartIndex;
            
            //检查边界
            if (actualBitStartIndex < 0) {
                throw new IllegalArgumentException(I18nUtil.getMessage("位起始索引不能小于0,计算结果:" + actualBitStartIndex, 
                    "globalcommonservice.error.bit.start.index.negative", actualBitStartIndex));
            }
            
            int actualBitEndIndex = actualBitStartIndex + offsetNum;
            if (actualBitEndIndex > fullBinaryChars.length) {
                throw new IllegalArgumentException(I18nUtil.getMessage("位结束索引超出数据范围,结束索引:" + actualBitEndIndex + ",数据总位数:" + fullBinaryChars.length, 
                    "globalcommonservice.error.bit.end.index.overflow", actualBitEndIndex, fullBinaryChars.length));
            }

            //根据数据类型准备要写入的二进制字符串
            char[] writeBinaryChars = null;

            if (dataType == DevConst.DataType.STRING && value instanceof String str) {
                //字符串类型
                byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
                int requiredBytes = offsetNum / ByteToBitLength;
                
                if (offsetNum % ByteToBitLength != 0) {
                    throw new IllegalArgumentException(I18nUtil.getMessage("字符串写入的位数必须是8的倍数,当前位数:" + offsetNum, 
                        "globalcommonservice.error.string.bit.count.must.be.multiple.of.8", offsetNum));
                }
                
                if (bytes.length > requiredBytes) {
                    throw new CodeException(HttpStatus.BAD_REQUEST.value(), I18nUtil.getMessage("字符串长度不能大于写入长度,字符串字节数:" + bytes.length + ",允许写入:" + requiredBytes, 
                        "globalcommonservice.error.string.length.exceeds.write.length.detail", bytes.length, requiredBytes));
                } else if (bytes.length < requiredBytes) {
                    //如果长度小于要求,则用0填充
                    byte[] newBytes = new byte[requiredBytes];
                    System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
                    bytes = newBytes;
                }
                
                writeBinaryChars = ModbusManagerUtils.bytesToBinaryStr(bytes).toCharArray();
                // 字符串类型,原始值和处理值相同
                result.setProcessedValue(str);

            } else if (dataType == DevConst.DataType.INTEGER && value instanceof Number num) {
                //整数类型
                double v = num.doubleValue();
                double processedValue = NumberUtil.div(v, conversionFactor, accuracy);
                long bitValue = (long) processedValue;
                
                //转换为二进制字符串
                String binaryStr = Long.toBinaryString(bitValue);
                
                //检查位数是否超出
                if (binaryStr.length() > offsetNum) {
                    throw new IllegalArgumentException(I18nUtil.getMessage("整数值需要的位数超出允许范围,需要:" + binaryStr.length() + ",允许:" + offsetNum, 
                        "globalcommonservice.error.integer.bit.count.overflow", binaryStr.length(), offsetNum));
                }
                
                //补齐到指定位数(前面补0)
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < offsetNum - binaryStr.length(); i++) {
                    sb.append('0');
                }
                sb.append(binaryStr);
                writeBinaryChars = sb.toString().toCharArray();
                // 记录处理后的值
                result.setProcessedValue(processedValue);

            } else if (dataType == DevConst.DataType.DOUBLE) {
                //按位写入浮点 不支持
                throw new IllegalArgumentException(I18nUtil.getMessage("不支持按位写入浮点", "globalcommonservice.error.bitwise.write.float.not.supported"));
            } else {
                throw new IllegalArgumentException(I18nUtil.getMessage("无法解析的类型或值类型不匹配", "globalcommonservice.error.unparseable.type.or.mismatch"));
            }

            //将准备好的二进制字符写入到全局二进制字符数组的指定位置
            System.arraycopy(writeBinaryChars, 0, fullBinaryChars, actualBitStartIndex, writeBinaryChars.length);
            
            //将修改后的二进制字符数组转换回字节数组,并写入原数组(不改变引用)
            byte[] modifiedBytes = ModbusManagerUtils.binaryStringToByteArrayFront(String.valueOf(fullBinaryChars));
            System.arraycopy(modifiedBytes, 0, data, 0, modifiedBytes.length);
        }
        
        return result;
    }


    /**
     * 从字节数组写入字节或者位或者字符 根据数据类型
     *
     * @param data                     源数据字节数组
     * @param dataStartRegisterAddrDec 指令起始寄存器地址  10进制
     * @param readStartRegisterAddrDec 参数起始寄存器地址  10进制
     * @param offsetStartIndex         参数起始下标
     * @param offsetNum                参数偏移数量
     * @param offsetUnits              参数偏移单位
     * @param dataType                 参数类型
     * @param dataTerminalType         数据终端类型
     * @return                         包含原始值和处理值的对象
     * @throws CodeException
     */
    public static UniversalReadAndWriteReturn writeModbusByteArrayParamValue(
            byte[] data,
            int dataStartRegisterAddrDec,
            int readStartRegisterAddrDec,
            int offsetStartIndex,
            int offsetNum,
            DevConst.OffsetUnits offsetUnits,
            DevConst.DataType dataType,
            String dataTerminalType,
            Object value,
            double conversionFactor,
            int accuracy
    ) throws CodeException {
        // 将寄存器地址转换为字节索引(1个寄存器=2字节)
        int dataStartByteIndex = dataStartRegisterAddrDec * RegisterAddressByteLength;
        int readStartByteIndex = readStartRegisterAddrDec * RegisterAddressByteLength;
        
        // 复用字节索引版本的方法
        return writeModbusByteArrayParamValueByByteIndex(
                data,
                dataStartByteIndex,
                readStartByteIndex,
                offsetStartIndex,
                offsetNum,
                offsetUnits,
                dataType,
                dataTerminalType,
                value,
                conversionFactor,
                accuracy
        );
    }


    //endregion

    public static void main(String[] args) throws CodeException {
        System.out.println("========== 有符号整数处理测试 ==========\n");
        System.out.println("此测试用于验证整数是否按有符号方式处理");
        System.out.println("关键:当最高位为1时,有符号会得到负数,无符号会得到大的正数\n");
        
        int passCount = 0;
        int failCount = 0;

        // ========== 测试1: 1字节有符号 - 正数 ==========
        System.out.println("【测试1】1字节有符号 - 正数");
        byte[] data1 = new byte[]{0x7F}; // 127
        UniversalReadAndWriteReturn result1 = readModbusByteArrayParamValue(
                data1, 0, 0, 0, 1,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB", 1.0, 0
        );
        long value1 = (Long) result1.getOriginalValue();
        boolean test1Pass = value1 == 127L;
        System.out.println("原始数据(HEX): 0x7F");
        System.out.println("读取值: " + value1);
        System.out.println("期望值: 127 (有符号和无符号都相同)");
        System.out.println("测试结果: " + (test1Pass ? "✅ 通过" : "❌ 失败"));
        if (test1Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试2: 1字节有符号 - 负数 ==========
        System.out.println("【测试2】1字节有符号 - 最高位为1");
        byte[] data2 = new byte[]{(byte) 0xFF}; // -1 (有符号) 或 255 (无符号)
        UniversalReadAndWriteReturn result2 = readModbusByteArrayParamValue(
                data2, 0, 0, 0, 1,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB", 1.0, 0
        );
        long value2 = (Long) result2.getOriginalValue();
        boolean test2Pass = value2 == -1L;
        System.out.println("原始数据(HEX): 0xFF");
        System.out.println("读取值: " + value2);
        System.out.println("期望值: -1 (有符号) / 如果是255则说明还在用无符号");
        System.out.println("测试结果: " + (test2Pass ? "✅ 通过 (有符号)" : "❌ 失败 (可能是无符号)"));
        if (test2Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试3: 1字节有符号 - 其他负数 ==========
        System.out.println("【测试3】1字节有符号 - 其他负数");
        byte[] data3 = new byte[]{(byte) 0x80}; // -128 (有符号) 或 128 (无符号)
        UniversalReadAndWriteReturn result3 = readModbusByteArrayParamValue(
                data3, 0, 0, 0, 1,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB", 1.0, 0
        );
        long value3 = (Long) result3.getOriginalValue();
        boolean test3Pass = value3 == -128L;
        System.out.println("原始数据(HEX): 0x80");
        System.out.println("读取值: " + value3);
        System.out.println("期望值: -128 (有符号) / 如果是128则说明还在用无符号");
        System.out.println("测试结果: " + (test3Pass ? "✅ 通过 (有符号)" : "❌ 失败 (可能是无符号)"));
        if (test3Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试4: 2字节有符号 - 正数 ==========
        System.out.println("【测试4】2字节有符号 - 正数");
        byte[] data4 = new byte[]{0x7F, (byte) 0xFF}; // 32767
        UniversalReadAndWriteReturn result4 = readModbusByteArrayParamValue(
                data4, 0, 0, 0, 2,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB", 1.0, 0
        );
        long value4 = (Long) result4.getOriginalValue();
        boolean test4Pass = value4 == 32767L;
        System.out.println("原始数据(HEX): 0x7FFF");
        System.out.println("读取值: " + value4);
        System.out.println("期望值: 32767 (有符号和无符号都相同)");
        System.out.println("测试结果: " + (test4Pass ? "✅ 通过" : "❌ 失败"));
        if (test4Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试5: 2字节有符号 - 负数 ==========
        System.out.println("【测试5】2字节有符号 - 最高位为1");
        byte[] data5 = new byte[]{(byte) 0xFF, (byte) 0xFF}; // -1 (有符号) 或 65535 (无符号)
        UniversalReadAndWriteReturn result5 = readModbusByteArrayParamValue(
                data5, 0, 0, 0, 2,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB", 1.0, 0
        );
        long value5 = (Long) result5.getOriginalValue();
        boolean test5Pass = value5 == -1L;
        System.out.println("原始数据(HEX): 0xFFFF");
        System.out.println("读取值: " + value5);
        System.out.println("期望值: -1 (有符号) / 如果是65535则说明还在用无符号");
        System.out.println("测试结果: " + (test5Pass ? "✅ 通过 (有符号)" : "❌ 失败 (可能是无符号)"));
        if (test5Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试6: 2字节有符号 - 其他负数 ==========
        System.out.println("【测试6】2字节有符号 - 其他负数");
        byte[] data6 = new byte[]{(byte) 0x80, 0x00}; // -32768 (有符号) 或 32768 (无符号)
        UniversalReadAndWriteReturn result6 = readModbusByteArrayParamValue(
                data6, 0, 0, 0, 2,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB", 1.0, 0
        );
        long value6 = (Long) result6.getOriginalValue();
        boolean test6Pass = value6 == -32768L;
        System.out.println("原始数据(HEX): 0x8000");
        System.out.println("读取值: " + value6);
        System.out.println("期望值: -32768 (有符号) / 如果是32768则说明还在用无符号");
        System.out.println("测试结果: " + (test6Pass ? "✅ 通过 (有符号)" : "❌ 失败 (可能是无符号)"));
        if (test6Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试7: 4字节有符号 - 正数 ==========
        System.out.println("【测试7】4字节有符号 - 正数");
        byte[] data7 = new byte[]{0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; // 2147483647
        UniversalReadAndWriteReturn result7 = readModbusByteArrayParamValue(
                data7, 0, 0, 0, 4,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB CD", 1.0, 0
        );
        long value7 = (Long) result7.getOriginalValue();
        boolean test7Pass = value7 == 2147483647L;
        System.out.println("原始数据(HEX): 0x7FFFFFFF");
        System.out.println("读取值: " + value7);
        System.out.println("期望值: 2147483647 (有符号和无符号都相同)");
        System.out.println("测试结果: " + (test7Pass ? "✅ 通过" : "❌ 失败"));
        if (test7Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试8: 4字节有符号 - 负数 ==========
        System.out.println("【测试8】4字节有符号 - 最高位为1");
        byte[] data8 = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; // -1 (有符号) 或 4294967295 (无符号)
        UniversalReadAndWriteReturn result8 = readModbusByteArrayParamValue(
                data8, 0, 0, 0, 4,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB CD", 1.0, 0
        );
        long value8 = (Long) result8.getOriginalValue();
        boolean test8Pass = value8 == -1L;
        System.out.println("原始数据(HEX): 0xFFFFFFFF");
        System.out.println("读取值: " + value8);
        System.out.println("期望值: -1 (有符号) / 如果是4294967295则说明还在用无符号");
        System.out.println("测试结果: " + (test8Pass ? "✅ 通过 (有符号)" : "❌ 失败 (可能是无符号)"));
        if (test8Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试9: 4字节有符号 - 其他负数 ==========
        System.out.println("【测试9】4字节有符号 - 其他负数");
        byte[] data9 = new byte[]{(byte) 0x80, 0x00, 0x00, 0x00}; // -2147483648 (有符号) 或 2147483648 (无符号)
        UniversalReadAndWriteReturn result9 = readModbusByteArrayParamValue(
                data9, 0, 0, 0, 4,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB CD", 1.0, 0
        );
        long value9 = (Long) result9.getOriginalValue();
        boolean test9Pass = value9 == -2147483648L;
        System.out.println("原始数据(HEX): 0x80000000");
        System.out.println("读取值: " + value9);
        System.out.println("期望值: -2147483648 (有符号) / 如果是2147483648则说明还在用无符号");
        System.out.println("测试结果: " + (test9Pass ? "✅ 通过 (有符号)" : "❌ 失败 (可能是无符号)"));
        if (test9Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试10: 8字节有符号 - 正数 ==========
        System.out.println("【测试10】8字节有符号 - 正数");
        byte[] data10 = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, (byte) 0xE8}; // 1000
        UniversalReadAndWriteReturn result10 = readModbusByteArrayParamValue(
                data10, 0, 0, 0, 8,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB CD EF GH", 1.0, 0
        );
        long value10 = (Long) result10.getOriginalValue();
        boolean test10Pass = value10 == 1000L;
        System.out.println("原始数据(HEX): 0x00000000000003E8");
        System.out.println("读取值: " + value10);
        System.out.println("期望值: 1000");
        System.out.println("测试结果: " + (test10Pass ? "✅ 通过" : "❌ 失败"));
        if (test10Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试11: 8字节有符号 - 负数 ==========
        System.out.println("【测试11】8字节有符号 - 最高位为1");
        byte[] data11 = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 
                                    (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; // -1
        UniversalReadAndWriteReturn result11 = readModbusByteArrayParamValue(
                data11, 0, 0, 0, 8,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB CD EF GH", 1.0, 0
        );
        long value11 = (Long) result11.getOriginalValue();
        boolean test11Pass = value11 == -1L;
        System.out.println("原始数据(HEX): 0xFFFFFFFFFFFFFFFF");
        System.out.println("读取值: " + value11);
        System.out.println("期望值: -1 (有符号)");
        System.out.println("测试结果: " + (test11Pass ? "✅ 通过 (有符号)" : "❌ 失败"));
        if (test11Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试12: 写入后回读验证 - 负数 ==========
        System.out.println("【测试12】写入负数后回读验证");
        byte[] data12 = new byte[4];
        writeModbusByteArrayParamValue(
                data12, 0, 0, 0, 4,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB CD",
                -100, // 写入负数
                1.0, 0
        );
        UniversalReadAndWriteReturn result12 = readModbusByteArrayParamValue(
                data12, 0, 0, 0, 4,
                DevConst.OffsetUnits.BYTE,
                DevConst.DataType.INTEGER,
                "AB CD", 1.0, 0
        );
        long value12 = (Long) result12.getOriginalValue();
        boolean test12Pass = value12 == -100L;
        System.out.println("写入值: -100");
        System.out.println("回读值: " + value12);
        System.out.println("原始数据(HEX): " + HexUtil.encodeHexStr(data12).toUpperCase());
        System.out.println("期望值: -100");
        System.out.println("测试结果: " + (test12Pass ? "✅ 通过" : "❌ 失败"));
        if (test12Pass) passCount++; else failCount++;
        System.out.println();

        // ========== 测试总结 ==========
        System.out.println("========================================");
        System.out.println("            测试总结");
        System.out.println("========================================");
        System.out.println("总测试数: " + (passCount + failCount));
        System.out.println("✅ 通过: " + passCount);
        System.out.println("❌ 失败: " + failCount);
        System.out.println("通过率: " + String.format("%.1f%%", (passCount * 100.0 / (passCount + failCount))));
        System.out.println("========================================");
        System.out.println();
        
        if (failCount == 0) {
            System.out.println("🎉 所有测试全部通过!");
            System.out.println("✅ 确认:整数处理已改为有符号方式");
        } else {
            System.out.println("⚠️  有测试失败!");
            if (failCount >= 6) {
                System.out.println("❌ 可能仍在使用无符号处理(失败的测试主要集中在负数检测)");
            } else {
                System.out.println("⚠️  部分场景有问题,请检查具体失败的测试");
            }
        }
        System.out.println();
    }

    /**
     * 去除字符串末尾的空字符(\0)和空白字符
     * 
     * @param originalValue 原始字符串
     * @return 去除末尾空字符和空白字符后的字符串
     */
    public static String trimTrailingNullAndWhitespace(String originalValue) {
        if (originalValue == null || originalValue.isEmpty()) {
            return originalValue;
        }
        
        int endIndex = originalValue.length();
        while (endIndex > 0 && (originalValue.charAt(endIndex - 1) == '\0' || Character.isWhitespace(originalValue.charAt(endIndex - 1)))) {
            endIndex--;
        }
        return originalValue.substring(0, endIndex);
    }

}
package com.tigeriot.deviceduplexcodingservice.duplexcoding.tcp.modbus.duplex.model;


import com.fasterxml.jackson.annotation.JsonIgnore;
import com.tigeriot.deviceduplexcodingservice.api.productmanager.devDefineParam.DevDefineParamBring;
import com.tigeriot.deviceduplexcodingservice.api.tcp.modbus.modbusParam.service.ModbusParamBring;
import com.tigeriot.globalcommonservice.model.productmanagerservice.iot.rundev.DevConst;
import com.tigeriot.globalcommonservice.model.productmanagerservice.modbusManager.utils.ModbusManagerUtils;
import com.tigeriot.productmanagerserviceapiclient.model.modbusManager.modbusParam.entity.ModbusParam;
import com.tigeriot.productmanagerserviceapiclient.model.modbusManager.modbusParamBindTemplateRelation.entity.ModbusParamBindTemplateRelation;
import com.tigeriot.productmanagerserviceapiclient.model.productRegister.devDefineParam.entity.DevDefineParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@Data
public class ModbusParamCompleteTemplate extends ModbusParamBindTemplateRelation implements ModbusParamBring, DevDefineParamBring, Comparable<ModbusParamCompleteTemplate> {


    @Schema(description = "设备定义参数ID")
    private String devDefineParamId;

    @Schema(description = "参数名称")
    private String paramName;


    @Schema(description = "设备参数唯一编码 对应实体字段名参数")
    private String devParamUniqueCode;

    @Schema(description = "读取寄存器终止地址 读取不到的位置 必须小于它才能够读取")
    @JsonIgnore
    private Integer readRegisterFinalAddressDec;


    @Schema(description = "读取寄存器起始地址 已经计算过偏移量的")
    @JsonIgnore
    private Integer startRegisterOffsetAddressDec;

    @Override
    public void bringModbusParam(ModbusParam modbusParam) {
        this.devDefineParamId = modbusParam.getDevDefineParamId();
    }

    @Override
    public String provideModbusParamId() {
        return this.getModbusParamId();
    }

    @Override
    public void bringDevDefineParam(DevDefineParam devDefineParam) {
        this.paramName = devDefineParam.getParamName();
        this.devParamUniqueCode = devDefineParam.getDevParamUniqueCode();
    }

    @Override
    public String provideDevDefineParamId() {
        return this.devDefineParamId;
    }


    /**
     * 获取改参数所读取最终寄存器地址 读取不到的开始 10进制
     *
     * @return
     */
    public Integer getReadRegisterFinalAddressDec() {
        if (this.readRegisterFinalAddressDec != null) {
            return this.readRegisterFinalAddressDec;
        }
        Integer registerAddressDec = this.getRegisterAddressDec();
        //这是计算最终寄存器地址 注意:计算起始地址是属于自己值范围 计算最终地址是自己所在值范围寄存器地址+1
        this.readRegisterFinalAddressDec = ModbusManagerUtils.offsetDec(registerAddressDec, DevConst.OffsetUnits.create(this.getOffsetUnit()), this.getOffsetNum() + this.getOffsetStartIndex());
        return this.readRegisterFinalAddressDec;
    }

    /**
     * 获取改参数所读取起始寄存器地址 读取不到的开始 10进制
     *
     * @return
     */
    public Integer getStartRegisterOffsetAddressDec() {
        if (this.startRegisterOffsetAddressDec != null) {
            return this.startRegisterOffsetAddressDec;
        }
        Integer registerAddressDec = this.getRegisterAddressDec();
        //这是计算起始寄存器地址  注意:计算起始地址是属于自己值范围 计算最终地址是自己所在值范围寄存器地址+1
        this.startRegisterOffsetAddressDec = ModbusManagerUtils.offsetDec(registerAddressDec, DevConst.OffsetUnits.create(this.getOffsetUnit()), this.getOffsetStartIndex());
        return this.startRegisterOffsetAddressDec;
    }

    @Override
    public int compareTo(ModbusParamCompleteTemplate o2) {
        // 统一转换为位单位进行比较,确保精确性
        int thisStartPositionInBits = calculateStartPositionInBits(this);
        int o2StartPositionInBits = calculateStartPositionInBits(o2);
        
        int compare = Integer.compare(thisStartPositionInBits, o2StartPositionInBits);
        if (compare == 0) {
            // 如果开始位置相同,则比较寄存器地址
            return this.getRegisterAddressDec().compareTo(o2.getRegisterAddressDec());
        } else {
            return compare;
        }
    }

    /**
     * 计算参数在总体地址空间中的起始位置(以位为单位)
     *
     * @param param 参数对象
     * @return 起始位置(位单位)
     */
    private int calculateStartPositionInBits(ModbusParamCompleteTemplate param) {
        int registerAddress = param.getRegisterAddressDec();
        int offsetStartIndex = param.getOffsetStartIndex();
        String offsetUnit = param.getOffsetUnit();
        
        if (DevConst.OffsetUnits.BYTE.value.equals(offsetUnit)) {
            // 字节偏移:寄存器地址转字节 + 字节偏移,再转为位
            int positionInBytes = registerAddress * ModbusManagerUtils.RegisterAddressByteLength + offsetStartIndex;
            return positionInBytes * ModbusManagerUtils.ByteToBitLength;
        } else {
            // 位偏移:寄存器地址转位 + 位偏移
            return registerAddress * ModbusManagerUtils.RegisterAddressBitLength + offsetStartIndex;
        }
    }

    /**
     * 判断两个参数地址是否连续 要保证排过序之后调用这个方法
     *
     * @param o2 是否与该对象连续 若冲突则跳过O2
     *           |00 00 |00 00 00 00 00
     * @return true表示连续,false表示不连续
     */
    public boolean continuous(ModbusParamCompleteTemplate o2) {
        // 统一转换为位单位进行计算
        int thisEndPositionInBits = calculateEndPositionInBits(this);
        int o2StartPositionInBits = calculateStartPositionInBits(o2);
        
        // 判断当前参数的结束位置是否等于下一个参数的开始位置
        return thisEndPositionInBits == o2StartPositionInBits;
    }

    /**
     * 计算参数在总体地址空间中的结束位置(以位为单位)
     *
     * @param param 参数对象
     * @return 结束位置(位单位)
     */
    private int calculateEndPositionInBits(ModbusParamCompleteTemplate param) {
        int startPosition = calculateStartPositionInBits(param);
        int offsetNum = param.getOffsetNum();
        String offsetUnit = param.getOffsetUnit();
        
        if (DevConst.OffsetUnits.BYTE.value.equals(offsetUnit)) {
            // 字节偏移:偏移数量转为位
            return startPosition + (offsetNum * ModbusManagerUtils.ByteToBitLength);
        } else {
            // 位偏移:直接加上位数量
            return startPosition + offsetNum;
        }
    }
}
/**
     * 获取写入消息 肯定是变化过后的
     *
     * @param updateData
     * @return
     */
    public TigerIotMessage getWriteMessage(RunDevModbusCompleteTemplate runDevModbusCompleteTemplate, Map<String, Object> updateData) throws CodeException {

        ModbusParamCompleteTemplate first = params.getFirst();
        ModbusParamCompleteTemplate last = params.getLast();

        //起始偏移地址
        Integer startRegisterOffsetAddressDec = first.getStartRegisterOffsetAddressDec();

        Integer lastRegisterAddress = last.getReadRegisterFinalAddressDec();
        //计算出字节数组长度

        int phaseDifferenceRegister = lastRegisterAddress - startRegisterOffsetAddressDec;
        if (phaseDifferenceRegister == 0) {
            phaseDifferenceRegister = 1;
        }
        int byteLength = (phaseDifferenceRegister) * ModbusManagerUtils.RegisterAddressByteLength;
        byte[] data = new byte[byteLength];

        for (ModbusParamCompleteTemplate param : params) {
            //写入
            try {
                ModbusManagerUtils.writeModbusByteArrayParamValue(
                        data,
                        startRegisterOffsetAddressDec,
                        param.getRegisterAddressDec(),
                        param.getOffsetStartIndex(),
                        param.getOffsetNum(),
                        DevConst.OffsetUnits.create(param.getOffsetUnit()),
                        DevConst.DataType.create(param.getDataType()),
                        param.getDataTerminalType(),
                        updateData.get(param.getDevParamUniqueCode()),
                        param.getConversionFactor(),
                        param.getAccuracy()
                );
            } catch (CodeException e) {
                log.error(StrUtil.format("写入参数不合法 参数名称:{} 参数key:{}", param.getParamName(), param.getDevParamUniqueCode()), e);
                throw e;
            }
        }
        String command;
        if (data.length == 2) {
            command = ModbusManagerUtils.generateSingleWriteRegisterCommand(runDevModbusCompleteTemplate.getModbusAddress().byteValue(), startRegisterOffsetAddressDec, data[0], data[1]);
        } else if (data.length > 2) {
            command = ModbusManagerUtils.generateMultiWriteRegisterCommand(runDevModbusCompleteTemplate.getModbusAddress().byteValue(), startRegisterOffsetAddressDec, data);
        } else {
            throw new CodeException(HttpStatus.BAD_REQUEST.value(), "写入数据长度不合法 数据字节长度必须大于等于2");
        }
        return TigerIotMessage.send(runDevModbusCompleteTemplate.getImei(), DevConst.MessageType.write, command, DevConst.ProtocolType.MODBUS_RTU, DevConst.TransportProtocol.TCP);
    }

  /**
     * 根据寄存器地址以及字节和位连续来分组区分区间
     * 将相邻的Modbus参数放在一组,支持字节和位级别的连续性判断
     *
     * @param modbusParam 原始Modbus参数列表
     * @param updateField 更新字段映射,用于日志输出
     * @return 按连续性分组的参数列表
     */
    @Override
    public List<RegisterContinuousIntervalGrouping> groupByContinuouslyRegisterAddress(List<ModbusParamCompleteTemplate> modbusParam, Map<String, Object> updateField) {
        // 1. 过滤有效参数:只保留开启命令同步的读写参数
        List<ModbusParamCompleteTemplate> validParams = modbusParam.stream()
                .filter(param -> {
                    try {
                        isEffectiveModbusParamCompleteTemplate(param);
                        // 必须开启同步且为读写参数
                        return param.isEnableCommandSync() && param.getType() == DevConst.ParamType.READ_WRITE.value;
                    } catch (CodeException e) {
                        log.trace("ModbusRTU解析 过滤了不合法的参数: {}", param.getDevParamUniqueCode());
                        return false;
                    }
                })
                .sorted(ModbusParamCompleteTemplate::compareTo)
                .toList();

        if (validParams.isEmpty()) {
            log.debug("ModbusRTU解析 精确过滤校验 没有需要同步的参数");
            return new ArrayList<>();
        }

        // 2. 按连续性进行分组
        List<RegisterContinuousIntervalGrouping> groupList = new ArrayList<>();
        RegisterContinuousIntervalGrouping currentGroup = new RegisterContinuousIntervalGrouping();
        currentGroup.add(validParams.getFirst()); // 添加第一个参数

        for (int i = 1; i < validParams.size(); i++) {
            ModbusParamCompleteTemplate currentParam = validParams.get(i);
            ModbusParamCompleteTemplate lastParamInGroup = currentGroup.getParams().getLast();

            // 判断当前参数是否与分组中最后一个参数连续
            if (lastParamInGroup.continuous(currentParam)) {
                // 连续则添加到当前分组
                currentGroup.add(currentParam);
            } else {
                // 不连续则保存当前分组,创建新分组
                groupList.add(currentGroup);
                currentGroup = new RegisterContinuousIntervalGrouping();
                currentGroup.add(currentParam);
            }
        }

        // 添加最后一个分组(如果存在)
        if (!currentGroup.getParams().isEmpty()) {
            groupList.add(currentGroup);
        }

        // 3. 输出分组信息用于调试
        logGroupingResults(groupList, updateField);

        return groupList;
    }

    /**
     * 输出分组结果日志
     *
     * @param groupList   分组列表
     * @param updateField 更新字段映射
     */
    private void logGroupingResults(List<RegisterContinuousIntervalGrouping> groupList, Map<String, Object> updateField) {
        for (int i = 0; i < groupList.size(); i++) {
            int groupNumber = i + 1;
            log.debug("ModbusRTU解析 ============= 分组 同步参数 第{}组 开始 =============", groupNumber);

            RegisterContinuousIntervalGrouping group = groupList.get(i);
            List<ModbusParamCompleteTemplate> params = group.getParams();

            for (ModbusParamCompleteTemplate param : params) {
                log.debug("ModbusRTU解析 参数名:{}, 参数key:{}, 参数值:{}",
                        param.getParamName(),
                        param.getDevParamUniqueCode(),
                        updateField.get(param.getDevParamUniqueCode()));
            }

            log.debug("ModbusRTU解析 ============= 分组 同步参数 第{}组 结束 =============", groupNumber);
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值