All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.martiii.modbustcpjava.net.NetHandler Maven / Gradle / Ivy

The newest version!
package me.martiii.modbustcpjava.net;

import me.martiii.modbustcpjava.protocol.ModbusHeader;
import me.martiii.modbustcpjava.protocol.ModbusRequest;
import me.martiii.modbustcpjava.protocol.ModbusResponse;
import me.martiii.simplenethandler.SimpleNetHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class NetHandler extends SimpleNetHandler {
    private final Logger logger = LoggerFactory.getLogger("ModbusTCPJava");
    private static int lastTransactionID = 0;
    private HashMap taskIDs;
    private final List retryThreads;

    public NetHandler() {
        taskIDs = new HashMap<>();
        retryThreads = new ArrayList<>();
        setPort(502);
        setCloseSocketIfDeactivated(false);
    }

    public void setSlaveAddress(String slaveAddress) {
        setAddress(slaveAddress);
    }

    public void setSlavePort(int slavePort) {
        setPort(slavePort);
    }

    public void executeTask(Task task, int retryTimeout) {
        if (closed) return;
        int transID = ++lastTransactionID;
        taskIDs.put(transID, task);
        if (lastTransactionID == 65535) {
            lastTransactionID = 0;
        }

        ModbusHeader header = task.getHeader();
        ModbusRequest request = task.getRequest();

        byte[] frame = new byte[8 + request.getData().length];

        frame[0] = (byte) (transID >>> 8);
        frame[1] = (byte) transID;

        int protocolID = header.getProtocolIdentifier();
        frame[2] = (byte) (protocolID >>> 8);
        frame[3] = (byte) protocolID;

        int length = 2 + request.getData().length;
        frame[4] = (byte) (length >>> 8);
        frame[5] = (byte) length;

        frame[6] = header.getUnitIdentifier();
        frame[7] = request.getFunctionCode();

        System.arraycopy(request.getData(), 0, frame, 8, request.getData().length);

        logger.debug("Writing task with id {}: {}", transID, task);

        Thread retryThread = new Thread(){
            @Override
            public void run() {
                write(frame);
                try {
                    Thread.sleep(retryTimeout);
                } catch (InterruptedException e) {
                    logger.debug("Retry thread interrupted");
                }
                if (taskIDs.containsValue(task) && (!closed || active)) {
                    logger.debug("Retrying task with id {}", transID);
                    run();
                } else {
                    synchronized (retryThreads) {
                        retryThreads.remove(this);
                    }
                }
            }
        };
        synchronized (retryThreads) {
            retryThreads.add(retryThread);
        }
        retryThread.start();

        activate();
    }

    public void cancelPendingRequests() {
        logger.debug("Cancelling pending requests");
        taskIDs.clear();
        deactivate();
    }

    @Override
    public boolean read(InputStream inputStream) throws Exception {
        DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(inputStream));

        byte[] frame = new byte[8];
        int read = dataInputStream.read(frame);
        if (read == 8) {
            int transID = ((frame[0] & 0xff) << 8) | (frame[1] & 0xff);
            int protocolID = ((frame[2] & 0xff) << 8) | (frame[3] & 0xff);
            int length = ((frame[4] & 0xff) << 8) | (frame[5] & 0xff);
            byte unitID = frame[6];
            byte functionCode = frame[7];

            byte[] data = new byte[length - 2];
            read = dataInputStream.read(data);
            if (read == length - 2) {
                if (taskIDs.containsKey(transID)) {
                    Task task = taskIDs.remove(transID);
                    ModbusResponse response = new ModbusResponse(functionCode, data, functionCode != task.getRequest().getFunctionCode());
                    logger.debug("Response for task with id {}: {}", transID, response);
                    task.getCallback().callback(response);
                }
            } else {
                throw new Exception("Invalid reading length");
            }
        } else {
            throw new Exception("Invalid reading length");
        }

        return taskIDs.isEmpty();
    }

    @Override
    public void close(boolean force) {
        if (force) {
            synchronized (retryThreads) {
                retryThreads.forEach(Thread::interrupt);
            }
        }
        super.close(force);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy