package com.zehong.system.modbus.util;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.ip.tcp.TcpMaster;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.*;
import com.zehong.system.modbus.handler.ModbusResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * modbus通讯工具类,采用modbus4j实现
 *
 */
@SuppressWarnings(value = "all")
public class Modbus4jUtils {

    private static final Logger log = LoggerFactory.getLogger(Modbus4jUtils.class);

    private static ModbusMaster master;

    private static final int START_ADDRESS = 0;  // 对应40001
    private static final int REGISTER_COUNT = 15; // 读取15个寄存器
    private static final int TARGET_VALUE = 1;   // 目标值（第二个寄存器的期望值）
    private static final int MAX_RETRIES = 3;    // 最大重试次数
    private static final int RETRY_DELAY = 500;  // 重试延迟(ms)// 监控参数
    private static final int MONITOR_INTERVAL = 5000; // 监控间隔(ms)
    // Modbus配置：取消内置重试，统一用自定义重试
    private static final int MODBUS_CONN_TIMEOUT_MS = 3000; // 连接超时：3秒
    private static final int CUSTOM_RETRY_TIMES = 2; // 自定义重试次数：1次

    // 监控控制标志
    private static final AtomicBoolean monitoring = new AtomicBoolean(false);

    /**
     * 工厂。
     */
    static ModbusFactory modbusFactory;
    static {
        if (modbusFactory == null) {
            modbusFactory = new ModbusFactory();
        }
    }
    /**
     * 获取master
     *
     * @return master
     * @throws ModbusInitException m
     */
    public static ModbusMaster getMaster() throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost("192.168.2.11");
        params.setPort(502);
        //
        // modbusFactory.createRtuMaster(wapper); //RTU 协议
        // modbusFactory.createUdpMaster(params);//UDP 协议
        // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
        if(master == null || !master.isConnected()) {
            master = modbusFactory.createTcpMaster(params, true);// TCP 协议
            master.setTimeout(5000); // 设置超时时间
            master.setRetries(3);    // 设置重试次数
            master.init();
        }

        return master;
    }

    // -------------------------- Modbus工具方法（显式抛出异常）--------------------------
    /**
     * 创建Modbus连接（取消内置重试，统一自定义重试）
     */
    public static ModbusMaster createModbusMaster(String ip, int port) throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost(ip);
        params.setPort(port);

        TcpMaster master = (TcpMaster) modbusFactory.createTcpMaster(params, true);
        master.setTimeout(MODBUS_CONN_TIMEOUT_MS);
        master.setRetries(0);
        master.init();
        return master;
    }

    /**
     * 销毁Modbus连接（反射失败直接抛出异常，显式暴露问题）
     */
    public static void destroyModbusMaster(ModbusMaster master, int deviceId) {
        if (master != null) {
            try {
                master.destroy();
            } catch (Exception e) {
                log.debug("设备{}: ModbusMaster销毁异常", deviceId, e);
            }
        }
    }
    /**
     * 读取[01 Coil Status 0x]类型 开关数据
     *
     * @param slaveId
     *            slaveId
     * @param offset
     *            位置
     * @return 读取值
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     * @throws ModbusInitException
     *             异常
     */
    public static Boolean readCoilStatus(int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 01 Coil Status
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        Boolean value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读一下 开关数据
     * @param master
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     */
    public static Boolean readCoilStatus(ModbusMaster master, int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 01 Coil Status
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        Boolean value = master.getValue(loc);
        return value;
    }

    /**
     * 读取[02 Input Status 1x]类型 开关数据
     *
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     */
    public static Boolean readInputStatus(int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 02 Input Status
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        Boolean value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[02 Input Status 1x]类型 开关数据
     *
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     */
    public static Boolean readInputStatus(ModbusMaster master,int slaveId, int offset)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 02 Input Status
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        Boolean value = master.getValue(loc);
        return value;
    }

    /**
     * 机械臂入口传送带 0位置是 投入点，1位置是 末尾点
     * @param slaveId
     * @param registerOffsets
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static boolean[] getRoboticArmEntryConveyorData(){

        ModbusMaster master = null;
        try {
            master = createModbusMaster("192.168.1.11", 503);
            boolean[] booleans = readDiscreteInputs(master, 1, 0, 2);

            if(master != null) {
                master.destroy();
            }

            return booleans;
        } catch (ModbusTransportException | ModbusInitException e) {
            return  new boolean[]{false, false}; // 示例数据
        } finally {
            if(master != null) {
                master.destroy();
            }
        }
    }

    /**
     * 机械臂出库传送带 0位置是 投入点，1位置是 末尾点
     * @param slaveId
     * @param registerOffsets
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static boolean[] getRoboticArmExitConveyorData(String ip, int port) {
        ModbusMaster master = null;
        try {
            master = createModbusMaster(ip, port);
            boolean[] booleans = readDiscreteInputs(master, 1, 0, 2);

            if(master != null) {
                master.destroy();
            }

            return booleans;
        } catch (ModbusTransportException | ModbusInitException e) {
            return  new boolean[]{false, false}; // 示例数据
        } finally {
            if(master != null) {
                master.destroy();
            }
        }
    }

    /**
     * 读取离散输入（功能码02）的兼容方法
     * 使用ReadDiscreteInputsRequest/Response，适配更多版本
     */
    private static boolean[] readDiscreteInputs(ModbusMaster master, int slaveId,
                                                int startAddress, int count) throws ModbusTransportException {
        // 创建功能码02对应的请求（ReadDiscreteInputsRequest）
        ModbusRequest request = new ReadDiscreteInputsRequest(slaveId, startAddress, count);

        // 发送请求并获取响应
        ModbusResponse response = master.send(request);

        // 转换为具体的响应类型
        if (response instanceof ReadDiscreteInputsResponse) {
            ReadDiscreteInputsResponse discreteResponse = (ReadDiscreteInputsResponse) response;
            return discreteResponse.getBooleanData();
        } else {
            throw new ModbusTransportException("无效的响应类型: " + response.getClass().getSimpleName());
        }
    }
    /**
     * 读取[03 Holding Register类型 2x]模拟量数据
     *
     * @param slaveId
     *            slave Id
     * @param offset
     *            位置
     * @param dataType
     *            数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     * @throws ModbusInitException
     *             异常
     */
    public static Number readHoldingRegister(int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 03 Holding Register类型数据读取
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        return value;
    }

    /**
     * 读取[04 Input Registers 3x]类型 模拟量数据
     *
     * @param slaveId
     *            slaveId
     * @param offset
     *            位置
     * @param dataType
     *            数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return 返回结果
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     * @throws ModbusInitException
     *             异常
     */
    public static Number readInputRegisters(int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 04 Input Registers类型数据读取
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(loc);
        return value;
    }

    /**
     *
     * @param master
     * @param slaveId
     * @param offset
     * @param length
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     */
    /**
     * 读取[04 Input Registers 3x]类型 模拟量数据
     *
     * @param master
     *          master
     * @param slaveId
     *            slaveId
     * @param offset
     *            位置
     * @param dataType
     *            数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return 返回结果
     * @throws ModbusTransportException
     *             异常
     * @throws ErrorResponseException
     *             异常
     * @throws ModbusInitException
     *             异常
     */
    public static Number readInputRegisters(ModbusMaster master,int slaveId, int offset, int dataType)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 04 Input Registers类型数据读取
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
        Number value = master.getValue(loc);
        return value;
    }

    /**
     * 读老化柜的 10层数据
     * @param master
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     * @throws ModbusInitException
     */
    public static Map<Integer, Object>  readInputRegistersForAgeng(ModbusMaster master)
            throws ModbusTransportException, ErrorResponseException {
        // 10 层
        List<Integer> registerOffsets = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        Map<Integer, Object> result = new HashMap<>();
        for (Integer registerOffset : registerOffsets) {
            // 04 Input Registers类型数据读取
            BaseLocator<Number> loc = BaseLocator.inputRegister(1, registerOffset, DataType.TWO_BYTE_INT_UNSIGNED);
            Number value = master.getValue(loc);
            result.put(registerOffset, value);
        }
        return result;
    }

    /**
     * 批量读取使用方法
     *
     * @throws ModbusTransportException m
     * @throws ErrorResponseException e
     * @throws ModbusInitException m
     */
    public static void batchRead() throws ModbusTransportException, ErrorResponseException, ModbusInitException {

        BatchRead<Integer> batch = new BatchRead<Integer>();

        batch.addLocator(0, BaseLocator.holdingRegister(1, 1, DataType.FOUR_BYTE_FLOAT));
        batch.addLocator(1, BaseLocator.inputStatus(1, 0));

        ModbusMaster master = getMaster();

        batch.setContiguousRequests(false);
        BatchResults<Integer> results = master.send(batch);
        System.out.println(results.getValue(0));
        System.out.println(results.getValue(1));
    }

    public static Map<Integer,Object> batchReadHoldingRegister(ModbusMaster master,List<Integer> registerOffsets) throws ModbusTransportException, ErrorResponseException {
        BatchRead<Integer> batch = new BatchRead<Integer>();
        for (Integer registerOffset : registerOffsets) {
            batch.addLocator(registerOffset, BaseLocator.holdingRegister(1, registerOffset,DataType.EIGHT_BYTE_INT_UNSIGNED));
        }

        // 非连续地址也支持
        batch.setContiguousRequests(true);

        BatchResults<Integer> send = master.send(batch);
//
        Map<Integer, Object> result = new HashMap<>();
        for (Integer registerOffset : registerOffsets) {
            result.put(registerOffset, send.getValue(registerOffset));
        }
        return result;
    }


    /**
     * 批量读取使用方法
     *
     * @throws ModbusTransportException m
     * @throws ErrorResponseException e
     * @throws ModbusInitException m
     */
    public static Map<Integer, Object> batchReadAgingCabinetStatus(ModbusMaster master, List<Integer> registerOffsets) throws ModbusInitException, ModbusTransportException, ErrorResponseException {

        // 把设备集成到一个交换机上后 这个批量读取 不管用了。。
        BatchRead<Integer> batch = new BatchRead<Integer>();
        for (Integer registerOffset : registerOffsets) {
            batch.addLocator(registerOffset, BaseLocator.inputStatus(1, registerOffset));
        }

        // 非连续地址也支持
        batch.setContiguousRequests(true);

        BatchResults<Integer> send = master.send(batch);
        Map<Integer, Object> result = new HashMap<>();
        for (Integer registerOffset : registerOffsets) {
            result.put(registerOffset, send.getValue(registerOffset));
        }
        return result;

//        Map<Integer, Object> result = new HashMap<>();
//        for (Integer registerOffset : registerOffsets) {
//            Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffset);
//            result.put(registerOffset, aBoolean);
//        }
//        return result;
    }

    /**
     * 读取保持寄存器（16位无符号整数）
     *
     * @param slaveId  从站ID
     * @param offset   寄存器起始地址（0-based）
     * @param count    读取的寄存器数量
     * @return 无符号整数值数组
     * 请求格式解析：
     * 00 00 - 事务ID (0)
     * 00 00 - 协议ID (0)
     * 00 06 - 长度 (6字节)
     * 01 - 从站ID (1)
     * 03 - 功能码 (读保持寄存器)
     * 00 03 - 起始地址 (3)
     * 00 0A - 寄存器数量 (10)
     * 响应格式解析：
     * 00 00 00 00 00 17 - Modbus TCP头
     * 01 - 从站ID
     * 03 - 功能码
     * 14 - 数据字节数 (20字节 = 10寄存器 × 2字节)
     * 后续20字节为10个寄存器的数据
     * 关键处理逻辑：
     * 16位无符号转换：register.getValue() & 0xFFFF
     * 寄存器地址处理：modbus4j使用0-based地址，所以地址3对应设备手册中的40004寄存器
     * TCP连接管理：使用长连接提高效率
     */
    public static int[] readHoldingRegisters(int slaveId, int offset, int count)
            throws ModbusTransportException, ErrorResponseException {

        // 创建读取请求
        ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(
                slaveId, offset, count
        );

        // 发送请求并获取响应
        ModbusResponse response = master.send(request);

        // 检查响应类型
        if (!(response instanceof ReadHoldingRegistersResponse)) {
            throw new IllegalArgumentException("Invalid response type: " + response.getClass().getName());
        }

        // 获取寄存器列表
        ReadHoldingRegistersResponse regResponse = (ReadHoldingRegistersResponse) response;
        short[] signedValues = regResponse.getShortData();
        // 转换为无符号整数
        int[] results = new int[signedValues.length];
        // 转为无符号整数并打印
        for (int i = 0; i < signedValues.length; i++) {
            int unsignedValue = signedValues[i] & 0xFFFF;
            results[i] = signedValues[i] & 0xFFFF;
            System.out.printf("寄存器 %d: %d (无符号) %n", i, unsignedValue);
        }
        return results;
    }

    /**
     * 写 [01 Coil Status(0x)]写一个 function ID = 5
     *
     * @param slaveId
     *            slave的ID
     * @param writeOffset
     *            位置
     * @param writeValue
     *            值
     * @return 是否写入成功
     * @throws ModbusTransportException m
     * @throws ModbusInitException m
     */
    public static boolean writeCoil(int slaveId, int writeOffset, boolean writeValue)
            throws ModbusTransportException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 创建请求
        WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
        // 发送请求并获取响应对象
        WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
        if (response.isException()) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 写[01 Coil Status(0x)] 写一个 function ID = 5
     * @param master
     * @param slaveId
     * @param writeOffset
     * @param writeValue
     * @return
     * @throws ModbusTransportException
     */
    public static boolean writeCoil(ModbusMaster master, int slaveId, int writeOffset, boolean writeValue) throws ModbusTransportException {
        // 创建请求
        WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
        // 发送请求并获取响应对象
        WriteCoilResponse response = (WriteCoilResponse) master.send(request);
        if (response.isException()) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 写[01 Coil Status(0x)] 写多个 function ID = 15
     *
     * @param slaveId
     *            slaveId
     * @param startOffset
     *            开始位置
     * @param bdata
     *            写入的数据
     * @return 是否写入成功
     * @throws ModbusTransportException m
     * @throws ModbusInitException m
     */
    public static boolean writeCoils(int slaveId, int startOffset, boolean[] bdata)
            throws ModbusTransportException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 创建请求
        WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
        // 发送请求并获取响应对象
        WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
        if (response.isException()) {
            return false;
        } else {
            return true;
        }

    }
    /**
     * 写入单个 Holding Register（功能码 6）
     *
     * @param slaveId     从站ID
     * @param writeOffset 寄存器偏移地址（如 0 表示地址 40001）
     * @param writeValue  要写入的值（short 类型）
     * @return 是否写入成功
     * @throws ModbusTransportException 如果传输失败
     * @throws ModbusInitException      如果初始化失败
     */
    public static boolean writeRegister(ModbusMaster master ,int slaveId, int writeOffset, short writeValue)
            throws ModbusTransportException, ModbusInitException {

        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);

        log.info("发送写入请求：从站={}, 地址={}, 值={}", slaveId, writeOffset, writeValue);

        WriteRegisterResponse response = null;
        synchronized (master) { // 多线程下保护主站资源
            response = (WriteRegisterResponse) master.send(request);
        }

        if (response == null) {
            log.error("未收到 Modbus 响应");
            return false;
        }

        if (response.isException()) {
            log.error("Modbus 异常响应: {}", response.getExceptionMessage());
            return false;
        }

        int writeValue1 = response.getWriteValue();

        log.info("写入成功，写入值={}", writeValue1);

        log.info("写入成功，响应确认");
        return true;
    }
    /**
     * 写入单个 Holding Register（功能码 6）
     *
     * @param slaveId     从站ID
     * @param writeOffset 寄存器偏移地址（如 0 表示地址 40001）
     * @param writeValue  要写入的值（short 类型）
     * @return 是否写入成功
     * @throws ModbusTransportException 如果传输失败
     * @throws ModbusInitException      如果初始化失败
     */
    public static boolean writeRegister(int slaveId, int writeOffset, short writeValue)
            throws ModbusTransportException, ModbusInitException {
        ModbusMaster master = getMaster();

        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);

        log.info("发送写入请求：从站={}, 地址={}, 值={}", slaveId, writeOffset, writeValue);

        WriteRegisterResponse response = null;
        synchronized (master) { // 多线程下保护主站资源
            response = (WriteRegisterResponse) master.send(request);
        }

        if (response == null) {
            log.error("未收到 Modbus 响应");
            return false;
        }

        if (response.isException()) {
            log.error("Modbus 异常响应: {}", response.getExceptionMessage());
            return false;
        }

        log.info("写入成功，响应确认");
        return true;
    }

    /**
     * 使用功能码16写入多个保持寄存器（更稳定，支持批量）
     */
    public static boolean writeRegistersMultiple(ModbusMaster master, int slaveId,
                                                 int startOffset, short[] values)
            throws ModbusTransportException, ModbusInitException {

        log.info("发送批量写入请求：从站={}, 起始地址={}, 数量={}, 值={}",
                slaveId, startOffset, values.length, Arrays.toString(values));

        WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, values);
        WriteRegistersResponse response = null;

        synchronized (master) {
            response = (WriteRegistersResponse) master.send(request);
        }

        if (response == null) {
            log.error("未收到 Modbus 响应");
            return false;
        }

        if (response.isException()) {
            log.error("Modbus 异常响应: {}", response.getExceptionMessage());
            return false;
        }

        log.info("批量写入成功，起始地址={}, 写入数量={}", startOffset, values.length);
        return true;
    }

    /**
     * 写入时间（使用功能码16一次性写入所有时间寄存器）
     */
    public static boolean writeTimeRegisters(ModbusMaster master, int deviceId) {
        try {
            Calendar cal = Calendar.getInstance();
            short[] timeValues = {
                    (short) cal.get(Calendar.YEAR),
                    (short) (cal.get(Calendar.MONTH) + 1),
                    (short) cal.get(Calendar.DATE),
                    (short) cal.get(Calendar.HOUR_OF_DAY),
                    (short) cal.get(Calendar.MINUTE)
            };

            // 一次性写入所有时间寄存器
            return writeRegistersMultiple(master, deviceId, 4, timeValues);

        } catch (Exception e) {
            log.error("批量写入时间失败", e);
            return false;
        }
    }
    /***
     * 写[03 Holding Register(4x)] 写一个 function ID = 6
     *
     * @param slaveId s
     * @param writeOffset w
     * @param writeValue w
     * @return
     * @throws ModbusTransportException m
     * @throws ModbusInitException m
     */
//    public static boolean writeRegister(int slaveId, int writeOffset, short writeValue)
//            throws ModbusTransportException, ModbusInitException {
//        // 获取master
//        ModbusMaster tcpMaster = getMaster();
//        // 创建请求对象
//        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
//        WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
//        if (response.isException()) {
//            log.error(response.getExceptionMessage());
//            return false;
//        } else {
//            return true;
//        }
//
//    }

    /**
     *
     * 写入[03 Holding Register(4x)]写多个 function ID=16
     *
     * @param slaveId
     *            modbus的slaveID
     * @param startOffset
     *            起始位置偏移量值
     * @param sdata
     *            写入的数据
     * @return 返回是否写入成功
     * @throws ModbusTransportException m
     * @throws ModbusInitException m
     */
    public static boolean writeRegisters(int slaveId, int startOffset, short[] sdata)
            throws ModbusTransportException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 创建请求对象
        WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
        // 发送请求并获取响应对象
        ModbusResponse response = tcpMaster.send(request);
        if (response.isException()) {
            log.error(response.getExceptionMessage());
            return false;
        } else {
            return true;
        }
    }



    /**
     * 写入数字类型的模拟量（如:写入Float类型的模拟量、Double类型模拟量、整数类型Short、Integer、Long）
     *
     * @param slaveId s
     * @param offset o
     * @param value
     *            写入值,Number的子类,例如写入Float浮点类型,Double双精度类型,以及整型short,int,long
     * @param dataType r
     *            ,com.serotonin.modbus4j.code.DataType
     * @throws ModbusTransportException m
     * @throws ErrorResponseException e
     * @throws ModbusInitException m
     */
    public static void writeHoldingRegister(int slaveId, int offset, Number value, int dataType)
            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
        // 获取master
        ModbusMaster tcpMaster = getMaster();
        // 类型
        BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
        tcpMaster.setValue(locator, value);
    }

    /**
     * 关闭Modbus连接
     */
    public static void destroyMaster() {
        if (master != null) {
            master.destroy();
            System.out.println("Modbus连接已关闭");
            master = null;
        }
    }

    /**
     * 获取读取Holding Register请求对象
     *
     * @param slaveId
     * @param offset
     * @param count
     * @return
     * @throws ModbusTransportException
     */
    public static ReadHoldingRegistersRequest getReadHoldingRegistersRequest(int slaveId, int offset, int count) throws ModbusTransportException {
        return new ReadHoldingRegistersRequest(slaveId, offset, count);
    }
    /**
     * 读取设备寄存器（线程安全版）
     */
    private static int[] readDeviceRegisters(int deviceId )
            throws ModbusTransportException, ModbusInitException {

        ModbusMaster master = getMaster();
        // 创建读取请求
        ReadHoldingRegistersRequest request = Modbus4jUtils.getReadHoldingRegistersRequest(deviceId,START_ADDRESS, REGISTER_COUNT);

        // 发送请求并获取响应
        ModbusResponse response = master.send(request);

        // 检查响应类型
        if (!(response instanceof ReadHoldingRegistersResponse)) {
            throw new IllegalArgumentException("Invalid response type: " + response.getClass().getName());
        }

        ReadHoldingRegistersResponse regResponse = (ReadHoldingRegistersResponse) response;
        short[] signedValues = regResponse.getShortData();

        // 转换为无符号整数
        int[] unsignedValues = new int[signedValues.length];
        for (int i = 0; i < signedValues.length; i++) {
            unsignedValues[i] = signedValues[i] & 0xFFFF;
        }

        return unsignedValues;
    }



    /**
     * 测试
     *
     * @param args a
     */
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        ModbusMaster modbusMaster = null;
        try {
            // 读取 第1个 pcba 板子的数据
            modbusMaster = createModbusMaster("192.168.2.1", 501);
//            writeCurrentTimeToDeviceEnhanced(modbusMaster, 1);
            writeTimeRegisters(modbusMaster, 1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (modbusMaster != null) {
                modbusMaster.destroy();
                modbusMaster = null;
            }
        }
        log.info("任务执行成功:, 耗时={}ms",  System.currentTimeMillis() - startTime);
    }
    /**
     * 写入当前时间到设备
     */
    public static void writeCurrentTimeToDevice(ModbusMaster master, int deviceId) {
        try {
            Calendar cal = Calendar.getInstance();
            int year = cal.get(Calendar.YEAR);
            int month = cal.get(Calendar.MONTH) + 1;
            int day = cal.get(Calendar.DATE);
            int hour = cal.get(Calendar.HOUR_OF_DAY);
            int minute = cal.get(Calendar.MINUTE);

            // 写入时间寄存器
            boolean success;
            success = Modbus4jUtils.writeRegister(master, deviceId, 4, (short) year);
            success &= Modbus4jUtils.writeRegister(master, deviceId, 5, (short) month);
            success &= Modbus4jUtils.writeRegister(master, deviceId, 6, (short) day);
            success &= Modbus4jUtils.writeRegister(master, deviceId, 7, (short) hour);
            success &= Modbus4jUtils.writeRegister(master, deviceId, 8, (short) minute);

            if (success) {
                int[] ints = readDeviceRegisters(master, deviceId);
                if(ints[4] == year && ints[5] == month && ints[6] == day && ints[7] == hour && ints[8] == minute) {
                    log.info("设备{}时间写入成功", deviceId);
                } else {
                    log.info("设备{}时间写入失败,板子时间为: year={}, month={}, day={}, hour={}, minute={}",deviceId,ints[4], ints[5], ints[6], ints[7], ints[8]);
                }
                log.info("设备{}时间写入成功", deviceId);
            } else {
                log.info("设备{}时间写入失败", deviceId);
            }
        } catch (Exception e) {
            log.info("设备{}时间写入异常", deviceId, e);
        }
    }

    /**
     * 带重试的设备读取
     */
    public static int[] readDeviceWithRetry(String ip, int port, int deviceId) {
        ModbusMaster master = null;
        int[] lastResult = null; // 用于记录最后一次读取的结果（无论是否满足停止条件）

        try {
            // 只创建一次ModbusMaster，循环内复用
            master = Modbus4jUtils.createModbusMaster(ip, port);

            for (int retry = 0; retry <= CUSTOM_RETRY_TIMES; retry++) {
                try {
                    // 执行读取操作，获取本次结果
                    int[] currentResult = readDeviceRegisters(master, deviceId);
                    // 更新最后一次结果（无论是否满足停止条件，都记录）
                    lastResult = currentResult;

                    // 检查停止条件，如果满足则提前返回（无需等到重试耗尽）
                    if (ModbusResultHandler.createDefaultStopCondition().test(currentResult)) {
                        log.info("设备{}第{}次读取成功（满足条件）: ip={}, port={}",
                                deviceId, retry + 1, ip, port);
                        return currentResult;
                    }

                    // 未满足条件且不是最后一次重试，休眠后继续
                    if (retry < CUSTOM_RETRY_TIMES) {
                        log.info("设备{}第{}次读取未满足条件，准备重试: ip={}, port={}",
                                deviceId, retry + 1, ip, port);
                        Thread.sleep(200);
                    }
                } catch (Exception e) {
                    // 本次读取发生异常，记录日志但不中断重试（继续下一次）
                    log.warn("设备{}第{}次读取发生异常: ip={}, port={}",
                            deviceId, retry + 1, ip, port, e);
                    // 如果是最后一次重试，异常时lastResult可能为null（需后续处理）
                }
            }

            // 循环结束（重试耗尽），此时lastResult为最后一次的结果（可能是正常读取但不满足条件，或null）
            log.info("设备{}重试次数耗尽，返回最后一次结果: ip={}, port={}",
                    deviceId, ip, port);
        } catch (Exception e) {
            // 捕获创建ModbusMaster或休眠时的异常（非读取操作的异常）
            log.error("设备{}连接创建或休眠失败: ip={}, port={}",
                    deviceId, ip, port, e);
            throw new RuntimeException("设备连接或操作异常", e);
        } finally {
            // 无论结果如何，最终销毁连接
            destroyModbusMaster(master, deviceId);
        }

        // 处理最后一次结果可能为null的情况（例如所有重试都异常）
        if (lastResult == null) {
            throw new RuntimeException("设备所有读取尝试均失败（无有效结果）");
        }
        return lastResult;
    }
    /**
     * 读取设备寄存器（线程安全版）
     */
    public static int[] readDeviceRegisters(ModbusMaster master, int deviceId )
            throws ModbusTransportException {

        // 创建读取请求
        ReadHoldingRegistersRequest request = Modbus4jUtils.getReadHoldingRegistersRequest(deviceId,START_ADDRESS, REGISTER_COUNT);

        // 发送请求并获取响应
        ModbusResponse response = master.send(request);

        // 检查响应类型
        if (!(response instanceof ReadHoldingRegistersResponse)) {
            throw new IllegalArgumentException("Invalid response type: " + response.getClass().getName());
        }

        ReadHoldingRegistersResponse regResponse = (ReadHoldingRegistersResponse) response;
        short[] signedValues = regResponse.getShortData();

        // 转换为无符号整数
        int[] unsignedValues = new int[signedValues.length];
        for (int i = 0; i < signedValues.length; i++) {
            unsignedValues[i] = signedValues[i] & 0xFFFF;
        }

        return unsignedValues;
    }


    /**
     * 增强版：写入并实时验证每个字段
     */
    public static void writeCurrentTimeToDeviceEnhanced(ModbusMaster master, int deviceId) {
        try {
            Calendar cal = Calendar.getInstance();
            int year = cal.get(Calendar.YEAR);
            int month = cal.get(Calendar.MONTH) + 1;
            int day = cal.get(Calendar.DATE);
            int hour = cal.get(Calendar.HOUR_OF_DAY);
            int minute = cal.get(Calendar.MINUTE);

            log.info("开始设置设备{}时间: {}-{}-{} {}:{}",
                    deviceId, year, month, day, hour, minute);

            // 逐个写入并验证
            boolean allSuccess = true;

            // 写入并验证年份
            allSuccess &= writeAndVerifyField(master, deviceId, 4, (short) year, "年份", year);
            Thread.sleep(200);

            // 写入并验证月份
            allSuccess &= writeAndVerifyField(master, deviceId, 5, (short) month, "月份", month);
            Thread.sleep(200);

            allSuccess &= writeAndVerifyField(master, deviceId, 6, (short) day, "日期", day);
            Thread.sleep(200);

            // 写入并验证小时
            allSuccess &= writeAndVerifyField(master, deviceId, 7, (short) hour, "小时", hour);
            Thread.sleep(200);

            // 写入并验证分钟
            allSuccess &= writeAndVerifyField(master, deviceId, 8, (short) minute, "分钟", minute);
            Thread.sleep(200);

            if (allSuccess) {
                // 最终整体验证
                Thread.sleep(500);
                int[] ints = readDeviceRegisters(master, deviceId);

                if (verifyTimeRegisters(ints, year, month, day, hour, minute)) {
                    log.info("设备{}时间设置全部完成且验证通过", deviceId);
                } else {
                    log.warn("设备{}时间设置完成，但最终验证失败", deviceId);
                }
            } else {
                log.error("设备{}时间设置过程中出现失败", deviceId);
            }

        } catch (Exception e) {
            log.error("设备{}时间写入异常", deviceId, e);
        }
    }

    /**
     * 写入并验证单个字段
     */
    private static boolean writeAndVerifyField(ModbusMaster master, int deviceId,
                                               int address, short value,
                                               String fieldName, int expectedValue) {
        try {
            log.info("开始写入{}: {} (地址={})", fieldName, expectedValue, address);

            // 写入
            boolean success = Modbus4jUtils.writeRegister(master, deviceId, address, value);

            if (!success) {
                log.error("写入{}失败", fieldName);
                return false;
            }

            // 等待设备处理
            Thread.sleep(100);

            // 读取验证
            int[] ints = readDeviceRegisters(master, deviceId);
            if (ints.length > address && ints[address] == expectedValue) {
                log.info("{}验证通过，写入值: {}", fieldName, expectedValue);
                return true;
            } else {
                log.warn("{}验证失败，期望: {}，实际: {}",
                        fieldName, expectedValue,
                        ints.length > address ? ints[address] : "N/A");
                return false;
            }

        } catch (Exception e) {
            log.error("写入{}时发生异常", fieldName, e);
            return false;
        }
    }

    /**
     * 验证时间寄存器
     */
    private static boolean verifyTimeRegisters(int[] registers,
                                               int year, int month, int day,
                                               int hour, int minute) {
        if (registers.length < 9) {
            log.warn("寄存器数量不足，无法验证时间");
            return false;
        }

        boolean verified = true;

        if (registers[4] != year) {
            log.warn("年份不匹配: 期望={}, 实际={}", year, registers[4]);
            verified = false;
        }

        if (registers[5] != month) {
            log.warn("月份不匹配: 期望={}, 实际={}", month, registers[5]);
            verified = false;
        }

        if (registers[6] != day) {
            log.warn("日期不匹配: 期望={}, 实际={}", day, registers[6]);
            verified = false;
        }

        if (registers[7] != hour) {
            log.warn("小时不匹配: 期望={}, 实际={}", hour, registers[7]);
            verified = false;
        }

        if (registers[8] != minute) {
            log.warn("分钟不匹配: 期望={}, 实际={}", minute, registers[8]);
            verified = false;
        }

        return verified;
    }
}
