com.iteaj.iot.modbus.client.rtu.ModbusRtuClientProtocol Maven / Gradle / Ivy
package com.iteaj.iot.modbus.client.rtu;
import com.iteaj.iot.AbstractProtocol;
import com.iteaj.iot.ProtocolException;
import com.iteaj.iot.client.ClientConnectProperties;
import com.iteaj.iot.client.IotClient;
import com.iteaj.iot.consts.ExecStatus;
import com.iteaj.iot.format.ABCDFormat;
import com.iteaj.iot.format.DataFormat;
import com.iteaj.iot.modbus.*;
import com.iteaj.iot.modbus.consts.ModbusCode;
import com.iteaj.iot.modbus.consts.ModbusCoilStatus;
import com.iteaj.iot.serial.SerialClient;
import com.iteaj.iot.serial.SerialComponent;
import com.iteaj.iot.serial.SerialConnectProperties;
import com.iteaj.iot.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.apache.commons.lang3.ObjectUtils;
import java.util.function.Consumer;
public class ModbusRtuClientProtocol extends AbstractProtocol implements ModbusCommonProtocol {
private int start;
private ModbusCode code;
private Payload payload;
private Object clientKey;
protected ModbusRtuClientProtocol(ModbusRtuClientMessage message) {
this.requestMessage = message;
this.code = message.getBody().getCode();
this.start = message.getBody().getStart();
}
protected ModbusRtuClientProtocol(ModbusCode code, ModbusRtuClientMessage message) {
this.code = code;
this.requestMessage = message;
}
protected ModbusRtuClientProtocol(int start, ModbusCode code, ModbusRtuClientMessage message) {
this.code = code;
this.start = start;
this.requestMessage = message;
}
@Override
public AbstractProtocol buildRequestMessage() {
if(this.requestMessage.getMessage() == null) {
this.requestMessage.writeBuild();
}
return this;
}
@Override
public AbstractProtocol buildResponseMessage() {
ModbusRtuClientMessage responseMessage = this.responseMessage();
if(responseMessage != null) {
ModbusCode code = responseMessage.getBody().getCode();
byte[] content = responseMessage.getBody().getContent();
if(responseMessage.getBody().getErrCode() != null) {
return null;
}
this.payload = ModbusUtil.resolvePayload(content, (short) this.start, code, ABCDFormat.INSTANCE);
}
return null;
}
public ModbusRtuClientProtocol request(String com) {
this.clientKey = com;
return this.sendRequest(null);
}
public ModbusRtuClientProtocol request(String com, Consumer consumer) {
this.clientKey = com;
return this.sendRequest(consumer);
}
public ModbusRtuClientProtocol request(SerialConnectProperties com) {
this.clientKey = com;
return this.sendRequest(null);
}
public ModbusRtuClientProtocol request(SerialConnectProperties com, Consumer consumer) {
this.clientKey = com;
return this.sendRequest(consumer);
}
protected ModbusRtuClientProtocol sendRequest(Consumer consumer) throws ProtocolException {
this.buildRequestMessage();
IotClient iotClient = this.getClient();
if(iotClient instanceof SerialClient) {
synchronized (iotClient) {
ClientConnectProperties config = iotClient.getConfig();
if(!((SerialClient) iotClient).isOpen()) {
if(!((SerialClient) iotClient).connect()) {
throw new ProtocolException("打开串口异常["+config.connectKey()+"]");
}
}
// 写新的报文
byte[] message = this.requestMessage().getMessage();
((SerialClient) iotClient).write(message);
long currentTimeMillis = System.currentTimeMillis();
ByteBuf buffer = Unpooled.buffer(256);
while (readBytes((SerialClient) iotClient, buffer, protocolType()) != -1) {
if(System.currentTimeMillis() - currentTimeMillis > config.getReaderIdleTime() * 1000) {
this.setExecStatus(ExecStatus.timeout); break;
}
}
if(this.getExecStatus() == ExecStatus.success && buffer.readableBytes() > 0) {
byte[] bytes = new byte[buffer.readableBytes()];
buffer.readBytes(bytes).release();
this.responseMessage = new ModbusRtuClientMessage(bytes);
this.responseMessage().doBuild(bytes);
}
}
this.buildResponseMessage();
}
if(consumer != null) {
consumer.accept(this);
}
return this;
}
protected synchronized IotClient getClient() {
SerialComponent instance = SerialComponent.instance();
SerialClient client = instance.getClient(this.clientKey);
if(client == null) {
if(this.clientKey instanceof String) {
this.clientKey = new SerialConnectProperties((String) this.clientKey);
}
return instance.createNewClientAndConnect((ClientConnectProperties) clientKey);
}
return client;
}
protected int readBytes(SerialClient client, ByteBuf buffer, ModbusCode code) {
if(client.bytesAvailable() == 0) {
return 0; // 无需读取
}
int readableBytes = buffer.readableBytes();
if(readableBytes == 0) { // 先校验是否是错误报文
// 先读取两个字节
byte[] message = new byte[2];
client.read(message);
buffer.writeBytes(message);
int respCode = message[1] & 0xFF;
if(respCode > 0x80) { // 错误报文
message = new byte[3];
// 读取剩下的3个字节
client.read(message);
buffer.writeBytes(message);
return -1; // 结束
}
}
// 写类型的报文
if(code.getCode() >= 0x05) {
if(readableBytes < 8) {
// 读取剩下的六个字节
byte[] message = new byte[6];
client.read(message);
buffer.writeBytes(message);
}
return -1; // 结束
} else { // 读类型的报文
if(readableBytes > 2) { // 已经获取长度字段
buffer.readerIndex(2);
int length = buffer.readByte() & 0xFF;
// 读取剩下的报文
byte[] message = new byte[length + 2]; // 长度字段 + CRC
client.read(message);
buffer.writeBytes(message).resetReaderIndex();
return -1; //读取结束
} else {
// 读取第三个字节
byte[] message = new byte[1];
client.read(message);
buffer.writeBytes(message); return message.length;
}
}
}
public void doBuildResponseMessage(ModbusRtuClientMessage responseMessage) {
if(getExecStatus() == ExecStatus.success) {
ModbusCode code = responseMessage.getBody().getCode();
byte[] content = responseMessage.getBody().getContent();
if(responseMessage.getBody().getErrCode() != null) {
return;
}
switch (code) {
case Read01:
case Read02:
this.payload = new RealCoilPayload(this.start, content); break;
case Read03:
case Read04:
this.payload = new ReadPayload(content, this.start, ABCDFormat.INSTANCE); break;
default:
this.payload = WritePayload.getInstance();
}
}
}
/**
* 构建Modbus读线圈协议
* @see ModbusCode#Read01
* @param device 从机的设备地址
* @param start 从哪个寄存器开始读
* @param num 读多少个
* @return
*/
public static ModbusRtuClientProtocol buildRead01(int device, int start, int num) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildRead01Message(device, start, num);
return new ModbusRtuClientProtocol(num, ModbusCode.Read01, message);
}
/**
* 构建Modbus读线圈协议
* @see ModbusCode#Read02
* @param device 从机的设备地址
* @param start 从哪个寄存器开始读
* @param num 读多少个
* @return
*/
public static ModbusRtuClientProtocol buildRead02(int device, int start, int num) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildRead02Message(device, start, num);
return new ModbusRtuClientProtocol(num, ModbusCode.Read02, message);
}
/**
* 构建Modbus读保持寄存器报文
* @param device 从机的设备地址
* @param start 从哪个寄存器开始读
* @param num 读几个寄存器
* @return
*/
public static ModbusRtuClientProtocol buildRead03(int device, int start, int num) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildRead03Message(device, start, num);
return new ModbusRtuClientProtocol(start, ModbusCode.Read03, message);
}
/**
* 构建Modbus读输入寄存器协议
* @param device 从机的设备地址 (1-255)
* @param start 从哪个寄存器开始读 (1-65535)
* @param num 读几个寄存器(1-2000)
* @return
*/
public static ModbusRtuClientProtocol buildRead04(int device, int start, int num) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildRead04Message(device, start, num);
return new ModbusRtuClientProtocol(start, ModbusCode.Read04, message);
}
/**
* 构建Modbus写单个线圈报文
* @param device 访问的设备
* @param start 写哪个寄存器
* @param status 写内容
* @return
*/
public static ModbusRtuClientProtocol buildWrite05(int device, int start, ModbusCoilStatus status) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildWrite05Message(device, start, status);
return new ModbusRtuClientProtocol(ModbusCode.Write05, message);
}
/**
* 构建Modbus写单个寄存器报文
* @param device 从机的设备地址 (1-255)
* @param start 从哪个寄存器开始写 (1-65535)
* @param write 写内容
* @return
*/
public static ModbusRtuClientProtocol buildWrite06(int device, int start, byte[] write) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildWrite06Message(device, start, write);
return new ModbusRtuClientProtocol(ModbusCode.Write06, message);
}
/**
* 构建Modbus写单个寄存器报文
* @param device 从机的设备地址 (1-255)
* @param start 从哪个寄存器开始写 (1-65535)
* @param value 写内容
* @return
*/
public static ModbusRtuClientProtocol buildWrite06(int device, int start, short value) {
byte[] write = ByteUtil.getBytesOfReverse(value);
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildWrite06Message(device, start, write);
return new ModbusRtuClientProtocol(ModbusCode.Write06, message);
}
/**
* 构建Modbus写多个线圈
*
* @param device 从机的设备地址 (1-255)
* @param start 从哪个寄存器开始写
* @param write 写到设备的内容
* @return
*/
public static ModbusRtuClientProtocol buildWrite0F(int device, int start, byte[] write) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildWrite0FMessage(device, start, write);
return new ModbusRtuClientProtocol(ModbusCode.Write0F, message);
}
/**
* 构建Modbus写多个寄存器报文
* @see ByteUtil#getBytes(int)
* @see ByteUtil#getBytes(byte)
* @see ByteUtil#getBytes(long)
* @see ByteUtil#getBytes(float)
* ......
* @param device 从机的设备地址 (1-255)
* @param start 从哪个寄存器开始写
* @param num 写几个寄存器
* @param write 写到设备的内容
* @return
*/
public static ModbusRtuClientProtocol buildWrite10(int device, int start, int num, byte[] write) {
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildWrite10Message(device, start, num, write);
return new ModbusRtuClientProtocol(ModbusCode.Write10, message);
}
/**
* 构建Modbus写多个寄存器报文
* @param device
* @param start
* @param convert 将值做转换
* @return
*/
public static ModbusRtuClientProtocol buildWrite10(int device, int start, WriteConvert convert) {
byte[] write = convert.getWrite();
return buildWrite10(device, start, write.length / 2, write);
}
/**
* 使用默认数据格式构建Modbus写多个寄存器报文(字符串类型使用UTF-8)
* @see ByteUtil#getBytes(int)
* @see ByteUtil#getBytes(byte)
* @see ByteUtil#getBytes(long)
* @see ByteUtil#getBytes(float)
* ......
* @param device 从机的设备地址 (1-255)
* @param start 从哪个寄存器开始写
* @param args 写到设备的内容(可以是Number类型和String类型) 如果是字符串类型使用UTF-8编码
* @return
*/
public static ModbusRtuClientProtocol buildWrite10(int device, int start, Object... args) {
return buildWrite10(device, start, DataFormat.ABCD, args);
}
/**
* 构建Modbus写多个寄存器报文(字符串类型使用UTF-8)
* @see ByteUtil#getBytes(int)
* @see ByteUtil#getBytes(byte)
* @see ByteUtil#getBytes(long)
* @see ByteUtil#getBytes(float)
* ......
* @param device 从机的设备地址 (1-255)
* @param start 从哪个寄存器开始写
* @param format 数据格式
* @param args 写到设备的内容(可以是Number类型和String类型) 如果是字符串类型使用UTF-8编码
* @return
*/
public static ModbusRtuClientProtocol buildWrite10(int device, int start, DataFormat format, Object... args) {
if(ObjectUtils.isEmpty(args)) {
throw new ModbusProtocolException("未指定要写的内容", ModbusCode.Write10);
}
ModbusUtil.Write10Build write10Build = ModbusUtil.write10Build(format, args);
ModbusRtuClientMessage message = ModbusRtuMessageBuilder.buildWrite10Message(
device, start, write10Build.num, write10Build.message);
return new ModbusRtuClientProtocol(ModbusCode.Write10, message);
}
/**
* 根据使用自定义的message构建报文
* @return
*/
public static ModbusRtuClientProtocol build(byte[] message) {
ModbusCode code = ModbusCode.INSTANCE(message[1]);
if(code.getCode() < 0x05) { // 读构建
short start;
if(code.getCode() <= 0x02) { // 读线圈使用读取数量
start = ByteUtil.bytesToShortOfReverse(message, 4);
} else { // 读其它使用起始地址
start = ByteUtil.bytesToShortOfReverse(message, 2);
}
return new ModbusRtuClientProtocol(start, code, new ModbusRtuClientMessage(message));
} else {
return new ModbusRtuClientProtocol(code, new ModbusRtuClientMessage(message));
}
}
public Object getClientKey() {
return clientKey;
}
@Override
public Payload getPayload() {
return this.payload;
}
@Override
public ModbusCode protocolType() {
return this.code;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy