A Java Modbus library

Some time ago I started writing a Java modbus library, not because there aren't any already, but because it's a reasonable way to get more familiar with the protocol. As tends to be the way with these things it was never really finished, but I did learn a fair bit in the process.

I'm in a bit of a tidy up mood, so I've dug out that old code to try to make it somewhat presentable.

tl;dr - https://github.com/ptomli/modbus

It's taken a little bit of exploring to remember what I was thinking, but the API itself seems fairly painless.

var config = new NioTcpClientTransportConfig("127.0.0.1", 502, 1);
var transport = new NioTcpClientTransport(config);
var client = new ModbusClient(transport);

client.connect(); // or try (client.open()) { ... }

var register = 0x1234;
var count = 10;

var response = client.readHoldingRegisters(register, count);

byte[] registers = response.registers();

Clearly the setup could cope with a little sugar, and not too much thought has been spent on actually consuming the response data, but it looks like a decent start.

On the server side it's similarly straightforward

class MyServices implements ModbusServices {
    @Override
    public CompletionStage<ReadHoldingRegistersResponse> readHoldingRegisters(
        ReadHoldingRegistersRequest request) {

        var address = request.address();
        var quantity = request.quantity();

        // for this example, just be synchronous
        byte[] bytes = ... 
        return CompletableFuture.completedStage(new ReadHoldingRegistersResponse(bytes));
    }
}

var config = new NioTcpServerTransportConfig("127.0.0.1", 502, Executors.newFixedThreadPool(5));
var transport = new NioTcpServerTransport(config);
var server = new ModbusServer(transport, services);

server.start();

Again, setup is a little verbose, and looking at it now I suspect ModbusServices might prefer those request properties as individual arguments. You can also see how the server ends up with a thread pool to service requests.

The old code includes some "tests", but those scare quotes are doing some heavy lifting. While I was writing this originally it was mostly exploration, so @Test was just shorthand for main(String...). There's a bit of work to be done there to verify the code in place already, besides anything that's missing.

That's it for now