### Modbus TCP Client Example Source: https://context7.com/digitalpetri/modbus/llms.txt Demonstrates how to configure and use the ModbusTcpClient to interact with a Modbus TCP device. Includes examples for reading coils, holding registers, writing single and multiple registers, and asynchronous operations. Ensure proper exception handling for Modbus-specific errors. ```java import com.digitalpetri.modbus.client.ModbusTcpClient; import com.digitalpetri.modbus.pdu.*; import com.digitalpetri.modbus.tcp.client.NettyTcpClientTransport; import com.digitalpetri.modbus.exceptions.*; // 1. Build the transport var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("192.168.1.100"); cfg.setPort(502); cfg.setConnectPersistent(true); // auto-reconnect on disconnect cfg.setReconnectLazy(false); // reconnect immediately, not on next request }); // 2. Build the client var client = ModbusTcpClient.create(transport); // 3. Connect (try-with-resources for auto-disconnect) try (var conn = client.open()) { // FC 0x01 – Read Coils: read 8 coils starting at address 0, unit ID 1 ReadCoilsResponse coilResp = client.readCoils(1, new ReadCoilsRequest(0, 8)); System.out.println("Coils bytes: " + java.util.Arrays.toString(coilResp.coils())); // FC 0x03 – Read Holding Registers: read 10 registers starting at address 0 ReadHoldingRegistersResponse hrResp = client.readHoldingRegisters(1, new ReadHoldingRegistersRequest(0, 10)); System.out.println("Registers: " + java.util.Arrays.toString(hrResp.registers())); // FC 0x06 – Write Single Register: write value 1234 to address 5 client.writeSingleRegister(1, new WriteSingleRegisterRequest(5, 1234)); // FC 0x10 – Write Multiple Registers: write 3 registers starting at address 10 client.writeMultipleRegisters(1, new WriteMultipleRegistersRequest(10, 3, new byte[]{0x00, 0x01, 0x00, 0x02, 0x00, 0x03})); // FC 0x16 – Mask Write Register: apply AND/OR masks to register at address 0 client.maskWriteRegister(1, new MaskWriteRegisterRequest(0, 0xF2FF, 0x0025)); // Async example – FC 0x04 Read Input Registers client.readInputRegistersAsync(1, new ReadInputRegistersRequest(0, 5)) .thenAccept(r -> System.out.println("Input regs: " + java.util.Arrays.toString(r.registers()))) .exceptionally(ex -> { System.err.println("Error: " + ex.getMessage()); return null; }); } catch (ModbusResponseException e) { // Server returned an exception response (e.g. ILLEGAL_FUNCTION, ILLEGAL_DATA_ADDRESS) System.err.printf("Modbus exception FC=0x%02X code=0x%02X%n", e.getFunctionCode(), e.getExceptionCode()); } catch (ModbusTimeoutException e) { System.err.println("Request timed out: " + e.getMessage()); } catch (ModbusExecutionException e) { System.err.println("Execution error: " + e.getMessage()); } ``` -------------------------------- ### Modbus TCP Client Quick Start Source: https://github.com/digitalpetri/modbus/blob/master/README.md Example of establishing a connection and reading holding registers using the Modbus TCP client. Ensure the hostname and port are correctly configured for your Modbus TCP device. ```java var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("172.17.0.2"); cfg.setPort(502); }); var client = ModbusTcpClient.create(transport); client.connect(); ReadHoldingRegistersResponse response = client.readHoldingRegisters( 1, new ReadHoldingRegistersRequest(0, 10) ); System.out.println("Response: " + response); ``` -------------------------------- ### Modbus RTU Serial Client Quick Start Source: https://github.com/digitalpetri/modbus/blob/master/README.md Example of setting up and connecting a Modbus RTU client over a serial port. Correctly configure serial port parameters such as baud rate, data bits, parity, and stop bits to match your serial Modbus device. ```java var transport = SerialPortClientTransport.create(cfg -> { cfg.setSerialPort("/dev/ttyUSB0"); cfg.setBaudRate(115200); cfg.setDataBits(8); cfg.setParity(SerialPort.NO_PARITY); cfg.setStopBits(SerialPort.TWO_STOP_BITS); }); var client = ModbusRtuClient.create(transport); client.connect(); client.readHoldingRegisters( 1, new ReadHoldingRegistersRequest(0, 10) ); System.out.println("Response: " + response); ``` -------------------------------- ### Modbus RTU Server over Serial Source: https://context7.com/digitalpetri/modbus/llms.txt Configure and start a Modbus RTU server that listens on a serial port. This setup requires specifying serial port parameters like baud rate and parity. ```java import com.digitalpetri.modbus.server.*; import com.digitalpetri.modbus.serial.server.SerialPortServerTransport; import com.fazecast.jSerialComm.SerialPort; var processImage = new ProcessImage(); // Populate discrete inputs processImage.with(tx -> tx.writeDiscreteInputs(dis -> { dis.put(0, true); dis.put(1, false); dis.put(2, true); })); var services = new ReadWriteModbusServices() { @Override protected java.util.Optional getProcessImage(int unitId) { return unitId == 1 ? java.util.Optional.of(processImage) : java.util.Optional.empty(); } }; var transport = SerialPortServerTransport.create(cfg -> { cfg.setSerialPort("/dev/ttyUSB0"); cfg.setBaudRate(9600); cfg.setDataBits(8); cfg.setParity(SerialPort.NO_PARITY); cfg.setStopBits(SerialPort.ONE_STOP_BIT); }); var rtuServer = ModbusRtuServer.create(transport, services); rtuServer.start(); System.out.println("Modbus RTU server listening on /dev/ttyUSB0"); ``` -------------------------------- ### ModbusRtuClient - RTU over Serial and TCP Source: https://context7.com/digitalpetri/modbus/llms.txt Demonstrates creating and using a Modbus RTU client over both a physical serial port and RTU encapsulated over TCP. Includes examples for reading holding registers, writing single coils, and broadcasting writes. ```APIDOC ## ModbusRtuClient - RTU over Serial and TCP This section shows how to instantiate and use `ModbusRtuClient` for both serial and TCP communication. ### Option A: RTU over a physical serial port ```java import com.digitalpetri.modbus.client.ModbusRtuClient; import com.digitalpetri.modbus.pdu.*; import com.digitalpetri.modbus.serial.client.SerialPortClientTransport; import com.digitalpetri.modbus.tcp.client.NettyRtuClientTransport; import com.fazecast.jSerialComm.SerialPort; var serialTransport = SerialPortClientTransport.create(cfg -> { cfg.setSerialPort("/dev/ttyUSB0"); cfg.setBaudRate(115200); cfg.setDataBits(8); cfg.setParity(SerialPort.NO_PARITY); cfg.setStopBits(SerialPort.ONE_STOP_BIT); }); var rtuClient = ModbusRtuClient.create(serialTransport); rtuClient.connect(); // FC 0x03 – Read 10 holding registers from slave ID 1 var response = rtuClient.readHoldingRegisters(1, new ReadHoldingRegistersRequest(0, 10)); System.out.println("RTU registers: " + java.util.Arrays.toString(response.registers())); // FC 0x05 – Write a single coil ON at address 3 rtuClient.writeSingleCoil(1, new WriteSingleCoilRequest(3, 0xFF00)); // 0xFF00 = ON // Broadcast FC 0x10 – Write multiple registers to all slaves (no response) rtuClient.broadcast(new WriteMultipleRegistersRequest(0, 2, new byte[]{0x00, 0x0A, 0x00, 0x14})); rtuClient.disconnect(); ``` ### Option B: RTU encapsulated over TCP ```java import com.digitalpetri.modbus.client.ModbusRtuClient; import com.digitalpetri.modbus.pdu.*; import com.digitalpetri.modbus.tcp.client.NettyRtuClientTransport; var rtuTcpTransport = NettyRtuClientTransport.create(cfg -> { cfg.setHostname("192.168.1.101"); cfg.setPort(502); }); var rtuTcpClient = ModbusRtuClient.create(rtuTcpTransport); rtuTcpClient.connect(); var tcpRtuResp = rtuTcpClient.readCoils(2, new ReadCoilsRequest(0, 16)); System.out.println("RTU-over-TCP coils: " + java.util.Arrays.toString(tcpRtuResp.coils())); rtuTcpClient.disconnect(); ``` ``` -------------------------------- ### ModbusTcpClient Usage Source: https://context7.com/digitalpetri/modbus/llms.txt Demonstrates how to use the ModbusTcpClient to connect to a Modbus TCP device and perform various operations like reading coils, reading holding registers, writing single registers, writing multiple registers, and mask writing. It also includes an asynchronous example and error handling. ```APIDOC ## ModbusTcpClient — Modbus TCP Client `ModbusTcpClient` sends typed request PDUs to a remote Modbus TCP device and returns typed responses. Both synchronous and async variants exist for every function code. Use `NettyTcpClientTransport.create(cfg -> {...})` to configure the underlying TCP connection (host, port, timeouts, TLS, reconnect policy). ```java import com.digitalpetri.modbus.client.ModbusTcpClient; import com.digitalpetri.modbus.pdu.*; import com.digitalpetri.modbus.tcp.client.NettyTcpClientTransport; import com.digitalpetri.modbus.exceptions.*; // 1. Build the transport var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("192.168.1.100"); cfg.setPort(502); cfg.setConnectPersistent(true); // auto-reconnect on disconnect cfg.setReconnectLazy(false); // reconnect immediately, not on next request }); // 2. Build the client var client = ModbusTcpClient.create(transport); // 3. Connect (try-with-resources for auto-disconnect) try (var conn = client.open()) { // FC 0x01 – Read Coils: read 8 coils starting at address 0, unit ID 1 ReadCoilsResponse coilResp = client.readCoils(1, new ReadCoilsRequest(0, 8)); System.out.println("Coils bytes: " + java.util.Arrays.toString(coilResp.coils())); // FC 0x03 – Read Holding Registers: read 10 registers starting at address 0 ReadHoldingRegistersResponse hrResp = client.readHoldingRegisters(1, new ReadHoldingRegistersRequest(0, 10)); System.out.println("Registers: " + java.util.Arrays.toString(hrResp.registers())); // FC 0x06 – Write Single Register: write value 1234 to address 5 client.writeSingleRegister(1, new WriteSingleRegisterRequest(5, 1234)); // FC 0x10 – Write Multiple Registers: write 3 registers starting at address 10 client.writeMultipleRegisters(1, new WriteMultipleRegistersRequest(10, 3, new byte[]{0x00, 0x01, 0x00, 0x02, 0x00, 0x03})); // FC 0x16 – Mask Write Register: apply AND/OR masks to register at address 0 client.maskWriteRegister(1, new MaskWriteRegisterRequest(0, 0xF2FF, 0x0025)); // Async example – FC 0x04 Read Input Registers client.readInputRegistersAsync(1, new ReadInputRegistersRequest(0, 5)) .thenAccept(r -> System.out.println("Input regs: " + java.util.Arrays.toString(r.registers()))) .exceptionally(ex -> { System.err.println("Error: " + ex.getMessage()); return null; }); } catch (ModbusResponseException e) { // Server returned an exception response (e.g. ILLEGAL_FUNCTION, ILLEGAL_DATA_ADDRESS) System.err.printf("Modbus exception FC=0x%02X code=0x%02X%n", e.getFunctionCode(), e.getExceptionCode()); } catch (ModbusTimeoutException e) { System.err.println("Request timed out: " + e.getMessage()); } catch (ModbusExecutionException e) { System.err.println("Execution error: " + e.getMessage()); } ``` ``` -------------------------------- ### Modbus Authorization with AuthzModbusServices Source: https://context7.com/digitalpetri/modbus/llms.txt Wraps Modbus services with an authorization handler to control access based on operation and unit ID. This example sets up a server that allows all reads but restricts writes to a specific unit. ```java import com.digitalpetri.modbus.server.*; import com.digitalpetri.modbus.server.authz.*; import com.digitalpetri.modbus.tcp.server.NettyTcpServerTransport; var processImage = new ProcessImage(); var baseServices = new ReadWriteModbusServices() { @Override protected java.util.Optional getProcessImage(int unitId) { return unitId == 1 ? java.util.Optional.of(processImage) : java.util.Optional.empty(); } }; // Authorization handler: allow reads from all, allow writes only to unit 1 AuthzHandler authzHandler = new ReadWriteAuthzHandler() { @Override public AuthzHandler.AuthzResult authorizeReadHoldingRegisters( AuthzContext ctx, int unitId, com.digitalpetri.modbus.pdu.ReadHoldingRegistersRequest req) { return AuthzHandler.AuthzResult.AUTHORIZED; // everyone can read } @Override public AuthzHandler.AuthzResult authorizeWriteSingleRegister( AuthzContext ctx, int unitId, com.digitalpetri.modbus.pdu.WriteSingleRegisterRequest req) { // Only allow writes to unit 1 return unitId == 1 ? AuthzHandler.AuthzResult.AUTHORIZED : AuthzHandler.AuthzResult.NOT_AUTHORIZED; } }; // Wrap services with authorization var secureServices = new AuthzModbusServices(authzHandler, baseServices); var transport = NettyTcpServerTransport.create(cfg -> { cfg.setPort(502); cfg.setBindAddress("0.0.0.0"); }); var server = ModbusTcpServer.create(transport, secureServices); server.start(); System.out.println("Authorized Modbus TCP server started on port 502"); ``` -------------------------------- ### Modbus ProcessImage Data Model Source: https://context7.com/digitalpetri/modbus/llms.txt Demonstrates transactional access to Modbus data areas (Coils, Discrete Inputs, Holding Registers, Input Registers) using ProcessImage. Includes examples of writing and reading data, exclusive transactions, and setting up modification listeners. ```java import com.digitalpetri.modbus.server.ProcessImage; import com.digitalpetri.modbus.server.ProcessImage.*; var image = new ProcessImage(); // Write coils and holding registers in a single non-exclusive transaction image.with(tx -> { tx.writeCoils(coils -> { coils.put(0, true); coils.put(1, false); coils.put(2, true); }); tx.writeHoldingRegisters(regs -> { regs.put(0, new byte[]{0x00, 0x64}); // register 0 = 100 regs.put(1, new byte[]{0x01, (byte) 0xF4}); // register 1 = 500 }); }); // Read holding registers and coils atomically byte[] reg0 = image.get(tx -> tx.readHoldingRegisters(regs -> regs.getOrDefault(0, new byte[2])) ); System.out.printf("Register 0 = %d%n", ((reg0[0] & 0xFF) << 8) | (reg0[1] & 0xFF)); // 100 // Exclusive transaction: guaranteed no other transaction runs concurrently image.with(true, tx -> { tx.writeDiscreteInputs(di -> di.put(0, true)); tx.writeInputRegisters(ir -> ir.put(0, new byte[]{0x00, 0x2A})); }); // Listen for modifications image.addModificationListener(new ModificationListener() { @Override public void onCoilsModified(java.util.List mods) { mods.forEach(m -> System.out.printf("Coil[%d] = %b%n", m.address(), m.value())); } @Override public void onDiscreteInputsModified(java.util.List mods) {} @Override public void onHoldingRegistersModified(java.util.List mods) { mods.forEach(m -> System.out.printf("HR[%d] = 0x%s%n", m.address(), java.util.HexFormat.of().formatHex(m.value()))); } @Override public void onInputRegistersModified(java.util.List mods) {} }); // Trigger listener image.with(tx -> tx.writeCoils(coils -> coils.put(5, true))); ``` -------------------------------- ### ModbusClientConfig - Client Configuration Source: https://context7.com/digitalpetri/modbus/llms.txt Illustrates how to customize the `ModbusClientConfig` to control request timeouts and other client behaviors when creating a `ModbusTcpClient`. ```APIDOC ## ModbusClientConfig - Client Configuration Customize client behavior using `ModbusClientConfig`. ```java import com.digitalpetri.modbus.client.ModbusClientConfig; import com.digitalpetri.modbus.client.ModbusTcpClient; import com.digitalpetri.modbus.tcp.client.NettyTcpClientTransport; import java.time.Duration; var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("10.0.0.5"); cfg.setPort(502); cfg.setConnectTimeout(Duration.ofSeconds(3)); }); // Custom client config: 10-second request timeout var client = ModbusTcpClient.create(transport, cfg -> { cfg.setRequestTimeout(Duration.ofSeconds(10)); // cfg.setRequestSerializer(...); // plug in custom PDU encoder // cfg.setResponseSerializer(...); // plug in custom PDU decoder }); client.connect(); System.out.println("Connected: " + client.isConnected()); client.disconnect(); ``` ``` -------------------------------- ### Modbus TCP Server with Process Image Source: https://context7.com/digitalpetri/modbus/llms.txt Set up a Modbus TCP server that dispatches requests to a `ProcessImage`. The server can be backed by `ReadWriteModbusServices` for automatic image management. ```java import com.digitalpetri.modbus.server.*; import com.digitalpetri.modbus.tcp.server.NettyTcpServerTransport; // Create an in-memory process image for unit ID 1 var processImage = new ProcessImage(); // Pre-populate some holding registers processImage.with(tx -> tx.writeHoldingRegisters(regs -> { regs.put(0, new byte[]{0x00, 0x64}); // address 0 = 100 regs.put(1, new byte[]{0x01, 0xF4}); // address 1 = 500 })); // Implement read-write services backed by the process image var services = new ReadWriteModbusServices() { @Override protected java.util.Optional getProcessImage(int unitId) { return unitId == 1 ? java.util.Optional.of(processImage) : java.util.Optional.empty(); } }; // Build and start the TCP server on port 502 var serverTransport = NettyTcpServerTransport.create(cfg -> { cfg.setBindAddress("0.0.0.0"); cfg.setPort(502); }); var server = ModbusTcpServer.create(serverTransport, services); server.start(); System.out.println("Modbus TCP server listening on port 502"); // Dynamically update the process image (e.g., from a sensor thread) processImage.with(tx -> tx.writeInputRegisters(regs -> regs.put(0, new byte[]{0x00, 0x2A}) // address 0 = 42 )); // Graceful shutdown // server.stop(); ``` -------------------------------- ### Modbus Client Configuration Source: https://context7.com/digitalpetri/modbus/llms.txt Configure Modbus clients with custom timeouts and serializers using ModbusClientConfig. The builder pattern is used for all configuration objects. ```java import com.digitalpetri.modbus.client.ModbusClientConfig; import com.digitalpetri.modbus.client.ModbusTcpClient; import com.digitalpetri.modbus.tcp.client.NettyTcpClientTransport; import java.time.Duration; var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("10.0.0.5"); cfg.setPort(502); cfg.setConnectTimeout(Duration.ofSeconds(3)); }); // Custom client config: 10-second request timeout var client = ModbusTcpClient.create(transport, cfg -> { cfg.setRequestTimeout(Duration.ofSeconds(10)); // cfg.setRequestSerializer(...); // plug in custom PDU encoder // cfg.setResponseSerializer(...); // plug in custom PDU decoder }); client.connect(); System.out.println("Connected: " + client.isConnected()); client.disconnect(); ``` -------------------------------- ### Implement Custom Modbus Server Services Source: https://context7.com/digitalpetri/modbus/llms.txt Override methods like readInputRegisters and readCoils to serve custom data. Ensure register ranges are checked before processing requests. ```java import com.digitalpetri.modbus.server.*; import com.digitalpetri.modbus.exceptions.*; import com.digitalpetri.modbus.pdu.*; // Custom services that serve hard-coded sensor data var services = new ModbusServices() { @Override public ReadInputRegistersResponse readInputRegisters( ModbusRequestContext context, int unitId, ReadInputRegistersRequest request) throws ModbusResponseException { ModbusServices.checkRegisterRange( request.getFunctionCode(), request.address(), request.quantity()); // Simulate sensor values: each register = address * 10 byte[] registers = new byte[request.quantity() * 2]; for (int i = 0; i < request.quantity(); i++) { int value = (request.address() + i) * 10; registers[i * 2] = (byte) ((value >> 8) & 0xFF); registers[i * 2 + 1] = (byte) (value & 0xFF); } return new ReadInputRegistersResponse(registers); } @Override public ReadCoilsResponse readCoils( ModbusRequestContext context, int unitId, ReadCoilsRequest request) throws ModbusResponseException { // All coils ON for unit 1, all OFF otherwise int byteCount = (request.quantity() + 7) / 8; byte[] coils = new byte[byteCount]; if (unitId == 1) java.util.Arrays.fill(coils, (byte) 0xFF); return new ReadCoilsResponse(coils); } }; var transport = NettyTcpServerTransport.create(cfg -> cfg.setPort(5020)); var server = ModbusTcpServer.create(transport, services); server.start(); ``` -------------------------------- ### ModbusRtuServer Source: https://context7.com/digitalpetri/modbus/llms.txt Listens on a serial port and processes Modbus RTU requests, responding via the same port. ```APIDOC ## ModbusRtuServer ### Description `ModbusRtuServer` listens on a serial port and processes Modbus RTU requests, responding via the same port. ### Usage 1. Create a `ProcessImage` or custom `ModbusServices` implementation. 2. Create a `SerialPortServerTransport` configured with serial port parameters. 3. Create the `ModbusRtuServer` using the transport and services. 4. Start the server using `rtuServer.start()`. ### Key Components - **`ModbusRtuServer`**: The main RTU server class. - **`SerialPortServerTransport`**: Provides the serial port transport layer. - **`ModbusServices`**: Interface for handling Modbus requests. - **`ReadWriteModbusServices`**: A common implementation using `ProcessImage`. - **`ProcessImage`**: Manages Modbus data points. ### Example ```java import com.digitalpetri.modbus.server.*; import com.digitalpetri.modbus.serial.server.SerialPortServerTransport; import com.fazecast.jSerialComm.SerialPort; var processImage = new ProcessImage(); // Populate discrete inputs processImage.with(tx -> tx.writeDiscreteInputs(dis -> { dis.put(0, true); dis.put(1, false); dis.put(2, true); })); var services = new ReadWriteModbusServices() { @Override protected java.util.Optional getProcessImage(int unitId) { return unitId == 1 ? java.util.Optional.of(processImage) : java.util.Optional.empty(); } }; var transport = SerialPortServerTransport.create(cfg -> { cfg.setSerialPort("/dev/ttyUSB0"); cfg.setBaudRate(9600); cfg.setDataBits(8); cfg.setParity(SerialPort.NO_PARITY); cfg.setStopBits(SerialPort.ONE_STOP_BIT); }); var rtuServer = ModbusRtuServer.create(transport, services); rtuServer.start(); System.out.println("Modbus RTU server listening on /dev/ttyUSB0"); ``` ``` -------------------------------- ### ModbusTcpServer Source: https://context7.com/digitalpetri/modbus/llms.txt Listens for incoming Modbus TCP connections and dispatches requests to a user-supplied ModbusServices implementation. ```APIDOC ## ModbusTcpServer ### Description `ModbusTcpServer` listens for incoming Modbus TCP connections and dispatches requests to a user-supplied `ModbusServices` implementation. It can be backed by a `ReadWriteModbusServices` (which automatically manages a `ProcessImage`) or a fully custom implementation. ### Usage 1. Create a `ProcessImage` or custom `ModbusServices` implementation. 2. Create a `NettyTcpServerTransport` configured with bind address and port. 3. Create the `ModbusTcpServer` using the transport and services. 4. Start the server using `server.start()`. ### Key Components - **`ModbusTcpServer`**: The main server class. - **`NettyTcpServerTransport`**: Provides the network transport layer. - **`ModbusServices`**: Interface for handling Modbus requests. - **`ReadWriteModbusServices`**: A common implementation using `ProcessImage`. - **`ProcessImage`**: Manages Modbus data points like coils, discrete inputs, holding registers, and input registers. ### Example ```java import com.digitalpetri.modbus.server.*; import com.digitalpetri.modbus.tcp.server.NettyTcpServerTransport; // Create an in-memory process image for unit ID 1 var processImage = new ProcessImage(); // Pre-populate some holding registers processImage.with(tx -> tx.writeHoldingRegisters(regs -> { regs.put(0, new byte[]{0x00, 0x64}); // address 0 = 100 regs.put(1, new byte[]{0x01, 0xF4}); // address 1 = 500 })); // Implement read-write services backed by the process image var services = new ReadWriteModbusServices() { @Override protected java.util.Optional getProcessImage(int unitId) { return unitId == 1 ? java.util.Optional.of(processImage) : java.util.Optional.empty(); } }; // Build and start the TCP server on port 502 var serverTransport = NettyTcpServerTransport.create(cfg -> { cfg.setBindAddress("0.0.0.0"); cfg.setPort(502); }); var server = ModbusTcpServer.create(serverTransport, services); server.start(); System.out.println("Modbus TCP server listening on port 502"); // Dynamically update the process image (e.g., from a sensor thread) processImage.with(tx -> tx.writeInputRegisters(regs -> regs.put(0, new byte[]{0x00, 0x2A}) // address 0 = 42 )); // Graceful shutdown // server.stop(); ``` ``` -------------------------------- ### NettyTcpClientTransport - TLS / Modbus TCP Security Source: https://context7.com/digitalpetri/modbus/llms.txt Shows how to enable Modbus TCP Security using TLS by configuring `NettyTcpClientTransport` with `KeyManagerFactory` and `TrustManagerFactory`. ```APIDOC ## NettyTcpClientTransport - TLS / Modbus TCP Security Secure Modbus TCP connections using TLS. ```java import com.digitalpetri.modbus.client.ModbusTcpClient; import com.digitalpetri.modbus.tcp.client.NettyTcpClientTransport; import javax.net.ssl.*; import java.security.KeyStore; // Load client identity keystore KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new java.io.FileInputStream("client.p12"), "password".toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, "password".toCharArray()); // Load trust store (server CA) KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(new java.io.FileInputStream("truststore.jks"), "trustpass".toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("secure-plc.example.com"); // port defaults to 802 when tlsEnabled = true cfg.setTlsEnabled(true); cfg.setKeyManagerFactory(kmf); cfg.setTrustManagerFactory(tmf); }); var client = ModbusTcpClient.create(transport); client.connect(); var resp = client.readHoldingRegisters(1, new com.digitalpetri.modbus.pdu.ReadHoldingRegistersRequest(0, 5)); System.out.println("Secure read: " + java.util.Arrays.toString(resp.registers())); client.disconnect(); ``` ``` -------------------------------- ### Maven Dependency for Modbus Serial Source: https://github.com/digitalpetri/modbus/blob/master/README.md Add this dependency to your Maven project to enable Modbus RTU communication over serial ports. ```xml com.digitalpetri.modbus modbus-serial 2.1.4 ``` -------------------------------- ### Maven Dependencies for Modbus Source: https://context7.com/digitalpetri/modbus/llms.txt Add these dependencies to your Maven project to include Modbus TCP or Modbus RTU on Serial functionality. ```xml com.digitalpetri.modbus modbus-tcp 2.1.4 com.digitalpetri.modbus modbus-serial 2.1.4 ``` -------------------------------- ### Secure Modbus TCP with TLS Source: https://context7.com/digitalpetri/modbus/llms.txt Enable TLS for Modbus TCP security by setting tlsEnabled to true and providing KeyManagerFactory and TrustManagerFactory. The default TLS port is 802. ```java import com.digitalpetri.modbus.client.ModbusTcpClient; import com.digitalpetri.modbus.tcp.client.NettyTcpClientTransport; import javax.net.ssl.*; import java.security.KeyStore; // Load client identity keystore KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new java.io.FileInputStream("client.p12"), "password".toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, "password".toCharArray()); // Load trust store (server CA) KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(new java.io.FileInputStream("truststore.jks"), "trustpass".toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("secure-plc.example.com"); // port defaults to 802 when tlsEnabled = true cfg.setTlsEnabled(true); cfg.setKeyManagerFactory(kmf); cfg.setTrustManagerFactory(tmf); }); var client = ModbusTcpClient.create(transport); client.connect(); var resp = client.readHoldingRegisters(1, new com.digitalpetri.modbus.pdu.ReadHoldingRegistersRequest(0, 5)); System.out.println("Secure read: " + java.util.Arrays.toString(resp.registers())); client.disconnect(); ``` -------------------------------- ### Maven Dependency for Modbus TCP Source: https://github.com/digitalpetri/modbus/blob/master/README.md Add this dependency to your Maven project to include the Modbus TCP client and server functionalities. ```xml com.digitalpetri.modbus modbus-tcp 2.1.4 ``` -------------------------------- ### ModbusTcpClient.sendRaw Source: https://context7.com/digitalpetri/modbus/llms.txt Send a raw PDU byte array over Modbus TCP for custom or vendor-specific function codes. ```APIDOC ## ModbusTcpClient.sendRaw ### Description Send a raw PDU byte array over Modbus TCP when working with custom or vendor-specific function codes not covered by the typed API. ### Method `sendRaw(int unitId, byte[] request)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```java // Custom FC 0x41: raw request bytes (function code + data) byte[] rawRequest = new byte[] { 0x41, 0x00, 0x05 }; byte[] rawResponse = client.sendRaw(1, rawRequest); ``` ### Response #### Success Response (200) - **rawResponse** (byte[]) - The raw byte array response from the Modbus server. #### Response Example ```java System.out.printf("Raw response (%d bytes): %s%n", rawResponse.length, java.util.HexFormat.of().formatHex(rawResponse)); ``` ## ModbusTcpClient.sendRawAsync ### Description Asynchronously sends a raw PDU byte array over Modbus TCP. ### Method `sendRawAsync(int unitId, byte[] request)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```java client.sendRawAsync(1, rawRequest) .thenAccept(resp -> System.out.println("Async raw response length: " + resp.length)); ``` ### Response #### Success Response (200) - **resp** (byte[]) - The raw byte array response from the Modbus server. #### Response Example ```java // Handled within the thenAccept block ``` ``` -------------------------------- ### Send Raw Modbus TCP PDU Source: https://context7.com/digitalpetri/modbus/llms.txt Use `sendRaw` to send custom or vendor-specific Modbus function codes. Ensure the Modbus TCP client is connected before sending. ```java import com.digitalpetri.modbus.client.ModbusTcpClient; import com.digitalpetri.modbus.tcp.client.NettyTcpClientTransport; var transport = NettyTcpClientTransport.create(cfg -> { cfg.setHostname("192.168.1.100"); cfg.setPort(502); }); var client = ModbusTcpClient.create(transport); client.connect(); // Custom FC 0x41: raw request bytes (function code + data) byte[] rawRequest = new byte[] { 0x41, 0x00, 0x05 }; byte[] rawResponse = client.sendRaw(1, rawRequest); System.out.printf("Raw response (%d bytes): %s%n", rawResponse.length, java.util.HexFormat.of().formatHex(rawResponse)); // Async variant client.sendRawAsync(1, rawRequest) .thenAccept(resp -> System.out.println("Async raw response length: " + resp.length)); client.disconnect(); ``` -------------------------------- ### Modbus RTU Client (Serial and TCP) Source: https://context7.com/digitalpetri/modbus/llms.txt Use ModbusRtuClient for RTU communication over serial ports or TCP. It handles CRC calculations and frame parsing. Supports broadcast writes to unit ID 0. ```java import com.digitalpetri.modbus.client.ModbusRtuClient; import com.digitalpetri.modbus.pdu.*; import com.digitalpetri.modbus.serial.client.SerialPortClientTransport; import com.digitalpetri.modbus.tcp.client.NettyRtuClientTransport; import com.fazecast.jSerialComm.SerialPort; // --- Option A: RTU over a physical serial port --- var serialTransport = SerialPortClientTransport.create(cfg -> { cfg.setSerialPort("/dev/ttyUSB0"); cfg.setBaudRate(115200); cfg.setDataBits(8); cfg.setParity(SerialPort.NO_PARITY); cfg.setStopBits(SerialPort.ONE_STOP_BIT); }); var rtuClient = ModbusRtuClient.create(serialTransport); rtuClient.connect(); // FC 0x03 – Read 10 holding registers from slave ID 1 var response = rtuClient.readHoldingRegisters(1, new ReadHoldingRegistersRequest(0, 10)); System.out.println("RTU registers: " + java.util.Arrays.toString(response.registers())); // FC 0x05 – Write a single coil ON at address 3 rtuClient.writeSingleCoil(1, new WriteSingleCoilRequest(3, 0xFF00)); // 0xFF00 = ON // Broadcast FC 0x10 – Write multiple registers to all slaves (no response) rtuClient.broadcast(new WriteMultipleRegistersRequest(0, 2, new byte[]{0x00, 0x0A, 0x00, 0x14})); rtuClient.disconnect(); // --- Option B: RTU encapsulated over TCP --- var rtuTcpTransport = NettyRtuClientTransport.create(cfg -> { cfg.setHostname("192.168.1.101"); cfg.setPort(502); }); var rtuTcpClient = ModbusRtuClient.create(rtuTcpTransport); rtuTcpClient.connect(); var tcpRtuResp = rtuTcpClient.readCoils(2, new ReadCoilsRequest(0, 16)); System.out.println("RTU-over-TCP coils: " + java.util.Arrays.toString(tcpRtuResp.coils())); rtuTcpClient.disconnect(); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.