me.martiii.modbustcpjava.net.NetHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of modbus-tcp-java Show documentation
Show all versions of modbus-tcp-java Show documentation
Modbus-TCP protocol for java.
The newest version!
package me.martiii.modbustcpjava.net;
import me.martiii.modbustcpjava.protocol.ModbusHeader;
import me.martiii.modbustcpjava.protocol.ModbusRequest;
import me.martiii.modbustcpjava.protocol.ModbusResponse;
import me.martiii.simplenethandler.SimpleNetHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class NetHandler extends SimpleNetHandler {
private final Logger logger = LoggerFactory.getLogger("ModbusTCPJava");
private static int lastTransactionID = 0;
private HashMap taskIDs;
private final List retryThreads;
public NetHandler() {
taskIDs = new HashMap<>();
retryThreads = new ArrayList<>();
setPort(502);
setCloseSocketIfDeactivated(false);
}
public void setSlaveAddress(String slaveAddress) {
setAddress(slaveAddress);
}
public void setSlavePort(int slavePort) {
setPort(slavePort);
}
public void executeTask(Task task, int retryTimeout) {
if (closed) return;
int transID = ++lastTransactionID;
taskIDs.put(transID, task);
if (lastTransactionID == 65535) {
lastTransactionID = 0;
}
ModbusHeader header = task.getHeader();
ModbusRequest request = task.getRequest();
byte[] frame = new byte[8 + request.getData().length];
frame[0] = (byte) (transID >>> 8);
frame[1] = (byte) transID;
int protocolID = header.getProtocolIdentifier();
frame[2] = (byte) (protocolID >>> 8);
frame[3] = (byte) protocolID;
int length = 2 + request.getData().length;
frame[4] = (byte) (length >>> 8);
frame[5] = (byte) length;
frame[6] = header.getUnitIdentifier();
frame[7] = request.getFunctionCode();
System.arraycopy(request.getData(), 0, frame, 8, request.getData().length);
logger.debug("Writing task with id {}: {}", transID, task);
Thread retryThread = new Thread(){
@Override
public void run() {
write(frame);
try {
Thread.sleep(retryTimeout);
} catch (InterruptedException e) {
logger.debug("Retry thread interrupted");
}
if (taskIDs.containsValue(task) && (!closed || active)) {
logger.debug("Retrying task with id {}", transID);
run();
} else {
synchronized (retryThreads) {
retryThreads.remove(this);
}
}
}
};
synchronized (retryThreads) {
retryThreads.add(retryThread);
}
retryThread.start();
activate();
}
public void cancelPendingRequests() {
logger.debug("Cancelling pending requests");
taskIDs.clear();
deactivate();
}
@Override
public boolean read(InputStream inputStream) throws Exception {
DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(inputStream));
byte[] frame = new byte[8];
int read = dataInputStream.read(frame);
if (read == 8) {
int transID = ((frame[0] & 0xff) << 8) | (frame[1] & 0xff);
int protocolID = ((frame[2] & 0xff) << 8) | (frame[3] & 0xff);
int length = ((frame[4] & 0xff) << 8) | (frame[5] & 0xff);
byte unitID = frame[6];
byte functionCode = frame[7];
byte[] data = new byte[length - 2];
read = dataInputStream.read(data);
if (read == length - 2) {
if (taskIDs.containsKey(transID)) {
Task task = taskIDs.remove(transID);
ModbusResponse response = new ModbusResponse(functionCode, data, functionCode != task.getRequest().getFunctionCode());
logger.debug("Response for task with id {}: {}", transID, response);
task.getCallback().callback(response);
}
} else {
throw new Exception("Invalid reading length");
}
} else {
throw new Exception("Invalid reading length");
}
return taskIDs.isEmpty();
}
@Override
public void close(boolean force) {
if (force) {
synchronized (retryThreads) {
retryThreads.forEach(Thread::interrupt);
}
}
super.close(force);
}
}