### Complete TCP Master Example in Java Source: https://context7.com/mangoautomation/modbus4j/llms.txt This comprehensive example demonstrates TCP master initialization, reading, writing, and batch operations. It includes setup for connection parameters, timeouts, retries, and various Modbus operations like reading/writing coils and holding registers for different data types. ```java import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.BatchRead; import com.serotonin.modbus4j.BatchResults; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.locator.BaseLocator; import com.serotonin.modbus4j.code.DataType; import com.serotonin.modbus4j.exception.ModbusInitException; import com.serotonin.modbus4j.exception.ModbusTransportException; import com.serotonin.modbus4j.exception.ErrorResponseException; public class ModbusTcpExample { public static void main(String[] args) { ModbusFactory factory = new ModbusFactory(); // Configure connection IpParameters params = new IpParameters(); params.setHost("192.168.1.100"); params.setPort(502); params.setEncapsulated(false); // Create master with keep-alive enabled ModbusMaster master = factory.createTcpMaster(params, true); master.setTimeout(2000); master.setRetries(2); try { // Initialize connection master.init(); System.out.println("Connected to Modbus device"); int slaveId = 1; // === Single Value Operations === // Read holding register as float BaseLocator tempLocator = BaseLocator.holdingRegister(slaveId, 0, DataType.FOUR_BYTE_FLOAT); float temperature = master.getValue(tempLocator).floatValue(); System.out.println("Temperature: " + temperature + " C"); // Write holding register BaseLocator setpointLocator = BaseLocator.holdingRegister(slaveId, 10, DataType.FOUR_BYTE_FLOAT); master.setValue(setpointLocator, 75.0f); System.out.println("Setpoint updated to 75.0"); // Read/write coil BaseLocator pumpLocator = BaseLocator.coilStatus(slaveId, 0); boolean pumpStatus = master.getValue(pumpLocator); System.out.println("Pump status: " + (pumpStatus ? "ON" : "OFF")); master.setValue(pumpLocator, !pumpStatus); // Toggle pump // === Batch Read Operations === BatchRead batch = new BatchRead<>(); batch.addLocator("temp1", BaseLocator.holdingRegister(slaveId, 0, DataType.FOUR_BYTE_FLOAT)); batch.addLocator("temp2", BaseLocator.holdingRegister(slaveId, 2, DataType.FOUR_BYTE_FLOAT)); batch.addLocator("pressure", BaseLocator.holdingRegister(slaveId, 4, DataType.FOUR_BYTE_FLOAT)); batch.addLocator("level", BaseLocator.inputRegister(slaveId, 0, DataType.TWO_BYTE_INT_UNSIGNED)); batch.addLocator("alarm", BaseLocator.coilStatus(slaveId, 10)); batch.setContiguousRequests(false); batch.setErrorsInResults(true); BatchResults results = master.send(batch); System.out.println("\n=== Batch Read Results ==="); System.out.println("Temp 1: " + ((Number) results.getValue("temp1")).floatValue() + " C"); System.out.println("Temp 2: " + ((Number) results.getValue("temp2")).floatValue() + " C"); System.out.println("Pressure: " + ((Number) results.getValue("pressure")).floatValue() + " bar"); System.out.println("Level: " + ((Number) results.getValue("level")).intValue() + " %"); System.out.println("Alarm: " + results.getValue("alarm")); // === Multiple Data Types Demo === System.out.println("\n=== Data Type Examples ==="); // 16-bit signed integer BaseLocator int16Loc = BaseLocator.holdingRegister(slaveId, 100, DataType.TWO_BYTE_INT_SIGNED); System.out.println("Int16: " + master.getValue(int16Loc).shortValue()); // 32-bit unsigned integer BaseLocator uint32Loc = BaseLocator.holdingRegister(slaveId, 102, DataType.FOUR_BYTE_INT_UNSIGNED); System.out.println("UInt32: " + master.getValue(uint32Loc).longValue()); // 64-bit double BaseLocator doubleLoc = BaseLocator.holdingRegister(slaveId, 106, DataType.EIGHT_BYTE_FLOAT); System.out.println("Double: " + master.getValue(doubleLoc).doubleValue()); } catch (ModbusInitException e) { System.err.println("Initialization failed: " + e.getMessage()); } catch (ModbusTransportException e) { System.err.println("Transport error (Slave " + e.getSlaveId() + "): " + e.getMessage()); } catch (ErrorResponseException e) { System.err.println("Error response: " + e.getErrorResponse().getExceptionCode()); } finally { master.destroy(); System.out.println("\nConnection closed"); } } } ``` -------------------------------- ### Efficient Batch Reading with modbus4j Source: https://context7.com/mangoautomation/modbus4j/llms.txt Demonstrates how to perform efficient batch reads of multiple Modbus data points using BatchRead. Includes setup for Modbus master, adding various locators with String keys, configuring batch options, executing the read, and processing results including error handling. Also shows an example with Integer keys for array-like access and how to cancel a batch. ```java import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.BatchRead; import com.serotonin.modbus4j.BatchResults; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.locator.BaseLocator; import com.serotonin.modbus4j.code.DataType; import com.serotonin.modbus4j.ExceptionResult; ModbusFactory factory = new ModbusFactory(); IpParameters params = new IpParameters(); params.setHost("192.168.1.100"); params.setPort(502); ModbusMaster master = factory.createTcpMaster(params, true); try { master.init(); int slaveId = 1; // Create a batch read request with String keys BatchRead batch = new BatchRead<>(); // Add multiple locators with unique keys batch.addLocator("temperature", BaseLocator.holdingRegister(slaveId, 0, DataType.FOUR_BYTE_FLOAT)); batch.addLocator("pressure", BaseLocator.holdingRegister(slaveId, 2, DataType.FOUR_BYTE_FLOAT)); batch.addLocator("flowRate", BaseLocator.holdingRegister(slaveId, 4, DataType.FOUR_BYTE_FLOAT)); batch.addLocator("status", BaseLocator.holdingRegister(slaveId, 6, DataType.TWO_BYTE_INT_UNSIGNED)); batch.addLocator("alarm1", BaseLocator.coilStatus(slaveId, 0)); batch.addLocator("alarm2", BaseLocator.coilStatus(slaveId, 1)); batch.addLocator("inputStatus", BaseLocator.inputStatus(slaveId, 0)); batch.addLocator("counter", BaseLocator.inputRegister(slaveId, 10, DataType.FOUR_BYTE_INT_UNSIGNED)); // Configure batch behavior // Force contiguous reads (prevents gaps in register addresses) batch.setContiguousRequests(false); // Include errors in results instead of throwing exceptions batch.setErrorsInResults(true); // Include transport exceptions in results batch.setExceptionsInResults(true); // Execute the batch read BatchResults results = master.send(batch); // Retrieve results by key Object tempValue = results.getValue("temperature"); if (tempValue instanceof ExceptionResult) { ExceptionResult error = (ExceptionResult) tempValue; System.err.println("Temperature read error: " + error.getExceptionCode()); } else { System.out.println("Temperature: " + ((Number) tempValue).floatValue() + " C"); } System.out.println("Pressure: " + ((Number) results.getValue("pressure")).floatValue() + " bar"); System.out.println("Flow Rate: " + ((Number) results.getValue("flowRate")).floatValue() + " m3/h"); System.out.println("Status: " + ((Number) results.getValue("status")).intValue()); System.out.println("Alarm 1: " + results.getValue("alarm1")); System.out.println("Alarm 2: " + results.getValue("alarm2")); System.out.println("Input Status: " + results.getValue("inputStatus")); System.out.println("Counter: " + ((Number) results.getValue("counter")).longValue()); // Example with Integer keys for array-like access BatchRead indexedBatch = new BatchRead<>(); for (int i = 0; i < 10; i++) { indexedBatch.addLocator(i, BaseLocator.holdingRegister(slaveId, 100 + i, DataType.TWO_BYTE_INT_SIGNED)); } BatchResults indexedResults = master.send(indexedBatch); for (int i = 0; i < 10; i++) { System.out.println("Register " + (100 + i) + ": " + indexedResults.getValue(i)); } // Cancel a long-running batch batch.setCancel(true); // Can be called from another thread } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } finally { master.destroy(); } ``` -------------------------------- ### Create and Configure Modbus TCP Slave Source: https://context7.com/mangoautomation/modbus4j/llms.txt Demonstrates the creation of a Modbus TCP slave, setting up a process image with various data types, and adding listeners for write events. Ensure the slave is started in a separate thread to avoid blocking. ```java import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusSlaveSet; import com.serotonin.modbus4j.BasicProcessImage; import com.serotonin.modbus4j.ProcessImageListener; import com.serotonin.modbus4j.code.DataType; import com.serotonin.modbus4j.code.RegisterRange; ModbusFactory factory = new ModbusFactory(); // Create TCP slave (false = standard Modbus TCP, true = encapsulated RTU) ModbusSlaveSet slave = factory.createTcpSlave(false); // Create a process image for slave ID 1 BasicProcessImage processImage = new BasicProcessImage(1); // Configure behavior for invalid addresses processImage.setAllowInvalidAddress(true); processImage.setInvalidAddressValue((short) 0); // Set initial coil values (addresses 0-9) for (int i = 0; i < 10; i++) { processImage.setCoil(i, i % 2 == 0); } // Set initial discrete input values (read-only) for (int i = 0; i < 10; i++) { processImage.setInput(i, i % 3 == 0); } // Set holding register values with various data types processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 0, DataType.TWO_BYTE_INT_SIGNED, 12345); processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 1, DataType.TWO_BYTE_INT_UNSIGNED, 65000); processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 2, DataType.FOUR_BYTE_FLOAT, 123.456f); processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 4, DataType.FOUR_BYTE_INT_SIGNED, 1000000); processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 6, DataType.EIGHT_BYTE_FLOAT, 3.14159265359); // Set string value in holding registers processImage.setString(RegisterRange.HOLDING_REGISTER, 20, DataType.CHAR, 10, "HELLO"); // Set individual register values processImage.setHoldingRegister(100, (short) 0x1234); processImage.setHoldingRegister(101, (short) 0x5678); // Set input register values (read-only from master's perspective) processImage.setNumeric(RegisterRange.INPUT_REGISTER, 0, DataType.FOUR_BYTE_FLOAT, 25.5f); processImage.setInputRegister(10, (short) 100); // Set individual bits within a register processImage.setHoldingRegisterBit(200, 0, true); processImage.setHoldingRegisterBit(200, 1, false); processImage.setHoldingRegisterBit(200, 15, true); // Add listener for write events from master processImage.addListener(new ProcessImageListener() { @Override public void coilWrite(int offset, boolean oldValue, boolean newValue) { System.out.println("Coil " + offset + " changed from " + oldValue + " to " + newValue); } @Override public void holdingRegisterWrite(int offset, short oldValue, short newValue) { System.out.println("Holding register " + offset + " changed from " + oldValue + " to " + newValue); } }); // Add the process image to the slave slave.addProcessImage(processImage); // Optionally add more process images for different slave IDs BasicProcessImage processImage2 = new BasicProcessImage(2); processImage2.setNumeric(RegisterRange.HOLDING_REGISTER, 0, DataType.FOUR_BYTE_FLOAT, 99.9f); slave.addProcessImage(processImage2); // Start the slave (this blocks the current thread) new Thread(() -> { try { slave.start(); // Listens on default port 502 } catch (Exception e) { System.err.println("Slave error: " + e.getMessage()); } }).start(); // To update values dynamically while running processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 2, DataType.FOUR_BYTE_FLOAT, 200.0f); // Read current values try { short regValue = processImage.getHoldingRegister(100); boolean coilValue = processImage.getCoil(0); Number floatValue = processImage.getNumeric(RegisterRange.HOLDING_REGISTER, 2, DataType.FOUR_BYTE_FLOAT); System.out.println("Current values - Reg100: " + regValue + ", Coil0: " + coilValue + ", Float: " + floatValue); } catch (Exception e) { System.err.println("Read error: " + e.getMessage()); } // Stop the slave when done slave.stop(); // Remove a process image slave.removeProcessImage(1); // or slave.removeProcessImage(processImage2); ``` -------------------------------- ### Modbus Master Read/Write Operations Source: https://context7.com/mangoautomation/modbus4j/llms.txt Demonstrates reading and writing various Modbus data types including coils, holding registers (signed/unsigned integers, floats, doubles), and input registers. Includes setup for Modbus TCP master and error handling. ```java import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.locator.BaseLocator; import com.serotonin.modbus4j.code.DataType; import com.serotonin.modbus4j.exception.ModbusTransportException; import com.serotonin.modbus4j.exception.ErrorResponseException; ModbusFactory factory = new ModbusFactory(); IpParameters params = new IpParameters(); params.setHost("192.168.1.100"); params.setPort(502); ModbusMaster master = factory.createTcpMaster(params, true); try { master.init(); int slaveId = 1; // Read a coil (boolean) BaseLocator coilLocator = BaseLocator.coilStatus(slaveId, 0); Boolean coilValue = master.getValue(coilLocator); System.out.println("Coil 0: " + coilValue); // Write a coil master.setValue(coilLocator, true); // Read a holding register as signed 16-bit integer BaseLocator int16Locator = BaseLocator.holdingRegister(slaveId, 100, DataType.TWO_BYTE_INT_SIGNED); Number int16Value = master.getValue(int16Locator); System.out.println("Register 100 (Int16): " + int16Value.shortValue()); // Write a 16-bit integer value master.setValue(int16Locator, (short) 12345); // Read a 32-bit floating point value (spans 2 registers) BaseLocator floatLocator = BaseLocator.holdingRegister(slaveId, 200, DataType.FOUR_BYTE_FLOAT); Number floatValue = master.getValue(floatLocator); System.out.println("Register 200-201 (Float): " + floatValue.floatValue()); // Write a float value master.setValue(floatLocator, 123.456f); // Read a 64-bit double (spans 4 registers) BaseLocator doubleLocator = BaseLocator.holdingRegister(slaveId, 300, DataType.EIGHT_BYTE_FLOAT); Number doubleValue = master.getValue(doubleLocator); System.out.println("Register 300-303 (Double): " + doubleValue.doubleValue()); // Read an input register (read-only) BaseLocator inputLocator = BaseLocator.inputRegister(slaveId, 0, DataType.TWO_BYTE_INT_UNSIGNED); Number inputValue = master.getValue(inputLocator); System.out.println("Input Register 0: " + inputValue.intValue()); // Read/write individual bit within a holding register BaseLocator bitLocator = BaseLocator.holdingRegisterBit(slaveId, 400, 3); Boolean bitValue = master.getValue(bitLocator); System.out.println("Register 400, Bit 3: " + bitValue); master.setValue(bitLocator, true); } catch (ModbusTransportException e) { System.err.println("Transport error: " + e.getMessage()); } catch (ErrorResponseException e) { System.err.println("Slave error response: " + e.getErrorResponse().getExceptionCode()); } finally { master.destroy(); } ``` -------------------------------- ### Modbus Locator Creation with Register Ranges Source: https://context7.com/mangoautomation/modbus4j/llms.txt Shows how to create NumericLocator objects for different Modbus register ranges using constants from RegisterRange and DataType. Requires importing com.serotonin.modbus4j.locator.NumericLocator, com.serotonin.modbus4j.code.DataType, and com.serotonin.modbus4j.code.RegisterRange. ```java import com.serotonin.modbus4j.locator.NumericLocator; import com.serotonin.modbus4j.code.DataType; import com.serotonin.modbus4j.code.RegisterRange; // Create locators for different register ranges NumericLocator holdingLocator = new NumericLocator(1, RegisterRange.HOLDING_REGISTER, 0, DataType.TWO_BYTE_INT_SIGNED); NumericLocator inputLocator = new NumericLocator(1, RegisterRange.INPUT_REGISTER, 0, DataType.TWO_BYTE_INT_UNSIGNED); ``` -------------------------------- ### Initialize and Configure Modbus TCP Master Source: https://context7.com/mangoautomation/modbus4j/llms.txt Configure Modbus TCP master settings such as timeouts, retries, and connection parameters before initializing the connection. Ensure to destroy the master instance when done. ```java import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.exception.ModbusInitException; ModbusFactory factory = new ModbusFactory(); IpParameters params = new IpParameters(); params.setHost("192.168.1.100"); params.setPort(502); ModbusMaster master = factory.createTcpMaster(params, true); // Configure timeout (milliseconds) - default is 500ms master.setTimeout(1000); // Configure number of retries - default is 2 master.setRetries(3); // Configure maximum read counts for batch operations master.setMaxReadBitCount(2000); // For coils and discrete inputs master.setMaxReadRegisterCount(125); // For holding and input registers master.setMaxWriteRegisterCount(120); // For write operations // Force use of multiple write commands only (for devices that don't support single writes) master.setMultipleWritesOnly(true); // Set discard data delay for serial communications master.setDiscardDataDelay(50); try { // Initialize the master connection master.init(); // Check if initialization was successful if (master.isInitialized()) { System.out.println("Master initialized successfully"); System.out.println("Connected: " + master.isConnected()); } // Perform operations... } catch (ModbusInitException e) { System.err.println("Failed to initialize master: " + e.getMessage()); } finally { // Always destroy the master when done master.destroy(); } ``` -------------------------------- ### Add modbus4j Snapshot Repository Source: https://github.com/mangoautomation/modbus4j/blob/master/README.md Add this repository to your pom.xml to include snapshot builds of modbus4j. ```xml false true ias-snapshots Infinite Automation Snapshot Repository https://maven.mangoautomation.net/repository/ias-snapshot/ true false ias-releases Infinite Automation Release Repository https://maven.mangoautomation.net/repository/ias-release/ ``` -------------------------------- ### Modbus4j Supported Data Types Source: https://context7.com/mangoautomation/modbus4j/llms.txt Illustrates the usage of DataType constants for different Modbus data types, including integers, floats, BCD, and strings. Also shows how to determine register count and Java type for a given Modbus data type. ```java import com.serotonin.modbus4j.code.DataType; // Binary (single bit) int binary = DataType.BINARY; // 1 register // 16-bit integers (1 register) int int16Signed = DataType.TWO_BYTE_INT_SIGNED; int int16Unsigned = DataType.TWO_BYTE_INT_UNSIGNED; int int16SignedSwapped = DataType.TWO_BYTE_INT_SIGNED_SWAPPED; // Byte swapped int int16UnsignedSwapped = DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED; // 32-bit integers (2 registers) int int32Signed = DataType.FOUR_BYTE_INT_SIGNED; int int32Unsigned = DataType.FOUR_BYTE_INT_UNSIGNED; int int32SignedSwapped = DataType.FOUR_BYTE_INT_SIGNED_SWAPPED; int int32UnsignedSwapped = DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED; int int32SignedSwappedSwapped = DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED; // 0xAABBCCDD -> 0xDDCCBBAA int int32UnsignedSwappedSwapped = DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED; // 64-bit integers (4 registers) int int64Signed = DataType.EIGHT_BYTE_INT_SIGNED; int int64Unsigned = DataType.EIGHT_BYTE_INT_UNSIGNED; int int64SignedSwapped = DataType.EIGHT_BYTE_INT_SIGNED_SWAPPED; int int64UnsignedSwapped = DataType.EIGHT_BYTE_INT_UNSIGNED_SWAPPED; // Floating point int float32 = DataType.FOUR_BYTE_FLOAT; // 2 registers int float32Swapped = DataType.FOUR_BYTE_FLOAT_SWAPPED; int float32SwappedInverted = DataType.FOUR_BYTE_FLOAT_SWAPPED_INVERTED; int float64 = DataType.EIGHT_BYTE_FLOAT; // 4 registers int float64Swapped = DataType.EIGHT_BYTE_FLOAT_SWAPPED; // BCD (Binary Coded Decimal) int bcd16 = DataType.TWO_BYTE_BCD; // 1 register int bcd32 = DataType.FOUR_BYTE_BCD; // 2 registers int bcd32Swapped = DataType.FOUR_BYTE_BCD_SWAPPED; // Modulo 10K types (for large counters) int mod10k32 = DataType.FOUR_BYTE_MOD_10K; // 2 registers int mod10k48 = DataType.SIX_BYTE_MOD_10K; // 3 registers int mod10k64 = DataType.EIGHT_BYTE_MOD_10K; // 4 registers int mod10k32Swapped = DataType.FOUR_BYTE_MOD_10K_SWAPPED; int mod10k48Swapped = DataType.SIX_BYTE_MOD_10K_SWAPPED; int mod10k64Swapped = DataType.EIGHT_BYTE_MOD_10K_SWAPPED; // Single byte integers (within a 16-bit register) int byte8Lower = DataType.ONE_BYTE_INT_UNSIGNED_LOWER; // Lower byte int byte8Upper = DataType.ONE_BYTE_INT_UNSIGNED_UPPER; // Upper byte // Strings int charType = DataType.CHAR; // Fixed length int varcharType = DataType.VARCHAR; // Variable length // Get register count for a data type int registerCount = DataType.getRegisterCount(DataType.FOUR_BYTE_FLOAT); // Returns 2 // Get Java type for a data type Class javaType = DataType.getJavaType(DataType.FOUR_BYTE_FLOAT); // Returns Float.class ``` -------------------------------- ### Modbus Register Range Constants and Usage Source: https://context7.com/mangoautomation/modbus4j/llms.txt Demonstrates the use of RegisterRange constants for different Modbus register types, including retrieving their address ranges and read function codes. Requires importing com.serotonin.modbus4j.code.RegisterRange and com.serotonin.modbus4j.code.FunctionCode. ```java import com.serotonin.modbus4j.code.RegisterRange; import com.serotonin.modbus4j.code.FunctionCode; // Coil Status (0x outputs) - Read/Write single bits // Address range: 00001-09999 (0x0000-0xFFFF) int coilRange = RegisterRange.COIL_STATUS; // Value: 1 int coilFrom = RegisterRange.getFrom(coilRange); // 0x00000 int coilTo = RegisterRange.getTo(coilRange); // 0x0FFFF int coilReadFunction = RegisterRange.getReadFunctionCode(coilRange); // FC 01 // Input Status (1x inputs) - Read-only discrete inputs // Address range: 10001-19999 (0x10000-0x1FFFF) int inputStatusRange = RegisterRange.INPUT_STATUS; // Value: 2 int inputStatusFrom = RegisterRange.getFrom(inputStatusRange); // 0x10000 int inputStatusTo = RegisterRange.getTo(inputStatusRange); // 0x1FFFF int inputStatusReadFunction = RegisterRange.getReadFunctionCode(inputStatusRange); // FC 02 // Holding Registers (4x registers) - Read/Write 16-bit registers // Address range: 40001-49999 (0x40000-0x4FFFF) int holdingRange = RegisterRange.HOLDING_REGISTER; // Value: 3 int holdingFrom = RegisterRange.getFrom(holdingRange); // 0x40000 int holdingTo = RegisterRange.getTo(holdingRange); // 0x4FFFF int holdingReadFunction = RegisterRange.getReadFunctionCode(holdingRange); // FC 03 // Input Registers (3x registers) - Read-only 16-bit registers // Address range: 30001-39999 (0x30000-0x3FFFF) int inputRegRange = RegisterRange.INPUT_REGISTER; // Value: 4 int inputRegFrom = RegisterRange.getFrom(inputRegRange); // 0x30000 int inputRegTo = RegisterRange.getTo(inputRegRange); // 0x3FFFF int inputRegReadFunction = RegisterRange.getReadFunctionCode(inputRegRange); // FC 04 ``` -------------------------------- ### Add Modbus4j Maven Repository Source: https://github.com/mangoautomation/modbus4j/blob/master/README.txt Configure your Maven project to use the modbus-data-source repository to download modbus4j libraries. Ensure checksum policy is ignored for releases and snapshots are disabled. ```xml true ignore false modbus-data-source Modbus Dependencies https://maven.mangoautomation.net/repository/ias-release/ ``` -------------------------------- ### Create Modbus Data Point Locators Source: https://context7.com/mangoautomation/modbus4j/llms.txt Use BaseLocator factory methods to create type-safe locators for various Modbus register types and data formats. This includes coil status, input status, holding registers, and input registers, with support for bit-level access and different data types. ```java import com.serotonin.modbus4j.locator.BaseLocator; import com.serotonin.modbus4j.code.DataType; import com.serotonin.modbus4j.code.RegisterRange; int slaveId = 1; // Coil Status (read/write single bits) - addresses 00001-09999 BaseLocator coilLocator = BaseLocator.coilStatus(slaveId, 0); BaseLocator coilLocator100 = BaseLocator.coilStatus(slaveId, 100); // Input Status (read-only discrete inputs) - addresses 10001-19999 BaseLocator inputLocator = BaseLocator.inputStatus(slaveId, 0); // Holding Registers (read/write) BaseLocator holdingInt16 = BaseLocator.holdingRegister(slaveId, 0, DataType.TWO_BYTE_INT_SIGNED); BaseLocator holdingUInt16 = BaseLocator.holdingRegister(slaveId, 1, DataType.TWO_BYTE_INT_UNSIGNED); BaseLocator holdingInt32 = BaseLocator.holdingRegister(slaveId, 2, DataType.FOUR_BYTE_INT_SIGNED); BaseLocator holdingFloat = BaseLocator.holdingRegister(slaveId, 4, DataType.FOUR_BYTE_FLOAT); BaseLocator holdingDouble = BaseLocator.holdingRegister(slaveId, 6, DataType.EIGHT_BYTE_FLOAT); // Holding Register Bit Access (read/write individual bit within a register) BaseLocator holdingBit0 = BaseLocator.holdingRegisterBit(slaveId, 10, 0); // Bit 0 of register 10 BaseLocator holdingBit15 = BaseLocator.holdingRegisterBit(slaveId, 10, 15); // Bit 15 of register 10 // Input Registers (read-only) BaseLocator inputInt16 = BaseLocator.inputRegister(slaveId, 0, DataType.TWO_BYTE_INT_SIGNED); BaseLocator inputFloat = BaseLocator.inputRegister(slaveId, 2, DataType.FOUR_BYTE_FLOAT); // Input Register Bit Access BaseLocator inputBit = BaseLocator.inputRegisterBit(slaveId, 20, 5); // Generic locator creation with full control BaseLocator genericLocator = BaseLocator.createLocator( slaveId, // Slave ID RegisterRange.HOLDING_REGISTER, // Register range 100, // Offset DataType.FOUR_BYTE_FLOAT, // Data type 0, // Bit (for binary types) 0 // Register count (for string types) ); ``` -------------------------------- ### Add modbus4j Dependency Source: https://github.com/mangoautomation/modbus4j/blob/master/README.md Include this dependency in your pom.xml to use modbus4j in your project. ```xml com.infiniteautomation modbus4j 3.0.3 ``` -------------------------------- ### Implement SerialPortWrapper for Serial Communication Source: https://context7.com/mangoautomation/modbus4j/llms.txt Implement the SerialPortWrapper interface to integrate custom serial communication libraries for RTU/ASCII transports. This involves providing methods to open, close, and access input/output streams of a serial port. ```java import com.serotonin.modbus4j.serial.SerialPortWrapper; import java.io.InputStream; import java.io.OutputStream; // Example implementation using a hypothetical serial library public class MySerialPortWrapper implements SerialPortWrapper { private final String portName; private final int baudRate; private final int dataBits; private final int stopBits; private final int parity; // Your serial port implementation object private Object serialPort; // e.g., SerialPort from jSerialComm public MySerialPortWrapper(String portName, int baudRate, int dataBits, int stopBits, int parity) { this.portName = portName; this.baudRate = baudRate; this.dataBits = dataBits; this.stopBits = stopBits; this.parity = parity; } @Override public void open() throws Exception { // Open the serial port using your preferred library // Example with jSerialComm: // serialPort = SerialPort.getCommPort(portName); // serialPort.setComPortParameters(baudRate, dataBits, stopBits, parity); // serialPort.openPort(); } @Override public void close() throws Exception { // Close the serial port // serialPort.closePort(); } @Override public InputStream getInputStream() { // Return the input stream from your serial port // return serialPort.getInputStream(); return null; } @Override public OutputStream getOutputStream() { // Return the output stream from your serial port // return serialPort.getOutputStream(); return null; } @Override public int getBaudRate() { return baudRate; } @Override public int getDataBits() { return dataBits; } @Override public int getStopBits() { return stopBits; } @Override public int getParity() { return parity; } } // Usage with RTU Master // SerialPortWrapper wrapper = new MySerialPortWrapper("COM1", 9600, 8, 1, 0); // ModbusMaster rtuMaster = factory.createRtuMaster(wrapper); // rtuMaster.init(); // Common serial settings: // Baud rates: 9600, 19200, 38400, 57600, 115200 // Data bits: 7 or 8 // Stop bits: 1 or 2 // Parity: 0=None, 1=Odd, 2=Even, 3=Mark, 4=Space ``` -------------------------------- ### Creating Modbus Masters and Slaves with ModbusFactory Source: https://context7.com/mangoautomation/modbus4j/llms.txt Use ModbusFactory to create instances of Modbus masters and slaves for TCP, UDP, RTU, and ASCII transports. Configure IP parameters or serial port wrappers as needed. ```java import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.ModbusSlaveSet; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.serial.SerialPortWrapper; ModbusFactory factory = new ModbusFactory(); // Create TCP Master with keepAlive enabled IpParameters tcpParams = new IpParameters(); tcpParams.setHost("192.168.1.100"); tcpParams.setPort(502); ModbusMaster tcpMaster = factory.createTcpMaster(tcpParams, true); // Create TCP Master with linger time for controlled connection closing ModbusMaster tcpMasterWithLinger = factory.createTcpMaster(tcpParams, true, 5); // Create UDP Master IpParameters udpParams = new IpParameters(); udpParams.setHost("192.168.1.100"); udpParams.setPort(502); ModbusMaster udpMaster = factory.createUdpMaster(udpParams); // Create TCP Listener (passive mode, waits for connections) IpParameters listenerParams = new IpParameters(); listenerParams.setPort(502); ModbusMaster tcpListener = factory.createTcpListener(listenerParams); // Create RTU Master (requires SerialPortWrapper implementation) // SerialPortWrapper wrapper = new MySerialPortWrapper("COM1", 9600, 8, 1, 0); // ModbusMaster rtuMaster = factory.createRtuMaster(wrapper); // Create ASCII Master // ModbusMaster asciiMaster = factory.createAsciiMaster(wrapper); // Create TCP Slave (encapsulated mode for RTU over TCP) ModbusSlaveSet tcpSlave = factory.createTcpSlave(false); // Create UDP Slave ModbusSlaveSet udpSlave = factory.createUdpSlave(false); // Create RTU Slave // ModbusSlaveSet rtuSlave = factory.createRtuSlave(wrapper); // Create ASCII Slave // ModbusSlaveSet asciiSlave = factory.createAsciiSlave(wrapper); ``` -------------------------------- ### Discover Modbus Slave Nodes Synchronously and Asynchronously Source: https://context7.com/mangoautomation/modbus4j/llms.txt This snippet shows how to discover Modbus slave nodes using both synchronous and asynchronous scans. Configure the ModbusMaster with IP parameters and timeouts before initiating the scan. The asynchronous scan utilizes a NodeScanListener to report progress and found nodes. ```java import com.serotonin.modbus4j.ModbusFactory; import com.serotonin.modbus4j.ModbusMaster; import com.serotonin.modbus4j.NodeScanListener; import com.serotonin.modbus4j.ip.IpParameters; import com.serotonin.modbus4j.sero.util.ProgressiveTask; import java.util.List; ModbusFactory factory = new ModbusFactory(); IpParameters params = new IpParameters(); params.setHost("192.168.1.100"); params.setPort(502); ModbusMaster master = factory.createTcpMaster(params, true); master.setTimeout(100); // Short timeout for faster scanning master.setRetries(0); // No retries during scan try { master.init(); // Synchronous scan - blocks until complete (scans IDs 1-240) List foundNodes = master.scanForSlaveNodes(); System.out.println("Found " + foundNodes.size() + " slave nodes:"); for (Integer nodeId : foundNodes) { System.out.println(" Slave ID: " + nodeId); } // Test a specific slave node boolean nodeExists = master.testSlaveNode(1); System.out.println("Slave 1 exists: " + nodeExists); // Asynchronous scan with progress callback ProgressiveTask scanTask = master.scanForSlaveNodes(new NodeScanListener() { @Override public void nodeFound(int nodeNumber) { System.out.println("Found slave at ID: " + nodeNumber); } @Override public void progressUpdate(float progress) { int percent = (int) (progress * 100); System.out.println("Scan progress: " + percent + "%"); } @Override public void taskCancelled() { System.out.println("Scan cancelled"); } @Override public void taskCompleted() { System.out.println("Scan completed"); } }); // Optionally cancel the scan // scanTask.cancel(); // Wait for completion while (!scanTask.isCompleted()) { Thread.sleep(100); } } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } finally { master.destroy(); } ``` -------------------------------- ### Maven Dependency for modbus4j Source: https://context7.com/mangoautomation/modbus4j/llms.txt Add this Maven dependency to include modbus4j in your project. Ensure the repository is configured. ```xml true false ias-releases Infinite Automation Release Repository https://maven.mangoautomation.net/repository/ias-release/ com.infiniteautomation modbus4j 3.0.3 ``` -------------------------------- ### Add Modbus4j Maven Dependency Source: https://github.com/mangoautomation/modbus4j/blob/master/README.txt Include the modbus4j artifact as a dependency in your Maven project's pom.xml file. Specify the group ID, artifact ID, and version. ```xml com.infiniteautomation modbus4j 3.0.3 ``` -------------------------------- ### Configure IpParameters for TCP/UDP Connections Source: https://context7.com/mangoautomation/modbus4j/llms.txt Use IpParameters to set host, port, and encapsulation mode for TCP/UDP Modbus masters. The default Modbus TCP port is 502. Encapsulated mode is used for RTU over TCP/IP. ```java import com.serotonin.modbus4j.ip.IpParameters; // Basic configuration IpParameters params = new IpParameters(); params.setHost("192.168.1.100"); params.setPort(502); // Default Modbus TCP port // Check current settings String host = params.getHost(); int port = params.getPort(); // Encapsulated mode (RTU over TCP/IP) // When true, uses RTU framing instead of standard Modbus TCP framing params.setEncapsulated(true); // Configure socket linger time (affects connection close behavior) // -1 or null = disabled (default) // 0 = immediate close with RST // >0 = linger for specified seconds before close params.setLingerTime(5); ``` ```java // Example: Standard Modbus TCP IpParameters standardParams = new IpParameters(); standardParams.setHost("10.0.0.50"); standardParams.setPort(502); standardParams.setEncapsulated(false); ``` ```java // Example: RTU over TCP (some devices use this) IpParameters encapsulatedParams = new IpParameters(); encapsulatedParams.setHost("10.0.0.51"); encapsulatedParams.setPort(502); encapsulatedParams.setEncapsulated(true); ``` ```java // Example: Non-standard port IpParameters customPortParams = new IpParameters(); customPortParams.setHost("192.168.1.200"); customPortParams.setPort(10502); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.