A java integration for libmodbus Basically using JNI wrappers to supply libmodbus functionality, while providing some integrations for java structures and such.
Only supporting TCP/Serial-RTU clients and TCP server for now.
jmodbus is published to maven central. For gradle, use
// for the java API
implementation group: 'com.github.tomtzook', name: 'jmodbus', version: version
// for the JNI natives
implementation group: 'com.github.tomtzook', name: 'jmodbus-jni', version: version, classifier: platform
The classifier
specifies the platform which is used, can be one of:
linux-aarch64
linux-amd64
linux-gnueabihf-arm
windows-x86_x64
Load the natives from the jni dependency. Can be done easily with castle:
Natives.newLoader()
.load("modbus_jni");
libmodbus should be already installed on the system.
try (ModbusClient client = Modbus.newTcpClient("127.0.0.1", 1524)) {
client.connect();
// read an int made out of two registers
ByteBuffer buffer = ByteBuffer.allocate(4);
client.readHoldingRegisters(0x0, 2, buffer);
int value = BufferDataHelper.getInt(buffer, 0);
}
try (ModbusClient client = Modbus.newRtuClient(
"/dev/ttyUSB0",
9600,
Parity.EVEN,
Databit.BYTESIZE_8,
Stopbit.STOPBIT_1,
SerialMode.RS485)) {
client.connect();
// read an int made out of two registers
ByteBuffer buffer = ByteBuffer.allocate(4);
client.readHoldingRegisters(0x0, 2, buffer);
int value = BufferDataHelper.getInt(buffer, 0);
}
final int maxBacklogSize = 2;
final int numberOfDiscreteBits = 2;
final int numberOfCoils = 2;
final int numberOfInputRegisters = 2;
final int numberOfHoldingRegisters = 2;
// holds data blocks which are returned upon client requests
// update the data here to update the data sent to clients
Registers registers = new Registers(
numberOfDiscreteBits,
numberOfCoils,
numberOfInputRegisters,
numberOfHoldingRegisters
);
try (ModbusTcpServer server = Modbus.newTcpServer(
"0.0.0.0", 5000,
maxBacklogSize,
registers
)) {
// buffer for requests
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
// loop for handling clients
while (true) {
ServerDataUpdate update = server.waitForNewData();
try {
switch(update.getType()) {
case NEW_CLIENT:
// new client wants to connect
update.accept();
break;
case NEW_DATA:
// a client sent a request
TcpRequest request = update.readClientRequest(buffer);
// can access request info if wanted
// reply the client with data in Registers
request.reply();
break;
}
} catch(ModbusIoException e) {
// error with the client
update.closeCurrentClient();
}
}
}
The Registers
class describes 4 data block, matching the standard data types in modbus.
Each data block is either a BitDataBlock
for bit sized data types or WordDataBlock
for word sized types.
Per modbus's specs, the data blocks store data in big endian order.
These data blocks contain the values that are to be returned to the clients on a request. Modify these regularly, or when a request is received, to update the data returned to the client. Query this regularly to see data set by the clients.