package com.jwk.spring.boot.modbus4j;

import com.jwk.spring.boot.constant.DATA_TYPE_WRAPPER;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.*;
import lombok.extern.slf4j.Slf4j;

/**
 * @author JWK
 * @version 1.0
 * @date 2022/12/12 22:10
 */
@Slf4j
public class ModbusMasterUtil {

    private ModbusMaster master;

    public ModbusMasterUtil(ModbusMaster master) {
        this.master = master;
    }

    /**
     * 读单个线圈寄存器 01
     *
     * @param slaveId
     * @param offset
     * @return 读取值
     */
    public Boolean readCoil(int slaveId, int offset) {
        Boolean value = null;
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        try {
            value = master.getValue(loc);
        } catch (Exception e) {
            log.error("读单个线圈寄存器失败:" + e.getMessage(), e);
        }
        return value;
    }

    /**
     * 读线圈寄存器 01
     *
     * @param slaveId
     * @param offset
     * @param len
     */
    public ReadResponse readCoils(int slaveId, int offset, int len) {
        try {
            ReadCoilsRequest request = new ReadCoilsRequest(slaveId, offset, len);
            ReadCoilsResponse response = (ReadCoilsResponse) master.send(request);
            if (response.isException()) {
                log.error("读线圈寄存器错误:" + response.getExceptionMessage());
                return null;
            }
            return response;
        } catch (Exception e) {
            log.error("读线圈寄存器失败:" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 写单个线圈寄存器 05
     *
     * @param slaveId
     * @param offset
     * @param value   0x0000 false | 0xFF00 true
     */
    public Boolean writeCoil(int slaveId, int offset, int value) {
        Boolean con = value == 0x0000 ? false : value == 0xFF00 ? true : null;
        return writeCoil(slaveId, offset, con);
    }

    /**
     * 写单个线圈寄存器 05
     *
     * @param slaveId
     * @param offset
     * @param value
     */
    public Boolean writeCoil(int slaveId, int offset, boolean value) {
        try {
            WriteCoilRequest request = new WriteCoilRequest(slaveId, offset, value);
            WriteCoilResponse response = (WriteCoilResponse) master.send(request);
            if (response.isException()) {
                log.error("写单个线圈寄存器错误:" + response.getExceptionMessage());
                return false;
            }
            return true;
        } catch (Exception e) {
            log.error("写单个线圈寄存器失败:" + e.getMessage(), e);
        }
        return false;
    }

    /**
     * 读取单个保持寄存器 03
     *
     * @param slaveId  从节点
     * @param offset   位置
     * @param dataType 数据类型 {@link com.serotonin.modbus4j.code.DataType}{@link DATA_TYPE_WRAPPER}
     */
    public Number readHoldingRegister(int slaveId, int offset, DATA_TYPE_WRAPPER dataType) {
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType.getValue());
        Number value = null;
        try {
            value = master.getValue(loc);
        } catch (Exception e) {
            log.error("读取单个保持寄存器失败：:" + e.getMessage(), e);
        }
        return value;
    }

    /**
     * 读取保持寄存器 03
     *
     * @param slaveId
     * @param offset
     * @param len
     */
    public ReadResponse readHoldingRegisters(int slaveId, int offset, int len) {
        try {
            ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, offset, len);
            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
            if (response.isException()) {
                log.error("读取保持寄存器错误:" + response.getExceptionMessage());
                return null;
            }
            return response;
        } catch (Exception e) {
            log.error("读取保持寄存器失败:" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 写单个保持寄存器 06
     *
     * @param slaveId
     * @param offset
     * @param value
     */
    public Boolean writeHoldingRegisters(int slaveId, int offset, int value) {
        try {
            WriteRegisterRequest request = new WriteRegisterRequest(slaveId, offset, value);
            WriteRegisterResponse response = (WriteRegisterResponse) master.send(request);
            if (response.isException()) {
                log.error("写保持寄存器错误:" + response.getExceptionMessage());
                return false;
            }
            return true;
        } catch (Exception e) {
            log.error("写保持寄存器失败:" + e.getMessage(), e);
        }
        return false;
    }
}
