Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a Modbus TCP Slave Server in Java with Value Change Listeners

Tech May 18 2

Establishing a Modbus TCP slave endpoint in Java commonly leverages dedicated protocol libraries. The following implementation demonstrates how to configure the environment, bootstrap the network listener, populate the holding register memory map, and attach an observer for real-time mutation tracking.

Dependency Resolution

<dependency>
    <groupId>com.infiniteautomation</groupId>
    <artifactId>modbus4j</artifactId>
    <version>3.0.3</version>
</dependency>

Configuration Note: Certain corporate proxies or aggregated repository mirrors occasionally route malformed requests for this artifact. If dependency resolution fails, switch explicitly to Maven Central or verify your local firewall/DNS forwarding rules.

Endpoint Initialization

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusSlaveSet;
import com.serotonin.modbus4j.ip.tcp.TcpSlave;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class ModbusEndpointStarter implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments arguments) throws Exception {
        // Launch the protocol listener on a detached worker thread to preserve application context loading
        Thread networkThread = new Thread(this::bindModbusDaemon, "Modbus-IoT-Worker");
        networkThread.setDaemon(true);
        networkThread.start();

        // Allow sufficient latency for socket binding and descriptor allocation
        Thread.sleep(1200);

        // Trigger secondary registration or cache-seeding routines here
        // populateStaticMappings();
    }

    private void bindModbusDaemon() {
        ModbusFactory protocolGateway = new ModbusFactory();
        // Instantiate TCP listener on standard industrial port 502
        ModbusSlaveSet deviceEndpoint = new TcpSlave(502, false);
        deviceEndpoint.addProcessImage(MemoryLayoutMapper.generateDefaultMap());

        try {
            System.out.println("Modbus TCP node bound and operational.");
            deviceEndpoint.start();
        } catch (Exception transportError) {
            transportError.printStackTrace();
        }
    }
}

Memory Layout & Register Seeding

import com.serotonin.modbus4j.BasicProcessImage;

public class MemoryLayoutMapper {

    private static final int HOLDING_SPACE_LIMIT = 608;

    public static BasicProcessImage generateDefaultMap() {
        // Reserve addressing range for logical device ID 1
        BasicProcessImage storageRegion = new BasicProcessImage(1);

        // Pre-allocate holding registers with zeroed states
        for (int pointer = 0; pointer < HOLDING_SPACE_LIMIT; pointer++) {
            storageRegion.setHoldingRegister(pointer, (short) 0x0000);
        }

        // Register the modification watcher against the process image
        storageRegion.addListener(new HoldingRangeWatcher());
        return storageRegion;
    }
}

Mutation Event Subscriber

import com.serotonin.modbus4j.ProcessImageListener;

public class HoldingRangeWatcher implements ProcessImageListener {

    @Override
    public void coilWrite(int targetAddress, boolean initialStatus, boolean updatedStatus) {
        // Coil-level events are excluded from this monitoring scope
    }

    @Override
    public void holdingRegisterWrite(int registerOffset, short previousValue, short newValue) {
        System.out.printf("Holding register #%d transitioned from %d to %d%n",
                registerOffset, previousValue, newValue);
    }
}

Upon deployment, the application binds to port 502 and continuously accepts incoming telegrams. Validation can be performed using standard diagnostic utilities like Modbus Poll or QModMaster. Establishing a session successfully indicates that the underlying socket is active and the exposed process image is responding to queries.

Related Articles

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Comprehensive Guide to Hive SQL Syntax and Operations

This article provides a detailed walkthrough of Hive SQL, categorizing its features and syntax for practical use. Hive SQL is segmented into the following categories: DDL Statements: Operations on...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.