package com.jwk.spring.boot.modbus4j;

import com.jwk.spring.boot.modbus4j.util.rtu.SerialPortWrapperImpl;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * @author JWK
 * @version 1.0
 * @date 2022/9/7 17:00
 */
@Slf4j
@Data
public class ModbusRtuMaster extends SerialPortWrapperImpl {

    private ModbusMaster master = null;
    private ModbusFactory modbusFactory = null;
    private ModbusMasterUtil modbusMasterUtil = null;
    private Lock lock = new ReentrantLock();

    /**
     * 初始化串口连接
     *
     * @param port
     * @param baudRate
     * @param dataBits
     * @param stopBits
     * @param parity
     * @param flowControlIn
     * @param flowControlOut
     * @throws ModbusInitException
     */
    public ModbusRtuMaster(String port, int baudRate, int dataBits, int stopBits, int parity,
                           int flowControlIn, int flowControlOut) {
        super(port, baudRate, dataBits, stopBits, parity, flowControlIn, flowControlOut);
    }

    /**
     * 打开串口 异步
     *
     * @throws ModbusInitException
     */
    public void connectAsync() {
        Executors.newSingleThreadExecutor().execute(() -> this.connect());
    }

    /**
     * 打开串口
     *
     * @throws ModbusInitException
     */
    public void connect() {
        for (; ; ) {
            try {
                if (!lock.tryLock()) {
                    break;
                }
                if (modbusFactory == null) {
                    modbusFactory = new ModbusFactory();
                }
                master = modbusFactory.createRtuMaster(this);
                master.init();
                modbusMasterUtil = new ModbusMasterUtil(master);
                break;
            } catch (Exception e) {
                log.error("当前串口：{},打开失败！", getPort(), e);
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ee) {

                }
            } finally {
                lock.unlock();
            }
        }
    }

    /**
     * 重新连接串口
     */
    public void reConnect() {
        try {
            this.close();
            Thread.sleep(1000);
        } catch (Exception e) {

        }
        connect();
    }
}
