Git Product home page Git Product logo

j2mod's Introduction

Overview

This project is a fork of the j2mod library which began life as jamod. A huge amount of refactoring and code fixing has been carried out on this library, with the addition of supporting JUnit tests, to ensure the library is fit for production use.

This implementation supports Modbus TCP, UDP, RTU over TCP, Serial RTU and Serial ASCII in both Master and Slave configurations. The serial comms is implemented using jSerialComm and does not require any outside dependencies over and above the logging facade slf4j.

For instructions on how to use the library, visit the wiki here

Releases

Stable releases can be downloaded here

https://mvnrepository.com/artifact/com.ghgande/j2mod

Snapshot releases can be downloaded here

https://oss.sonatype.org/content/repositories/snapshots/com/ghgande/j2mod/

Known Issues

  • There are no unit tests for the RTU over TCP transport
  • There is no way of adding AbstractSerialTransportListener to a ModbusSlave which means you cannot get informed of when the library is switching between send and receive
  • A refactor is overdue to hide package components to encourage best practise usage patterns

Dependencies

  • jSerialComm The serial comms is handled by JSerialComm that includs native implementations for most platforms.
  • slf4j Logging facade to fit in with your application logging framework
  • JRE 1.8 (JRE 1.6 for v2.70 and lower)

Including j2mod

<dependency>
    <groupId>com.ghgande</groupId>
    <artifactId>j2mod</artifactId>
    <version>LATEST</version>
</dependency>

Announcements

j2mod's People

Contributors

adramaqueen avatar ambroises avatar bantu avatar caiokrauel avatar feduska avatar j123b567 avatar javicacheiro avatar liebehentze avatar martentamerius avatar martynasrim avatar mkurt avatar nnadeau avatar pan-henryk avatar sirhcel avatar steveohara avatar vrolijkxcentrica avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

j2mod's Issues

Is ObservableRegister broken?

I am trying to detect changes in my slave image in a way similar to described here:
#64

My code looks like this:

`
SimpleProcessImage spi = new SimpleProcessImage(unitId);

               ObservableRegister or = new ObservableRegister();

                or.setValue(bb.getShort());

                or.addObserver(this);

                spi.setInputRegister(address,or);

`

I can read this register from master (so general setup is ok), but if I try to write to it, update method of observer is never called. At the message level slave receives write request and responds to it.
Is there a chance that slave refactoring broke it?

I am using Modbus TCP.

Serial slave not reading response from other slave

Expected Behavior

The slave should detect that the master request is not destined to the slave. After this the slave should expect there to come a response on the serial line and read it. Otherwise should timeout and expect another request.

Actual Behavior

The slave detects that the message it not for it, and correctly ignores it. But the slave does not expect the response and thinks that this is supposed to be another request. This results in the slave not correctly reading the next request meant for it.

Steps to Reproduce the Problem

  1. Connect one master to two slaves on a serial bus.
  2. Send read requests to one of the slaves.
  3. Look at debug printouts on the other master.

Specifications

  • Version: 2.5.1-SNAPSHOT

Listen to one specific UnitID with serial RTU slave?

I'm trying to write an application that is supposed to emulate a slave on a specific address. So far I have gotten the program to receive data through the serial port and it sends back som messages to the master. But I sends a lot of exception messages because it receives messages ment for another unit. This is not good for the master program as it only expects one answer but gets a response from two units.

Is there a way to stop this behavior?
To create the slave I do: ModbusSlave slave = ModbusSlaveFactory.createSerialSlave(params);
I create a ProcessImageImplementation like this: And add it to the slave like this:

Is there something that I am doing wrong, something about the library I am using in a wrong way?

Otherwise this is a very good feature to have as it allows for simulating one of many devices on a network.

WARNUNG: Error com.ghgande.j2mod.modbus.ModbusIOException:I/O exception - failed to read

Thank you for keeping this library with an excellent api alive.
I am having issues comparable to:

with the following code on a raspberry PI using /dev/ttyUSB0 with a UART USB-connector applied. The connection works with QModBus at 9600 baud, 8 databits 1 stop bit and no parity.
What might be wrong in this setup and how can I debug it?

grafik

import com.ghgande.j2mod.modbus.util.SerialParameters;

/**
 * SimpleEvSE Modbus
 * 
 * @author wf
 *         // https://github.com/steveohara/j2mod
 */
public class SModbus {

  String portName;
  private SerialParameters serialParams;
  private ModbusSerialMaster master;
  private int timeOut;

  /**
   * construct me for the given port
   * 
   * @param portName
   * @param timeOut
   */
  public SModbus(String portName, int timeOut) {
    this.portName = portName;
    this.timeOut = timeOut;
    // http://jamod.sourceforge.net/kb/serial_master_howto.html
    // https://stackoverflow.com/questions/26621299/java-modbus-rtu-master-example-code
    serialParams = new SerialParameters();
    serialParams.setPortName(portName);
    serialParams.setBaudRate(9600);
    serialParams.setDatabits(8);
    serialParams.setParity("None");
    serialParams.setStopbits(1);
    serialParams.setEncoding("ascii");
    serialParams.setEcho(false);
    master = new ModbusSerialMaster(serialParams, this.timeOut);
  }

  /**
   * dump registers
   * 
   * @throws Exception
   */
  public void dumpRegisters() throws Exception {
    master.connect();
    // https://github.com/steveohara/j2mod/pull/48
    AbstractSerialConnection con = master.getConnection();
    System.out.println(String.format(
        "connected to %s %s at %5d baud %2d data bits %2d stop bits\n available ports:%s",
        con.getDescriptivePortName(), portName, con.getBaudRate(),
        con.getNumDataBits(), con.getNumStopBits(),
        con.getCommPorts().toString()));
    master.setRetries(0);
    int ref = 1000;
    int count = 2;
    Register[] regs = master.readMultipleRegisters(ref, count);
    int i = ref;
    for (Register reg : regs) {
      System.out.println(String.format("%3d: %3d", i++, reg.getValue()));
    }
    master.disconnect();
  }
}

Setting timeout of TCPMaster does not get applied to transactions

ModBusTCPTransport does not receive the timeout from the ModbusTCPMaster

To reproduce:
Set the timeout on the ModbusTCPMaster to 30000
Make a request to readMultipleRegisters

The transaction timeout is back to the default of 3000
Also, when the connection fails and is re-established the timeouts for the transaction are also reverted to the default of 3000

Function code 0x17 first performs a read and then the write.

According to the specification a Read/Write request in a single command (function code 23, or 0x17) should first perform the write and then the read command.

If you write to an address and read the same address back using the same command, you would expect the number you've just written to be returned. (used for is-alive tests)

Yet, the second call returns the value written so it always lacks a command behind.

From the spec:
This function code performs a combination of one read operation and one write operation in a
single MODBUS transaction. The write operation is performed before the read.

Length of ReadWriteMultipleResponse indicates 1 byte too much?

Compared to the modbusTCP specs listed at the website http://www.modbus-ida.org the respons of a functioncall 0x17 contains the following information:

Function code
Byte count
2bytes for each register

When reading 5 registers, the bytecount shows 11 instead of 10.. In the code I can see +1 added everywere. Is this actually correct?

byteCount = registers.length * 2 + 1; (what is the +1 doing here?)

ModbusTCPListener does not propagate timeout to slave connections

When creating a ModbusTCPListener it accepts to set a timeout for incoming connections but this timeout is not propagated to TCPSlaveConnections.

This means that when you set the timeout of the ModbusTCPListener only affects the original server socket that is listening for connections, but the slave sockets assigned to each incoming connections maintain the Modbus.DEFAULT_TIMEOUT of 3 seconds and it is not possible to change it.

Changing the TCPSlaveConnection timeout is very useful to avoid closing the established master connections after 3 seconds.

I would say that probably most users of the library would expect that when they change the timeout of the listener it will affect also the slave connections created.

It would be possible to set the two timeouts separately but I can not think of many situations where this would be useful, so propagating the timeout seems the most straightforward solution.

Got java.util.IllegalFormatConversionException in exceptions throws

Stacktrace:

java.util.IllegalFormatConversionException: d != com.ghgande.j2mod.modbus.ModbusIOException
	at java.util.Formatter$FormatSpecifier.failConversion(Formatter.java:4302)
	at java.util.Formatter$FormatSpecifier.printInteger(Formatter.java:2793)
	at java.util.Formatter$FormatSpecifier.print(Formatter.java:2747)
	at java.util.Formatter.format(Formatter.java:2520)
	at java.util.Formatter.format(Formatter.java:2455)
	at java.lang.String.format(String.java:2940)
	at com.ghgande.j2mod.modbus.ModbusException.<init>(ModbusException.java:59)
	at com.ghgande.j2mod.modbus.ModbusIOException.<init>(ModbusIOException.java:60)
	at com.ghgande.j2mod.modbus.io.ModbusTCPTransaction.execute(ModbusTCPTransaction.java:176)

Modbus Slave Multiple Port Support

We need to be able to use multiple ports for our Modbus Slave project. From what I can see, this isn't possible because the ModbusCoupler is a singleton with only a single port assignment possible.

I am happy to put together a pull request with support for multiple ports, but I would appreciate your feedback on whether or not you are interested in including it in your library, and if so, what your preferred implementation would be. The two approaches that I see are

  1. change ModbusCoupler from a singleton to an instantiated class. This would break backwards compatibility.
  2. change ModbusCoupler to have a public constructor but continue to maintain support for the singleton ModbusCoupler. This would maintain backwards compatibility, but might look a little messy.

Any other suggested implementations are welcome too.
Thanks!

Is ObservableRegister broken

Expected Behavior

Actual Behavior

Steps to Reproduce the Problem

Specifications

  • Version:
  • Platform:
  • Subsystem:

Function code 23: read&write registers

Hi Steve,

First a big thank you for all the hard work you have done on this project!

I was going through the source code today and noticed a function (23 - ReadWriteMultipleRegisters) which we would like to use, might not be fully functional yet. The ReadWriteMultipleRequest and -Response classes are implemented, but in the AbstractModbusMaster there is no mention of this type of request.

Is this on purpose, or a work-in-progress, or maybe something else I missed?

Marten Tamerius

WriteMultipleRegisters (Function Code : 0x10) does not work.

I created a mockup modbus slave(TCP Server) using ModbusTCPListener class and test WriteMultipleRegisters function, but error occurred with "Illegal Data Address" message.

I think it is problem with WriteMultipleRegistersRequest.readData()'s m_Reference = input.readShort();.

I changed to input.readUnsignedShort() and checked it works fine.

Serial/RTU slower on 2.x

Hello,

For starters, I would like to thank all of the people who are working on improving j2mod, notably in the exception handling and logging aspects. The 2.x version looks much cleaner and it is a relief to move away from RxtxComm !

That being said, I just migrated to j2mod 2.0, and using the exact same code for my RTU tests, I noticed the time tripled. A single connection to read 2 registers takes ~400ms on j2mod 1.06, but takes 2s 800ms using j2mod 2.x.

Has anyone else noticed this behavior upon moving 2.0?

Add checks to see if serial port is available during connect

At the moment, the library can fail with a variety of opaque errors when the user chooses to connect to a port that they don't have access to either through permissions or because it doesn't actually exist.
It would be helpful if this situation were detected and a more useful error thrown to indicate the exact problem.

Multiple reads of the same function code

The registers on my device as following:

  • Holding registers: ref: 0, length 18
  • Holding registers: ref: 100, length 18
  • Holding registers: ref: 200, length 1

I can't read it in 1 read request because the protocol limit is 125 registers per request.
When I'm trying to read like this:

registers = master.readMultipleRegisters(1, 0, 18);
registers = master.readMultipleRegisters(1,100, 1);

Something is not correct, I got delays between the reads.

Modbus TCP Slave / How to detect process image change

(I posted this on the sourceforge site, but I saw you moved here - sorry for duplicate post)

I have question about modbus TCP slave. I have the simple tutorial working (the one from the Wiki) and masters can connect to it and read/write the process image

Question:
On my slave device, what's the best way to detect if the process image has been changed (by the master of course).

CR characters lost on ModbusSerialTransport

I noticed that the communications with our equipment is very slow.
When I enable debug logging, I get messages like:

17:09:27.399 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Read From buffer: 68 (44)
17:09:27.400 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Read From buffer: 70 (46)
17:09:27.400 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Returning combined value of: DF
17:09:27.401 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Read From buffer: 49 (31)
17:09:27.402 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Read From buffer: 51 (33)
17:09:27.402 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Returning combined value of: 13
17:09:27.404 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Read From buffer: 10 (0A)
17:09:33.403 DEBUG [main] c.g.j.m.i.ModbusASCIITransport - Cannot read from serial port
17:09:33.403 DEBUG [main] c.g.j.m.i.ModbusSerialTransaction - Execute try 1 error: I/O exception - failed to read
17:09:33.403 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Wrote FRAME_START
17:09:33.403 DEBUG [main] c.g.j.m.i.ModbusSerialTransport - Wrote byte 1=[48, 49]

which suggests to me that the expected CR before the NL isn't there, and the program is waiting for another byte while the line has already ended. AFAICS the stty settings are not set to drop them.
This happens both on Linux and on Mac OSX, using the 2.1.1 version.

NullPointerException when trying to communicate between Windows and Linux

Hello,

Simply, I am running Modbuspal.java on a windows machine, where I have created a slave and filled some coils and registers.

Then from the same windows machine, I used j2mod in order to read coils/registers, the operation wen successfully.

The problem is that when I ran the same code on a linux (ubuntu) virtual machine, a null pointer exception is being released everytime, the connection phase is succeeding, but the reading is not.

The code is:

import java.net.InetAddress;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ghgande.j2mod.modbus.Modbus;
import com.ghgande.j2mod.modbus.ModbusException;
import com.ghgande.j2mod.modbus.io.ModbusTCPTransaction;
import com.ghgande.j2mod.modbus.msg.ReadCoilsRequest;
import com.ghgande.j2mod.modbus.msg.ReadCoilsResponse;
import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesRequest;
import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesResponse;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersRequest;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersResponse;
import com.ghgande.j2mod.modbus.net.TCPMasterConnection;

//Process
public class ModbusTest {

/* The important instances of the classes mentioned before */
protected static TCPMasterConnection con = null; //the conection
/* Variables for storing the parameters */
protected static InetAddress addr = null; //the slave's address
protected static final int port = 502;
protected static final int ref = Integer.parseInt("1", 16); //the reference; offset where to start reading from
protected static final int count = 100; //the number of DI's to read
protected static final int repeat = 1; //a loop for repeating the transaction
static int SlaveAddr=1;


public static void main(String[] args) {
	
	try {
        addr = InetAddress.getByName("130.190.97.101");
        //Coils
        ReadCoilsRequest RCreq = new ReadCoilsRequest (3,1);
        ReadCoilsResponse RCres = new ReadCoilsResponse();
        
        //Registers
        ReadMultipleRegistersRequest RRreq = new ReadMultipleRegistersRequest (4,1);
        ReadMultipleRegistersResponse RRres = new ReadMultipleRegistersResponse();
        
        RCreq.setUnitID(SlaveAddr); //set Slave Address  
        RCres.setUnitID(SlaveAddr); //set Slave Address
        
        RRreq.setUnitID(SlaveAddr);
        RRres.setUnitID(SlaveAddr);
        
        
        //2. Open the connection
        con = new TCPMasterConnection(addr);
        con.setPort(5555);
        con.connect();
        
        ModbusTCPTransaction trans = null;
        trans = new ModbusTCPTransaction(con);
        
        
        trans.setRequest(RCreq);
        trans.execute();
        RCres = (ReadCoilsResponse) trans.getResponse();
        System.out.println("Connected to = "+ addr + " " + con.isConnected() + " /Start Register " + Integer.toHexString(ref));
        System.out.println("The value READ (coils): " + RCres.getCoils().toString());
        
        trans.setRequest(RRreq);
        trans.execute();
        RRres = (ReadMultipleRegistersResponse) trans.getResponse();
        for (int n = 0; n < RRres.getWordCount(); n++) {
            System.out.println("Word = " + RRres.getRegisterValue(n));
        }
        
        
        //6. Close the connection
        con.close();
    } catch (Exception ex) {
        Logger.getLogger(ModbusTest.class.getName()).log(Level.SEVERE, null, ex);
    }
}

}

The error is in the line:
System.out.println("The value READ (coils): " + RCres.getCoils().toString());

Connected to = /130.190.97.101 true /Start Register 1
Apr 19, 2017 2:55:16 AM ModbusTest main
SEVERE: null
java.lang.NullPointerException
at ModbusTest.main(ModbusTest.java:62)

Double socket creation in ModbusTCP

It seems that the execution of the following code creates two different sockets:

ModbusTCPMaster` master = new ModbusTCPMaster(slaveAddress,slavePort);
master.connect();
InputRegister[] registers = master.readMultipleRegisters(unitId, ref, count);

The constructor of ModbusTCPMaster, also creates a new instance of TCPMasterConnection (let's name it mc1)
The first socket (let's name it s1) is created by TCPMasterConnection connect() method that also instantiate a new ModbusTCPTransport, by passing the socket to its constructor; finally this method sets TCPMasterConnection's connected property to true.
After this, connection.getModbusTransport().createTransaction(); is called. This method, at first, checks if master variable is null (that is the case, because it is not set anywhere in the code) and creates another instance of TCPMasterConnection (let's name it mc2), assinging it to master variable (let's note that mc2.connected == false). Finally, it returns a new instance of ModbusTCPTransaction.
The code of ModbusTCPMaster's readMultipleRegisters(int unitId, int ref, int count) method, after building the modbus request, invokes the execute() method on the previously returned istance of ModbusTCPTransaction. This method, first check if the instance of TCPMasterConnection referenced by this transaction is connected; in this case the associated instance is mc2 (not connected) and not mc1 (connected), thus implying the creation of a new socket (let's name it s2) that is then used to send the request. The previously created socket (s1) is never used to send/receive data.
I used readMultipleRegisters method as an example, but every method using ModbusTCPTransaction's executeMethod() has the same behaviour.
I think that a possible solution could be adding a setMaster(TCPMasterConnection master) method in ModbusTCPTransport class and modifiyng prepareTransport method in TCPMasterConnection in the following way:

    private void prepareTransport(boolean useRtuOverTcp) throws IOException {
        if (transport == null) {
            if (useRtuOverTcp) {
                logger.trace("prepareTransport() -> using RTU over TCP transport.");
                transport = new ModbusRTUTCPTransport(socket);
                transport.setMaster(this);
            }
            else {
                logger.trace("prepareTransport() -> using standard TCP transport.");
                transport = new ModbusTCPTransport(socket);
                transport.setMaster(this);
            }
        }
        else {
            logger.trace("prepareTransport() -> using custom transport: {}", transport.getClass().getSimpleName());
            transport.setSocket(socket);
        }
    }

Debug logger messages causing garbage collections even when DEBUG mode is not enabled

I made a little benchmark to compare the memory performance of j2mod and another Modbus library (jlibmodbus). I read 6 holding registers with a repetition period of 20ms and 100.000 repetitions. I saw that the j2mod test caused 27 garbage collections (young space minor GCs) while the jlibmodbus test caused only 6 garbage collections in the 31,5 minutes that the benchmark was running.

I investigated why j2mod is causing more garbage collections and I found out that temporary char arrays (i.e. Strings) are filling the young space. In my test the most of these char arrays are allocated by the ModbusUtil.toHex method which is called by the ModbusTCPTransport class as shown in the following allocation call tree:
image

I saw that the calls of the ModbusUtil.toHex method in the ModbusTCPTransport class are made from logger.debug calls so I added the isDebugEnabled() check in the 3 calls of the logger.debug method:

 if(logger.isDebugEnabled())
            	logger.debug(...);

After the change I repeated the benchmark and the garbage collections of j2mod test were only 7.

As explained here https://stackoverflow.com/a/29561054 when building one of the parameters of the debug message might be expensive, you would still want to use isDebugEnabled() even with SLF4J.

So you could consider adding the isDebugEnabled check in all your debug messages.

Not possible to override handleRequest in ModbusSlave

I have developed a modbus proxy service for modbus that redirects requests to a given gateway, allowing multiple masters to connect simulataneously.

To implement it, it would be quite useful to be able to override the handleRequest method of the ModbusSlave class making it again protected (as it was before).

Amend TCPMasterConnection socket handling

When attempting a connection in the above class the Socket creation isn't respecting the timeout period. The result is that if a connection is attempted to an unavailable host the code hangs for 30-40s before issuing a timeout exception. The connect method should probably use:

        if (!isConnected()) {
            logger.debug("connect()");

            socket = new Socket();
            socket.setReuseAddress(true);
            socket.setSoLinger(true, 1);
            socket.setKeepAlive(true);
            setTimeout(timeout);

            socket.connect(new InetSocketAddress(address, port), timeout);

            prepareTransport(useRtuOverTcp);

            connected = true;
        }

which does respect the timeout.

RS485 echo in RTU mode

I have echo turned on (rs485 with echo) and using RTU coding. Now not the whole echo gets ignored. The crc of the master-request is taken as slave response.

The problem is in the class
ModbusRTUTransport:
if (echo) { readEcho(len); }

there should be 'readEcho(len +2);'
+2 for the 2 crc bytes... the same as in the class ModbusBINTransport. There this is already fixed...
I fixed this locally and it works great!

Getting j2mod/jSerialComm to work on Android

Has anyone been able to successfully get j2mod and its dependency jSerialComm to work on Android? I'm facing the same issue that the users in jSerialComm's issues thread 45 were facing. I've been searching for an answer for more than a week and have gotten nowhere.

I've tried the following (plus many others, all of which did not help):

  • Google's Add Build Dependencies, which consisted of me placing the JARs for j2mod, jSerialComm, and slf4j into my project's app/libs/ directory. I also tried removing the jSerialComm JAR and adding it's Gradle dependency directive for Maven, compile 'com.fazecast:jSerialComm:1.3.11'.
  • The marked solution in this Stackoverflow post on how to include .so files (which I tried to do instead of using the jSerialComm JAR file)
  • The marked solution in this Stackoverflow post on getting jSerialComms to work in Android

I'm working with a device running Android 5.1.1 (API 22) on an ARM Cortex-A9 SoC with 5 physical serial ports, labelled ttyAMA0 through ttyAMA4 in /dev/. SELinux is set to Disabled.

I know that this question is better suited for the jSerialComm issues threads, but it's already been asked there and no one has provided a viable solution.

Thank you very much for the help.

RTU over TCP

The application runs with Modbus TCP with a simulator . The problem is running with Modbus RTU over TCP. It doesnยดt work.
I understand the concepts of SetHeadless, but my application is different.

Thank you very much in advance.

package teste;

import java.net.;
import java.io.
;

import com.ghgande.j2mod.modbus.;
import com.ghgande.j2mod.modbus.msg.
;
import com.ghgande.j2mod.modbus.io.;
import com.ghgande.j2mod.modbus.net.
;
import com.ghgande.j2mod.modbus.util.*;

public class Modbus_ip {

public static void main(String[] args) {

    try{
     //Read And Write Register Sample
    int port = 502;
    int ref=5;
    int count = 6; //the number Address to read
    int SlaveAddr=1;
    String astr = "127.0.0.1"; //Modbus Device                 

    InetAddress addr = InetAddress.getByName(astr);
    TCPMasterConnection con = new TCPMasterConnection(addr); //the connection
    ModbusTCPTransaction trans = null; //the transaction

    //1.Prepare the request
    /************************************/
    ReadMultipleRegistersRequest Rreq = new ReadMultipleRegistersRequest(ref,count);
    ReadMultipleRegistersResponse Rres = new ReadMultipleRegistersResponse();

    Rreq.setHeadless(false);
    Rreq.setUnitID(SlaveAddr); //set Slave Address  

    //2. Open the connection
    con.setPort(port);
    con.connect();
    con.setTimeout(5000);


    //3. Start Transaction
    trans = new ModbusTCPTransaction(con);
    trans.setRetries(1);

    trans.setReconnecting(true);
    trans.setRequest(Rreq);
    trans.execute();

    /*Print Response*/
    Rres = (ReadMultipleRegistersResponse) trans.getResponse();

    System.out.println("Connected to=  "+ astr + con.isConnected() + " / Start Register " + ref);

// count=1;
for (int k=0;k<count;k++){
System.out.println("The value READ: " + Rres.getRegisterValue(k));
}

/****************Close Connection**************/
    con.close();
    System.out.println("\nConnected = " + con.isConnected());
    System.exit(0);//edit Java bug error


} 
catch (Exception ex) {
ex.printStackTrace();

}   


}

}

RTU Over TCP Resend Bug

When writing via RTU Over TCP after the first write subsequent writes go with header and the "useRtuOverTcp" turn false.
All the tries to write fail after that.

This issue only occur when reconnection is set to true "((ModBusTCPMaster)).setReconnecting(true)", the "transport" object get NULL and set the "headless" flag to false.

Wrong transaction ID set to request

Let's assume to execute the following code:

for (int i = 0; i < 10; i++) {
    ModbusTCPMaster master = new ModbusTCPMaster(slaveAddress,slavePort);
    try {
        master.connect();
    }
    catch (Exception e) {
        logger.error("Error while connecting to slave at {}:{}", slaveAddress, slavePort, e);
        System.exit(-1);
    }
    try {   
        InputRegister[] registers1 = master.readMultipleRegisters(slaveId, 601, 1);
        InputRegister[] registers2 = master.readMultipleRegisters(slaveId, 1001, 1);
    }
    catch (ModbusException e) {
        logger.error("Failure while reading register", e);
    }
    master.disconnect();
}

Here the transaction id associated with the first read request will always be 0, while the transaction id associated to the second read request will be 1 for the first iteration, 3 for the second, and so on.
This is due to the fact that, on each iteration, a new ModbusTCPMaster is instantiated and, when invoking readMultipleRegisters(), a new ReadMultipleRegistersRequest object is created too. The newly request object is always initialized with a transaction id equal to 0.
Instead, the second readMultipleRegisters() reuses this request object whose transaction id was modified at the end of the previous read operation by ModbusTCPTransaction, setting it to the value of the static property ModbusTransaction.transactionID which is incremented at the end of every read/write operation.
I believe that the transaction id associated to the first read in the iteration should also be set to the value in ModbusTransaction.transactionID
A possible workaround could be modifying the setRequest method of ModbusTransaction class in the following way:

    public void setRequest(ModbusRequest req) {
        request = req;
        request.setTransactionID(getTransactionID());
    }

In this way, we can always be sure that the transaction id associated to a request will always be equal to the value of ModbusTransaction.transactionID
Moreover, a transaction id shaould also be incremented if the current transaction fails.

j2mod on Android

Hello, I'm triyng to use j2mod on an Android application through RTU, but I saw that the library needs the jSerialComm dependency that requires /dev/tti* device. So it does't work with a specific kernel driver.
I am planning to use https://github.com/felHR85/UsbSerial for the low level communication.
Do you have any advice about this?

Thanks

Help: reading schneider PM5350, weird behavior encountered.

I am experiencing a weird issue using J2mod to read a Schneider power meter (PM5350).

Before I got into details, I have to mention that I have so far used J2mod to read many other power meters without any issue. In fact, J2mod has been extremely helpful in our project. I have also written a fluent wrapper API around J2mod to abstract and encapsulate Serial, TCP and RTU/TCP connections (which I would love to share, but cannot at this moment, will be doing so in the future). Anyhow, J2mod has worked seamlessly until I tried to read this device. I pray that this is a mistake of mine only, and hope that you might enlighten me on what I might be doing wrong, but after two days of trying to figure this out on my own, I am beginning to suspect J2mod to be culprit. Now, onto the details:

As mentioned, I am trying to read a Schneider PM5350 power meter. Its configuration is as follows:

Modbus RTU / ASCII
Baud: 9600
Parity "none" -> Databits 8, Stop bits 2
Parity "even/odd" -> Databits 8, Stop bits 1

I would like to read its frequency, of which the value is known to be 60.00 Hz (varies between 59~61). This value is big-endian floating point value stored onto two typical 16bit registers. The registers are 3110 and 3111.

When reading modbus devices, I use command line tool named "Modpoll" in conjunction with my code (j2mod 2.1.+ && jSerialComm 1.3.11) to compare values. So far, on all the devices I have previously mapped, values were the same. However, when trying to read the meter using j2mod, the returned values are always incorrect.

Using Modpoll (as demonstrated below), I am always able to read the proper values for both registers. Because it is a big-endian floating point, the value of the second register (3111) always changes, which is normal. Using an IEEE conversion sheet, I am able to compute the correct value to ~60.00.

Lastly, I have tried reading the meter (using both modpoll and j2mod) in two ways:

  1. Using a TCP to RTU converter gateway (which works neatly with other devices)
  2. Directly using RTU on /dev/ttyUSB0

The following are my tests:

MODPOLL TCP

Hex

$ ./modpoll -m tcp -a 5 -r 3110 -c 2 -t 4:hex -f 192.168.127.55

Protocol configuration: MODBUS/TCP
Slave configuration...: address = 5, start reference = 3110, count = 2
Communication.........: 192.168.127.55, port 502, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register (hex), output (holding) register table
Word swapping.........: Slave configured as big-endian float machine

-- Polling slave... (Ctrl-C to stop)
[3110]: 0x4270
[3111]: 0x0A41

Dec

$ ./modpoll -m tcp -a 5 -r 3110 -c 2 -t 4 -f 192.168.127.55

Protocol configuration: MODBUS/TCP
Slave configuration...: address = 5, start reference = 3110, count = 2
Communication.........: 192.168.127.55, port 502, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, output (holding) register table
Word swapping.........: Slave configured as big-endian float machine

-- Polling slave... (Ctrl-C to stop)
[3110]: 17008
[3111]: 4781

# Float = 60.0182380676

J2MOD TCP

(not using my wrapper code for testing purposes here)

TCPMasterConnection connection = new TCPMasterConnection(InetAddress.getByName("192.168.127.55"));
connection.setPort(502);

// Build request (unit 1, register 3110, 2 words)
ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(3110, 2);
req.setUnitID(5);

// Obtain transaction, set request
connection.connect();
ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
//        transaction.setConnection(connection);
transaction.setRequest(req);

// Open, execute, close
transaction.execute();
ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) transaction.getResponse();
connection.close();

// Read value

LOG.debug("Response: {} words\n>{}\n>{}\n{} + {}",
        res.getWordCount(), res.getMessage(), res.getHexMessage(),
        res.getRegisterValue(0), res.getRegisterValue(1));

Exec 1

2016-07-07 13:56:48,248 [main] DEBUG c.g.j.modbus.net.TCPMasterConnection - connect()
2016-07-07 13:56:48,254 [main] TRACE c.g.j.modbus.net.TCPMasterConnection - prepareTransport() -> using standard TCP transport.
2016-07-07 13:56:48,261 [main] DEBUG c.g.j.modbus.io.ModbusTCPTransaction - request transaction ID = 0
2016-07-07 13:56:48,265 [main] DEBUG c.g.j.modbus.io.ModbusTCPTransport - Sent: 00 00 00 00 00 06 05 03 0C 26 00 02
2016-07-07 13:56:48,266 [main] DEBUG c.g.j.modbus.io.ModbusTCPTransport - Read: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2016-07-07 13:56:48,303 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - reset()
2016-07-07 13:56:48,303 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - mark=0 pos=0
2016-07-07 13:56:48,303 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - mark()
2016-07-07 13:56:48,304 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - mark=0
2016-07-07 13:56:48,304 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,304 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,316 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - reset()
2016-07-07 13:56:48,316 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - mark=0 pos=0
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,317 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,318 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,318 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,318 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,318 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,318 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,318 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,321 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,321 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,321 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,321 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,321 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,321 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,322 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 13:56:48,323 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=13
2016-07-07 13:56:48,323 [main] DEBUG c.g.j.modbus.io.ModbusTCPTransaction - response transaction ID = 0, RESPONSE: 00 00 00 00 00 07 05 03 04 12 1C FF FF 
2016-07-07 13:56:48,325 [main] DEBUG c.x.modbus.schneider.SimpleReadTest - Response: 2 words
>[4, 18, 28, -1, -1]
>00 00 00 00 00 07 05 03 04 12 1C FF FF 
4636 + 65535

Exec 2

2016-07-07 13:58:23,404 [main] DEBUG c.g.j.modbus.io.ModbusTCPTransport - Sent: 00 00 00 00 00 06 05 03 0C 26 00 02
2016-07-07 13:58:23,411 [main] DEBUG c.g.j.modbus.io.ModbusTCPTransport - Read: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
2016-07-07 13:58:23,459 [main] DEBUG c.g.j.modbus.io.ModbusTCPTransaction - response transaction ID = 0, RESPONSE: 00 00 00 00 00 07 05 03 04 FD 2F FF FF 
// (skip FastByteArrayInputStream debug)
2016-07-07 13:58:23,462 [main] DEBUG c.x.modbus.schneider.SimpleReadTest - Response: 2 words
>[4, -3, 47, -1, -1]
>00 00 00 00 00 07 05 03 04 FD 2F FF FF 
64815 + 65535

Now back to Modpoll, using direct RTU on /dev/ttyUSB0.

MODPOLL RTU

$ ./modpoll -m rtu -a 5 -r 3110 -c 2 -t 4 -f -b 9600 -d 8 -s 2 -p none /dev/ttyUSB0

Protocol configuration: Modbus RTU
Slave configuration...: address = 5, start reference = 3110, count = 2
Communication.........: /dev/ttyUSB0, 9600, 8, 2, none, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, output (holding) register table
Word swapping.........: Slave configured as big-endian float machine

-- Polling slave... (Ctrl-C to stop)
[3110]: 17008
[3111]: 7826
-- Polling slave... (Ctrl-C to stop)
[3110]: 17008
[3111]: 3756

$ ./modpoll -m rtu -a 5 -r 3110 -c 2 -t 4:hex -f -b 9600 -d 8 -s 2 -p none /dev/ttyUSB0

Slave configuration...: address = 5, start reference = 3110, count = 2
Communication.........: /dev/ttyUSB0, 9600, 8, 2, none, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register (hex), output (holding) register table
Word swapping.........: Slave configured as big-endian float machine

-- Polling slave... (Ctrl-C to stop)
[3110]: 0x426F
[3111]: 0xFC67
-- Polling slave... (Ctrl-C to stop)
[3110]: 0x426F
[3111]: 0xF642

# Float = 60.0143280029

J2MOD RTU

(not using my wrapper code for testing purposes here)

// Build connection
SerialParameters connectionParameters;
connectionParameters = new SerialParameters();
connectionParameters.setPortName("/dev/ttyUSB0");
connectionParameters.setBaudRate(9600);
connectionParameters.setDatabits(8);
connectionParameters.setParity("none");
connectionParameters.setStopbits(2);
connectionParameters.setEncoding(Modbus.SERIAL_ENCODING_RTU);
SerialConnection connection = new SerialConnection(connectionParameters);

// Build request (unit 5, register 3110, 2 words)
ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(3110, 2);
req.setUnitID(5);

// Open connection, obtain transaction, set request
connection.open();
ModbusSerialTransaction transaction = new ModbusSerialTransaction(connection);
transaction.setRequest(req);

// Execute, close
transaction.execute();
connection.close();

// Read value
ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) transaction.getResponse();

LOG.debug("Response: {} words\n>{}\n>{}\n{} + {}",
        res.getWordCount(), res.getMessage(), res.getHexMessage(),
        res.getRegisterValue(0), res.getRegisterValue(1));

Exec 1

2016-07-07 14:10:13,540 [main] DEBUG c.g.j.modbus.io.ModbusRTUTransport - Sent: 05 03 0C 26 00 02 27 14 
2016-07-07 14:10:13,586 [main] DEBUG c.g.j.modbus.io.ModbusRTUTransport - Response: 05 03 04 F1 33 FF FF 7C B0 
2016-07-07 14:10:13,586 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 14:10:13,586 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=7
2016-07-07 14:10:13,586 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 14:10:13,586 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=7
2016-07-07 14:10:13,587 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 14:10:13,587 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=7
2016-07-07 14:10:13,593 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 14:10:13,597 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=7
2016-07-07 14:10:13,598 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 14:10:13,599 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=7
2016-07-07 14:10:13,599 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 14:10:13,599 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=7
2016-07-07 14:10:13,602 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - read()
2016-07-07 14:10:13,604 [main] DEBUG c.g.j.m.io.FastByteArrayInputStream - count=7
2016-07-07 14:10:13,610 [main] DEBUG c.x.modbus.schneider.SimpleReadTest - Response: 2 words
>[4, -15, 51, -1, -1]
>05 03 04 F1 33 FF FF 
61747 + 65535

Exec 2

2016-07-07 14:10:45,401 [main] DEBUG c.g.j.modbus.io.ModbusRTUTransport - Sent: 05 03 0C 26 00 02 27 14 
2016-07-07 14:10:45,456 [main] DEBUG c.g.j.modbus.io.ModbusRTUTransport - Response: 05 03 04 1D 1B FF FF C8 28 
// (skip FastByteArrayInputStream debug)
2016-07-07 14:10:45,484 [main] DEBUG c.x.modbus.schneider.SimpleReadTest - Response: 2 words
>[4, 29, 27, -1, -1]
>05 03 04 1D 1B FF FF 
7451 + 65535

I intend to parse the float value using the following code, but as you can see, register 3111 (word 2) is always "FF FF", and even the first word does not seem correct when compared to Modpoll's output.

public static float getFloat(Register mostSignificantWord, Register leastSignificantWord) {
    if (mostSignificantWord == null || leastSignificantWord == null) throw new NullPointerException();

    byte[] array = new byte[4];
    array[0] = mostSignificantWord.toBytes()[0];
    array[1] = mostSignificantWord.toBytes()[1];
    array[2] = leastSignificantWord.toBytes()[0];
    array[3] = leastSignificantWord.toBytes()[1];

    ByteBuffer bb = ByteBuffer.wrap(array);
    return bb.getFloat();
}

I must say I am not a Modbus expert, and am self-taught in the art of computer science. I am looking forward to your input and am eager to learn where I might be mistaken. Otherwise, it sounds like a bug candidate!

Last note: because the Schneider meter modbus settings are configurable, I have played around and tried with different parity, and even using ASCII, but to no avail.

Best regards,
Christopher

Serial port connection

Library version: 2.3.1

Hi!

I have some trouble with ModbusSerialMaster. I got a NPE during reading registers.

My code:

`

    SerialParameters parameters = new SerialParameters();

    parameters.setPortName("/dev/ttyUSB1");
    parameters.setBaudRate(9600);
    parameters.setDatabits(8);
    parameters.setStopbits(1);
    parameters.setParity("none");
    parameters.setEncoding("rtu");
    parameters.setEcho(false);

    ModbusSerialMaster master = new ModbusSerialMaster(parameters);

    master.connect();
    master.readMultipleRegisters(1, 0, 100);
    master.disconnect();

`
And stack:

Exception in thread "main" java.lang.NullPointerException at com.ghgande.j2mod.modbus.net.SerialConnection.setComPortTimeouts(SerialConnection.java:221) at com.ghgande.j2mod.modbus.io.ModbusSerialTransport.setTimeout(ModbusSerialTransport.java:142) at com.ghgande.j2mod.modbus.io.ModbusSerialTransport.open(ModbusSerialTransport.java:131) at com.ghgande.j2mod.modbus.io.ModbusSerialTransport.writeMessage(ModbusSerialTransport.java:73) at com.ghgande.j2mod.modbus.io.ModbusSerialTransaction.execute(ModbusSerialTransaction.java:143) at com.ghgande.j2mod.modbus.facade.AbstractModbusMaster.readMultipleRegisters(AbstractModbusMaster.java:236)

BIN encoding in serial connection

Is the BIN encoding supported for the serial connections?
From this I concluded, j2mod doesn't support. But jamod docs say that it does (see section Implementation, first Note).

Change hard coded 'value' in ObservableRegister

I'm using ObservableRegister to determine updates on my slave devices.
It calls notifyObservers with hardcoded argument of 'value', I can't inherit from ObservableRegister and overridden setValue methods because they are final.
I had to copy whole ObservableRegister class and change the argument to given one - I think it's a better default behavior.

Support as OSGi Bundle

It would be helpful if you can provide this library as an OSGi bundle so that it can be made available in lots of OSGi based frameworks.

Serial port errors are swallowed.

Running the debugger to see why j2mod doesn't work, I can see that errors about serial port are sent to AbstractModbusListener and readable via getErrors() but the listener is not accessible through ModbusSlave.

By extending ModbusSlave (I've called it ListenedSlave, sounds surreal) and making getListener() public, It's possible to get the error message, and perhaps printing it every 1 second. Raising an exception early sound like a better idea. Or perhaps I'm missing something?

By the way, nice job! j2mod is a great re-architecture of the old library.

Connection failed for /192.168.0.110:502

@test
public void testReadHoldingRegisters() {
ReadMultipleRegistersResponse res =(ReadMultipleRegistersResponse)readRequest(Modbus.READ_HOLDING_REGISTERS, 1, 1);
System.out.println(res.getRegisterValue(0));
//assertEquals("Incorrect value for holding register 1", 251, res.getRegisterValue(0));
}
Error
2018-05-25 12:36:49 INFO utils.AbstractTestModbusTCPMaster - Got error for request to localhost:502 (FC:3, Reg:1, Cnt:1) - Connection failed for /192.168.0.110:502

Modbus4j tested successfully, j2mod reported as above error

Using j2mod, Siemens s7 1200 test failed, modbus slave test succeeded

Cannot read from Serial Port

I'm not sure if this is problem related to the recent switch to jSerialComm, something missing in the documentation, or just something locally on my machine.

No matter what I seem to try I end up with:

DEBUG com.ghgande.j2mod.modbus.io.ModbusASCIITransport: Cannot read from serial port

I have tried two different implementations of Modbus Master with the same result. (The examples are below.)
In both examples, I end up at ModbusSerialTransport in readAsciiByte() where the call to readBytes from the commPort returns 0. I believe this means that the readBytes call is timing out without reading anything. I have tried increasing the timeout with no luck.

Normally, I would say this is an issue where the slave is not replying. The slave seems to receive the message perfectly fine, and replies. I have also used independent Modbus Master programs to test the communications with the slave is all working.

I'm hoping someone can point at an obvious problem in my code, or point me in a new direction.

private static void testModbusSerialASCIIConnection() {
        try {
            SerialParameters params = new SerialParameters();
            params.setPortName("COM1");
            params.setBaudRate(9600);
            params.setDatabits(8);
            params.setParity(SerialPort.NO_PARITY);
            params.setStopbits(SerialPort.ONE_STOP_BIT);
            params.setEncoding(Modbus.SERIAL_ENCODING_ASCII);
            params.setFlowControlIn(SerialPort.FLOW_CONTROL_DISABLED);
            params.setFlowControlOut(SerialPort.FLOW_CONTROL_DISABLED);
            params.setEcho(false);

            SerialConnection con = new SerialConnection(params);
            con.open();

            ReadCoilsRequest req = new ReadCoilsRequest(1, 40);
            req.setUnitID(20);

            ModbusSerialTransaction trans = new ModbusSerialTransaction(con);
            trans.setRequest(req);

            trans.execute();

            ReadCoilsResponse res = (ReadCoilsResponse) trans.getResponse();

            System.out.println("Digital Inputs Status=" + res.getCoils());

            con.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

And

private static void testModbusSerialASCIIConnection2() {
        try{

        SerialParameters params = new SerialParameters();
        params.setPortName("COM1");
        params.setBaudRate(9600);
        params.setDatabits(8);
        params.setParity(SerialPort.NO_PARITY);
        params.setStopbits(SerialPort.ONE_STOP_BIT);
        params.setEncoding(Modbus.SERIAL_ENCODING_ASCII);
        params.setFlowControlIn(SerialPort.FLOW_CONTROL_DISABLED);
        params.setFlowControlOut(SerialPort.FLOW_CONTROL_DISABLED);
        params.setEcho(false);

        ModbusSerialMaster master = new ModbusSerialMaster(params);
        master.connect();

        //master.setTimeout(10000);

        System.out.println(master.readCoils(20, 1, 8));

        master.disconnect();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Handle TCP Fragmentation cases

I'm diagnosing an issue whereby, for some devices, TCP fragmentation occurs and the J2mod library is not waiting for the rest of the message payload, thus filling the remainder with random bytes, causing response values to be incorrect.

My use case is:
Read Input Register, length 2
I'm using version 2.0 of the library.

Using Wireshark, I can see the message sent successfully, and I see the response. The response should be 12 bytes (8 header and 4 bytes payload). The first frame contains bytes 0-11, and the later frame contains byte 12. Wireshark correctly figures out that the PDU is split over multiple TCP frames, and reconstructs the messages. But J2mod does not wait for the second frame. Instead, my Response contains the correct data for bytes 0-11, plus a random byte for the 12th.

I confess that I don't know enough about the underlying implementation to be able to suggest what should change, nor have I found an easy way to reproduce this issue locally so I can test without connecting to a field device.

The tool 'ModPoll' seems to handle this use-case, since I'm able to run my code and get an incorrect value, and the ModPoll gives the correct value. The two requests and responses look identical in Wireshark (attached image).

image

Hope this is enough information to be helping to diagnose the problem.

Thanks!
Dan

Does Modbus ASCII handle the longer max message length?

Serial modbus with ASCII framing has a larger max message length than RTU. It dosen't look like this is handled in the code.

From the specification:

Each data byte needs two characters for encoding. Thus, to ensure compatibility at MODBUS application level between
ASCII mode and RTU mode, the maximum data size for ASCII data field (2x252) is the double the maximum data size for RTU data
field (252). Consequently, the maximum size of a MODBUS ASCII frame is 513 characters.

TCP slave, error on reading

Hi,

I was testing j2mod TCP slave for my project. I used example code:

public static void main(String[] args) 
    {
        ModbusSlave slave;
        try
        {
            // Create your register set
            ProcessImage image = makeMyProcessImage();

            // Create a slave to listen on port 502 and create a pool of 5 listener threads
            // This will create a new slave or return you the same slave already assigned to this port
            slave = ModbusSlaveFactory.createTCPSlave(502, 5);

            // Add the register set to the slave for unit ID 1
            // Each slave can have multiple process images but they must have a unique Unit ID within the slave
            slave.addProcessImage(1, image);

            // Start the slave listening on the port - this will throw an error if the socket is already in use
//            ModbusSlaveFactory.close(); 
            slave.open();
            while(1 == 1)
            {
                Thread.sleep(1000);
                System.out.println(new Date().toString());
            }
            // Close the slave - closes the socket and stops listening
        }
        catch(Exception ex)
        {
            System.out.println("exception on main: " + ex);
        }
    }

    private static ProcessImage makeMyProcessImage() 
    {
        SimpleProcessImage spi = null;
        spi = new SimpleProcessImage();
        spi.addDigitalOut(new SimpleDigitalOut(true));
        spi.addDigitalOut(new SimpleDigitalOut(false));
        spi.addDigitalIn(new SimpleDigitalIn(false));
        spi.addDigitalIn(new SimpleDigitalIn(true));
        spi.addDigitalIn(new SimpleDigitalIn(false));
        spi.addDigitalIn(new SimpleDigitalIn(true));
        spi.addRegister(new SimpleRegister(251));
        spi.addInputRegister(new SimpleInputRegister(45));
        return spi;
    }

For master I used ModMaster 0.4 program. On first read everything would be ok and I would get the value, that I had set in my Java program. But on second read I would get Bad file descriptor insider ModMaster and I would had to open and close connection to get another value.

After a while I tried it again, and now I can read same registers multiple times, but now I get unknown error if I change type of registers that I want to read or if I want to read bigger number of coils or registers then I had set in my Java program.

It's not ideal that you can read only coils / registers that had been set inside Java program, but it's quite a problem that you have to close and open connection if you want to read some other registers.

Does anyone any idea if this is library's limitation or should I change my code?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.