【Modbus】Java使用 modbus-master-tcp 读取和写入Modbus服务器数据
1、前言
在井下综采面需要用到工业级控制协议,采用了Modbus主站从站通讯方式,直接操作寄存器数据,实现读取和控制。
2、引用pom
<dependency>
<groupId>com.digitalpetri.modbus</groupId>
<artifactId>modbus-master-tcp</artifactId>
<version>1.1.0</version>
</dependency>
3、上代码
package com.ruoyi.project.socket.underJava;
import com.digitalpetri.modbus.FunctionCode;
import com.digitalpetri.modbus.codec.Modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import com.digitalpetri.modbus.requests.*;
import com.digitalpetri.modbus.responses.*;
import com.ruoyi.project.utils.HexUtils;
import com.ruoyi.project.utils.LogHelper;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
* @version: V1.0
* @description: modbus TCP协议 数据读取写入
* @date: 2021-02-04
*/
public class ModbusMasterTCPFromZhengMei {
/**
* 日志记录
*/
private static LogHelper log = new LogHelper();
/**
* tcp连接对象
*/
private static ModbusTcpMaster modbusTcpMaster;
/**
* modbus ip地址
*/
private static final String IP = "192.168.19.130";
/**
* 端口
*/
private static final Integer PORT = 502;
/**
* modubs从站ID
*/
private static final Integer UNIT_ID = 1;
/**
* 成功代码
*/
private static final String SUCCESS_CODE = "0x000000";
/**
* 与modubs连接异常
*/
private static final String COON_FAIL_CODE = "0x000001";
/**
* 向modubs发送命令执行异常
*/
private static final String EXEC_FAIL_CODE = "0x000002";
/**
* 数据写入失败
*/
private static final String WRITE_FAIL_CODE = "0x000004";
private static String logName = "ModbusMasterTCPFromZhengMei ";
/**
* @description: 初始化连接
* @param:
* @return: 结果值
*/
private static String init() {
try {
if (modbusTcpMaster == null) {
// 创建配置
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(IP).setPort(PORT).build();
// 新建连接
modbusTcpMaster = new ModbusTcpMaster(config);
}
return SUCCESS_CODE;
} catch (Exception e) {
log.error("ModbusMasterTCP::init - " + e.getMessage() + "(0x000001)" +
"\r\n" + Arrays.toString(e.getStackTrace()));
return COON_FAIL_CODE;
}
}
/**
* @description: 释放连接
* @param:
* @return: 结果值
*/
private static String release() {
try {
if (modbusTcpMaster != null) {
modbusTcpMaster.disconnect();
}
Modbus.releaseSharedResources();
return SUCCESS_CODE;
} catch (Exception e) {
return COON_FAIL_CODE;
}
}
/**
* @param address 寄存器地址
* @param value 写入值
* @param unitId id
* @description: 写HoldingRegister数据
* @return: 结果值
*/
public static String writeHoldingRegisters(Integer address, Integer value, Integer unitId) {
ModbusResponse modbusResponse;
try {
// 发送单个寄存器数据,一般是无符号16位值:比如10
CompletableFuture<ModbusResponse> future = modbusTcpMaster.sendRequest(new WriteSingleRegisterRequest(address, value), unitId);
//获取写入的响应流
modbusResponse = future.get();
if (modbusResponse == null) {
System.out.println("FCSC-ExternalConnection WriteHoldingRegisters:modbusResponse is null ");
return WRITE_FAIL_CODE;
}
//获取写入的响应FunctionCode
FunctionCode functionCode = modbusResponse.getFunctionCode();
System.out.println("FCSC-ExternalConnection functionCode=" + functionCode + " value=" + value);
if (functionCode == FunctionCode.WriteSingleRegister) {
return SUCCESS_CODE;
} else {
return WRITE_FAIL_CODE;
}
} catch (Exception e) {
log.error("ModbusMasterTCP::writeHoldingRegisters - " + e.getMessage() + ",value=" + value + "(0x000002)"
+ "\r\n" + Arrays.toString(e.getStackTrace()));
e.printStackTrace();
return EXEC_FAIL_CODE;
} finally {
// String releaseRes = release();
// //如果释放连接失败,返回执行失败
// if (!SUCCESS_CODE.equals(releaseRes)) {
// return releaseRes;
// }
}
}
/**
* @param address 寄存器地址
* @param quantity 写位数
* @param values 写入值
* @description: 写HoldingRegister数据
* @return: 结果值
*/
public static String WriteMultipleRegisters(Integer address, Integer quantity, byte[] values) {
try {
WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(address, quantity, values);
// 发送单个寄存器数据,一般是无符号16位值:比如10
CompletableFuture<ModbusResponse> future = modbusTcpMaster.sendRequest(request, UNIT_ID);
ModbusResponse modbusResponse;
//获取写入的响应流
modbusResponse = future.get();
if (modbusResponse == null) {
System.out.println("FCSC-ExternalConnection WriteMultipleRegisters:modbusResponse is null ");
return WRITE_FAIL_CODE;
}
//获取写入的响应FunctionCode
FunctionCode functionCode = modbusResponse.getFunctionCode();
System.out.println("FCSC-ExternalConnection functionCode.getCode()===" + functionCode.getCode() + "=" + functionCode);
if (functionCode == FunctionCode.WriteMultipleRegisters) {
return SUCCESS_CODE;
} else {
return WRITE_FAIL_CODE;
}
} catch (InterruptedException e) {
e.printStackTrace();
return EXEC_FAIL_CODE;
} catch (ExecutionException e) {
e.printStackTrace();
return EXEC_FAIL_CODE;
} finally {
// String releaseRes = release();
// //如果释放连接失败,返回执行失败
// if (!SUCCESS_CODE.equals(releaseRes)) {
// return releaseRes;
// }
}
}
/**
* @description: 写入数据
* @param: address 寄存器地址
* @param: value 写入值
* @return: 结果值
*/
public static String writeByteData(byte[] values) {
String initRes = init();
//如果初始化失败,则立即返回
if (!SUCCESS_CODE.equals(initRes)) {
return initRes;
}
String writeRes = WriteMultipleRegisters(916, 2, values);
//如果写入失败,返回
if (!SUCCESS_CODE.equals(writeRes)) {
return writeRes;
}
return SUCCESS_CODE;
}
/**
* @description: 写入数据
* @param: address 寄存器地址
* @param: value 写入值
* @return: 结果值
*/
public static String writeData(Integer address, Integer value) {
String initRes = init();
//如果初始化失败,则立即返回
if (!SUCCESS_CODE.equals(initRes)) {
return initRes;
}
String writeRes = writeHoldingRegisters(address, value, UNIT_ID);
//如果写入失败,返回
if (!SUCCESS_CODE.equals(writeRes)) {
return writeRes;
}
return SUCCESS_CODE;
}
/**
* @description: writeDemo
* @param:
* @return:
*/
public static void writeDemo() {
// 初始化资源
init();
Random random = new Random();
int value = random.nextInt(100) + 1;
System.out.println("write value=" + value);
try {
writeHoldingRegisters(222, value, UNIT_ID);
} catch (Exception e) {
e.printStackTrace();
}
// 释放资源
release();
}
/**
* @description: readDemo
* @param:
* @return:
*/
public static void readDemo() {
try {
// 初始化资源
init();
System.out.println("readDemo=" + readHoldingRegisters(222, 4, 1));
release();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 读取Coils开关量
*
* @param address 寄存器开始地址
* @param quantity 数量
* @param unitId ID
* @return 读取值
* @throws InterruptedException 异常
* @throws ExecutionException 异常
*/
public static Boolean readCoils(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Boolean result = null;
CompletableFuture<ReadCoilsResponse> future = modbusTcpMaster.sendRequest(new ReadCoilsRequest(address, quantity), unitId);
ReadCoilsResponse readCoilsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (readCoilsResponse != null) {
ByteBuf buf = readCoilsResponse.getCoilStatus();
result = buf.readBoolean();
ReferenceCountUtil.release(readCoilsResponse);
}
return result;
}
/**
* 读取readDiscreteInputs开关量
*
* @param address 寄存器开始地址
* @param quantity 数量
* @param unitId ID
* @return 读取值
* @throws InterruptedException 异常
* @throws ExecutionException 异常
*/
public static Boolean readDiscreteInputs(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Boolean result = null;
CompletableFuture<ReadDiscreteInputsResponse> future = modbusTcpMaster
.sendRequest(new ReadDiscreteInputsRequest(address, quantity), unitId);
ReadDiscreteInputsResponse discreteInputsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (discreteInputsResponse != null) {
ByteBuf buf = discreteInputsResponse.getInputStatus();
result = buf.readBoolean();
ReferenceCountUtil.release(discreteInputsResponse);
}
return result;
}
/**
* 读取HoldingRegister数据
*
* @param address 寄存器地址
* @param quantity 寄存器数量
* @param unitId id
* @return 读取结果
* @throws InterruptedException 异常
* @throws ExecutionException 异常
*/
public static Number readHoldingRegisters(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Number result = null;
CompletableFuture<ReadHoldingRegistersResponse> future = modbusTcpMaster
.sendRequest(new ReadHoldingRegistersRequest(address, quantity), unitId);
ReadHoldingRegistersResponse readHoldingRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (readHoldingRegistersResponse != null) {
ByteBuf buf = readHoldingRegistersResponse.getRegisters();
byte[] bytes = new byte[buf.capacity()];
buf.readBytes(bytes, 0, buf.capacity());
// System.out.println("bytes=" + Arrays.toString(bytes));
result = HexUtils.bytes2Short(bytes, 0);
ReferenceCountUtil.release(readHoldingRegistersResponse);
}
return result;
}
public static Integer readData(Integer address, Integer quantity) throws Exception {
String initRes = init();
//如果初始化失败,则立即返回
if (!SUCCESS_CODE.equals(initRes)) {
return -5;
}
Number number = readHoldingRegisters(address, quantity, UNIT_ID);
return number.intValue();
}
/**
* 读取InputRegisters模拟量数据
*
* @param address 寄存器开始地址
* @param quantity 数量
* @param unitId ID
* @return 读取值
* @throws InterruptedException 异常
* @throws ExecutionException 异常
*/
public static Number readInputRegisters(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Number result = null;
CompletableFuture<ReadInputRegistersResponse> future = modbusTcpMaster
.sendRequest(new ReadInputRegistersRequest(address, quantity), unitId);
ReadInputRegistersResponse readInputRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (readInputRegistersResponse != null) {
ByteBuf buf = readInputRegistersResponse.getRegisters();
result = buf.readDouble();
ReferenceCountUtil.release(readInputRegistersResponse);
}
return result;
}
/**
* @description: writeDemo2
* @param:
* @return:
*/
public static void writeDemo2() {
Random random = new Random();
int value = random.nextInt(100) + 1;
System.out.println("ready write value=" + value);
String res = writeData(222, value);
System.out.println("res=" + res);
}
public static void writeDemo3() {
byte[] bytes = new byte[]{0, 2, 0, 3};
String res = writeByteData(bytes);
System.out.println(res);
}
public static byte[] double2Bytes(double d) {
long value = Double.doubleToRawLongBits(d);
byte[] byteRet = new byte[8];
for (int i = 0; i < 8; i++) {
byteRet[i] = (byte) ((value >> 8 * i) & 0xff);
}
return byteRet;
}
public static String writeCoils(int address, boolean value) {
try {
init();
WriteSingleCoilRequest writeSingleCoilRequest = new WriteSingleCoilRequest(address, value);
CompletableFuture<ModbusResponse> request = modbusTcpMaster.sendRequest(writeSingleCoilRequest, UNIT_ID);
ModbusResponse modbusResponse = request.get();
if (modbusResponse == null) {
System.out.println(logName + "writeCoils:modbusResponse is null ");
return WRITE_FAIL_CODE;
}
FunctionCode functionCode = modbusResponse.getFunctionCode();
System.out.println(logName + "writeCoils address=" + address + " value=" + value + " functionCode=" + functionCode);
if (functionCode == FunctionCode.WriteSingleCoil) {
return SUCCESS_CODE;
} else {
return WRITE_FAIL_CODE;
}
} catch (Exception e) {
log.error(logName + "writeCoils - " + e.getMessage() + ",address" + address + ",value=" + value + "(0x000002)"
+ "\r\n" + Arrays.toString(e.getStackTrace()));
System.out.println(logName + "writeCoils - " + e.getMessage());
return WRITE_FAIL_CODE;
}
}
/**
* @description: main
* @param:
* @return:
*/
public static void main(String[] args) {
// writeDemo();
// readDemo();
writeDemo3();
release();
}
}