HomeDevelopmentSF Project Home
 

TCP Master HOW-TO

About

This document is a tutorial for writing Modbus/TCP Master applications utilizing the jamod library. It explains the basics and walk's you through a simple command line Master implementation, that will allow you to read that will allow you to read the state of one or more discrete input's from a slave on the network.
If you are new to Modbus, it is highly recommended to first take a look at Understanding the Protocol (especially the section about the TCP implementation) as well as the actual protocol specifications.

Note

The application build in the tutorial is actually part of the distribution codebase (net.wimpi.modbus.cmd.DITest).

What is a Master?

Thinking in terms of the Client-Server network computing paradigm, the Master application is a client. It establishes a connection with the slave (i.e. the server) and uses this connection for sending a Request to the slave, from which a Response will be received.
As described in Understanding the Protocol, each cycle of Request and Response is called a Transaction. Figure 1 shows a simple graphical representation of such a cycle:

Figure 1: Modbus Transaction

Modbus Transaction

The master can pull or poll (repeatedly) data from a source (data acquisition), as well as control a device. In the latter case it is often recommended to understand the mode of operation of the slave device. Industrial remote I/O's for example might have a mechanism (i.e. a watchdog) to ensure predictable behavior when the communication with the master is lost. Thus ensure to study the documentation of the particular device you are working with.
The simplenetwork setup for this tutorial is composed of two nodes, as depicted in Figure 2.

Figure 2: Network Setup

Network setup

What is a Discrete Input?

According to the Modbus data model, which is part of the protocol specification (see section 4.3) a Discrete Input is a single bit (i.e. 0 or 1, false or true), read-only "data item", which is usually provided by an I/O system. Figure 3 shows an example with simple switches that are mapped into the slave's process image in form of discrete inputs. The example master application will be capable of obtaining the state of these DI's from the slave.

Figure 3: Slave with DI's

Slave with DI's

Note

Related information is available in Understanding the Process Image.

Classes of Interest for the Developer

The motivation for creating jamod was to achieve an intuitive and object oriented implementation of the protocol, in a way, that there is a natural mapping from the domain knowledge (i.e. Modbus protocol) to the abstract class model. The important elements in the description above (What is a Master?) have been highlighted and the following list represents the mapping between them and the classes from jamod that will be needed for a master implementation:

Implementation

As the idea is to provide a tutorial in form of a very simple command line example, it will consist of only one class and most of the work will be done in the entry method (public static void main(String args[])). This is probably not the way jamod will be usually employed in OO designs, but we hope it serves the demonstrative purpose.

Before we start with coding, let's take a look at the simplified interaction diagram of the application, given as Figure 4. The part most interesting for this tutorial is colored blue, but note that the diagram also contains a little bit of the things that happen behind the scenes (i.e. within the Transport, with writeRequest() and readRequest()), which are there to give a more complete picture.

Figure 4: Simplified Master Interaction Diagram

Sequential Interaction Diagram

Now let's start writing code. We need a simple Java application skeleton, with imports of all jamod packages:

import java.net.*;
import java.io.*;
import net.wimpi.modbus.*;
import net.wimpi.modbus.msg.*;
import net.wimpi.modbus.io.*;
import net.wimpi.modbus.net.*;
import net.wimpi.modbus.util.*;
 
public class DITest {

  public static void main(String[] args) {
    try {
      ...
      ...
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }//main
  
}//class DITest
      

Next we add the instances and variables the application will need:

/* The important instances of the classes mentioned before */
TCPMasterConnection con = null; //the connection
ModbusTCPTransaction trans = null; //the transaction
ReadInputDiscretesRequest req = null; //the request
ReadInputDiscretesResponse res = null; //the response

/* Variables for storing the parameters */
InetAddress addr = null; //the slave's address
int port = Modbus.DEFAULT_PORT;
int ref = 0; //the reference; offset where to start reading from
int count = 0; //the number of DI's to read
int repeat = 1; //a loop for repeating the transaction
	  

Next the application needs to read in the parameters:

  1. <address [String]> as InetAddress into addr
    optionally the port might be added to the address as :<port>, and read into port.
  2. <register [int16]> as int into ref
  3. <bitcount [int16]> as int into count
  4. {<repeat [int]>} as int into repeat, 1 by default (optional)
//1. Setup the parameters
if (args.length < 3) {
  System.exit(1);
} else {
  try {
    String astr = args[0];
    int idx = astr.indexOf(':');
    if(idx > 0) {
      port = Integer.parseInt(astr.substring(idx+1));
      astr = astr.substring(0,idx);
    }
    addr = InetAddress.getByName(astr);
    ref = Integer.decode(args[1]).intValue();
    count = Integer.decode(args[2]).intValue();
    if (args.length == 4) {
      repeat = Integer.parseInt(args[3]);
    }
  } catch (Exception ex) {
    ex.printStackTrace();
    System.exit(1);
  }
}
	  

These will be used subsequently to setup and open the connection as well as prepare a request and a transaction:

//2. Open the connection
con = new TCPMasterConnection(addr);
con.setPort(port);
con.connect();

//3. Prepare the request
req = new ReadInputDiscretesRequest(ref, count);

//4. Prepare the transaction
trans = new ModbusTCPTransaction(con);
trans.setRequest(req);
	  

No we are ready for action. The last part is executing the prepared transaction the given (repeat) number of times and then for cleanup, close the connection:

//5. Execute the transaction repeat times
int k = 0;
do {
  trans.execute();
  res = (ReadInputDiscretesResponse) trans.getResponse();
  System.out.println("Digital Inputs Status=" + res.getDiscretes().toString());
  k++;
} while (k < repeat);

 //6. Close the connection
 con.close();
	  

That's all. Pretty simple no?.
The following is an example output with (debug enabled) of the application run against a test slave:

Fangorn:~/development/java/jamod wimpi$ java -Dnet.wimpi.modbus.debug=true \
  -cp build/classes net.wimpi.modbus.cmd.DITest localhost:5555 0 4 3
Connected to localhost/127.0.0.1:5555
Request: 00 00 00 00 00 06 00 02 00 00 00 04 
Response: 00 00 00 00 00 04 00 02 01 50 
Digital Inputs Status=00001010 
Response: 00 01 00 00 00 04 00 02 01 50 
Digital Inputs Status=00001010 
Response: 00 02 00 00 00 04 00 02 01 50 
Digital Inputs Status=00001010	  
	  

Note

The debug outputs of the library can be activated by passing the property net.wimpi.modbus.debug to the JVM (i.e. java -Dnet.wimpi.modbus.debug=true) and allow to see the actually exchanged modbus messages encoded as hex.

by Dieter Wimberger