The aim of this library is to let users to leverage the power of modbus RTU protocol through RS485 on Android devices, specifically on the Ltouch multi-touch panels (picture on the right) and development boards.

In order to communicate with your instruments and devices from Android through RS485 and modbus, you can link the modbus RTU library in your projects and call the methods, such as function code 3 Read Holding Registers or function 16 Preset Multiple Registers, the most widely used modbus functions.

This document helps you to understand how to design a project that uses the native modbus library for Android. Many approaches exist in the way a project could be structured; we suggest one of that is complete and efficient though.

Starting from January 2014, the latest library (v.0.3) supports both Android 2.3 Gingerbread and Android 4.0.4 Ice Cream Sandwich.
  • Ltouch F touch panel

    The Ltouch board is a high-performance system based on the Samsung ARM Cortex-A8 microcontroller specifically designed for industrial and home automation. Supports Android 2.3 and 4.0.4.

    Details Store

The most frequent situation that is encountered in industrial and home automations applications is the following: one or more slave devices (such as PLCs, Power inverters, remote I/O modules) connected in a bus line and a touch panel that acts as a master displaying devices' states accepting commands from users. Basically, this is at the heart of Human Machine Interface (HMI).

The HMI interface is designed using the Android framework. For those of you that are not familiar with creating Android projects, we suggest to take a look at this brief tutorial on how to create your first app with Android. Many other tutorials and books are available on the net.

The high-level architecture of a hypothetical Android project can be summarized in the picture below. The rounded boxes represent respectively:

  • The main activity (that runs on the MainUIthread)
  • The thread that manage all the modbus requests (red)
  • The native modbus library (yellow)
  • A FIFO queue data structure that is used for the modbus Writes.
  • android modbus rtu library

    The first question may arise is the following: why using a FIFO queue and critical sections? Because we supposed that the project has to manage regular graphical updates, therefore the stream of read requests has to be correctly overlapped with writes. Indeed, the FIFO queue garantees the requests will be processed with the same order as they arrive.

    In this tutorial, modbus reads and writes are considered as synonyms of modbus function 3 and 16 respectively.

    The mainUIthread represent the main thread Activity("Window") that the users see. It contains all the code necessary to manage the UI, like buttons, progress bars, text boxes, etc. We used only one Activity, but obviously, real world applications use more than one activity for accomplish their jobs. Indeed, it starts and stops the thread that manages the modbus reads/writes. The java code might be:

    public class MainActivity extends Activity{
    	private int fid 	     = 0;	//file handler to the serial port
    	private Thread workingthread = null;	//modbus thread
    	private int ReadsRefreshRate = 1000;
    	
    	//declare the queue with maximum 2000 elements
    	private BlockingQueue queue_writes = new ArrayBlockingQueue(2000);
    	
    	protected void onResume() {
    		super.onResume();
    		
    		if (fid == 0){
    			//Serial port opening with baudrate 38400bps and 40000ns for read/write timeout
                		fid = ModbusLib.openCom(38400,40000,40000);
    	        }
    		
    		//start the thread that manage the modbus RTU requests
    		workingthread=new ReadsWrites(queue_writes, mHandler, fid, ReadsRefreshRate);
    		workingthread.start();
    				
    	}
    }
    

    The onResume method accounts for opening the serial port (in this case with baudrate set to 38400bps and timeouts 40000ns for both modbus reads and writes) and for starting the thread that manages the modbus requests. When creating the modbus thread, it needs four parameters:

    • a blocking queue data structure,
    • an handler for returning back the modbus replies to the UI thread,
    • the file id that refers to the serial port you want to work with,
    • the Reads Refresh Rate that is the ideal refresh rate with which the reads will be executed.

    The queue_writes is a blocking queue with a maximum length of 2000. We used a BlockingQueue data structure because the elements must be added atomically, preserving also the order with which requests arrives. Because of that, the code that inserts the elements into the queue will be in a critical section.

    The objects that are stored in the queue must be of type WriteRequest. The class WriteRequest simply defines the object "modbus function" and is coded as follow:

    public class WriteRequest {
    	private int address;			//register address to start writing
    	private int node_id;			//slave id device number
    	private int regs;			//number of registers to write
    	private int[] holdingRegs;		//registers to write
    
    	public int getAddress() {
    		return address;
    	}
    
    	public void setAddress(int address) {
    		this.address = address;
    	}
    
    	public int getNode_id() {
    		return node_id;
    	}
    
    	public void setNode_id(int node_id) {
    		this.node_id = node_id;
    	}
    
    	public int getRegs() {
    		return regs;
    	}
    
    	public void setRegs(int regs) {
    		this.regs = regs;
    	}
    
    	public int[] getHoldingRegs() {
    		return holdingRegs;
    	}
    
    	public void setHoldingRegs(int[] holdingRegs) {
    		this.holdingRegs = holdingRegs;
    	}
    
    	public WriteRequest(int node_id, int address, int regs, int[] holdingRegs) {
    		//class constructor
    		super();
    		this.address = address;
    		this.node_id = node_id;
    		this.regs = regs;
    		this.holdingRegs = holdingRegs;
    	}
    	
    }
    

    A modbus write request can be defined as

    int hr = new int[6];		//the holding register
    WriteRequest w1 = new WriteRequest(1,1,6,hr);
    

    with hr as a valid reference to an integer array. As previously stated, the code that adds write requests has to be in a critical section to preserve the order. This is accomplished by using a Java synchronized statement specifying the name of the variable to be accessed atomically (i.e., the queue), namely:

    synchronized (queue_writes) {
    
    	WriteRequest w1 = new WriteRequest(1,1,6,hr);
    	
    	queue_writes.add(w1);
    
    	workingthread.interrupt();
    }
    

    The final statement wakes up the modbus thread in case it was sleeping, therefore it can process the new requests that are on the queue.

    We are now ready to analyze how can be designed the main thread that manage the modbus requests. We called this class ReadsWrites and it extends Thread in order to be executed in parallel with the other threads in the Android OS. The class private variables wrqueue, hd, fid and reads_rr are the same as those passed to the object constructor together with some other variables referring to modbus reads.

    The core of the class stands in the critical section. It works in a way that when the queue is not empty, it executes all the writing requests; otherwise it cyclically reads registers from the slave(s) and pause itself for a limited timespan. The thread wakes up when a new write request has to be executed.

    Since in Android background threads can not access the graphical objects directly, it is mandatory to manage the UI updates with messages and in particular using the handle that were gathered at the time of thread creation. The messages are created and sent by calling the obtainMessage and sendMessage methods. The class' code might be the following:

    public class ReadsWrites extends Thread{
    
       private BlockingQueue wrqueue = null;
       private Handler hd                          = null;
       private int max_retries                     = 1;	//defines how many retries before giving up
       private int reads_rr                        = 1000; 	//Read refresh rate, default value 
       
       private int node_to_write     = 1;
       private int starting_address  = 1;
       private int no_of_registers   = 10;
       
       private int offset            = no_of_registers;
       private int fid               = 0;
       int retries                   = 0;
       
       public ReadsWrites(BlockingQueue q, Handler handle, int serial_port, int rrefresh) {
          wrqueue  = q;
          hd       = handle;
          fid      = serial_port;
          reads_rr = rrefresh;
       }
       
       @Override
       public void run() {
          do{
             
             int[] holdingRegs;
             
             //registers that stores the read values
             holdingRegs       = new int[15];
             
             long bytes_received1    = 0;
    
             try {
                
                synchronized (wrqueue) {
                
                   if (!wrqueue.isEmpty()){
                      //extract Modbus Presets Registers from queue
                      WriteRequest wr = wrqueue.poll();
                      
                      //wr will be not null because isEmpty is false
                      
                      //use the preset parameters from wr object
                      node_to_write     = wr.getNode_id();
                      starting_address  = wr.getAddress();
                      no_of_registers   = wr.getRegs();
                      holdingRegs       = wr.getHoldingRegs();
                      
                      do{
                      if (bytes_received1 <= 0){
                         bytes_received1 = ModbusLib.PresetMultipleRegisters(
                            fid, 
                            node_to_write, 
                            starting_address, 
                            no_of_registers, 
                            holdingRegs);
                      }
                      retries++;
                      
                      }while (retries <= max_retries);
                      
                   }else{
                      
                      node_to_write       = 1;
                      starting_address    = 0;
                      no_of_registers    = 10;
                      
                      do{
                         //Modbus Reads                     
                         bytes_received2 = ModbusLib.ReadHoldingRegisters(
                           fid,
                           node_to_write,
                           starting_address,
                           no_of_registers, 
                           holdingRegs);                
                         
                           if (bytes_received2 >= 7){
    
                              Message msg = hd.obtainMessage();
                              msg.what = 1;
                              msg.arg1 = holdingRegs[0];
                              msg.arg2 = holdingRegs[1];
                            
                              hd.sendMessage(msg);
                           }
                         retries++;
                         
                      }while (retries <= max_retries);
                   }
                }
                
                Thread.sleep(reads_rr);
                
             } catch (InterruptedException e) {
                Log.d("Modbus_THREAD_", "wake up!");
             }
          }while(true);
          
       }
    
    }

    In this demo project, two values only are sent back to the main UI thread. If you need to exchange more than few values, please take a look at our blog post in which Android bundle is used to figure out this issue.

    The design we presented in this overview helps you to lay out the architecture of your Android application. It is quite general so can be adopted in many situations and by many professional and home users of our Android touch panels and development boards. We strongly suggest to starting with it and extending as your needs.

    We tested this library with many devices such as PLCs, AC Drives, Arduinos and actuators. It might happen that, mostly in cases when the refresh frequency is high, not all the requests can be executed correctly. This issue is caused by slave devices connected on the bus that are slow in aswering. This issue is simple to figure out: just tune the reply delay of your PLC or actuator as low as possible, that's it.
    This Java snippets we presented above do not manage the modbus errors that might happen. We omit these parts for the purpose of clarity. We strongly suggest to manage these situations in order to create successful and fault tolerant Android applications.