Menu

modbus/TCP: sometimes trans.getResponse() == null ?!

2016-03-21
2016-03-24
  • Patrick Legrand

    Patrick Legrand - 2016-03-21

    Dear all

    I'm trying to interact with an ABB 595 over modbus/tcp.
    It basically works fine, but under some load I sometimes get a 'null' object back. This happens after a couple of hunderd to thousand loops.
    in these cases the connection remains connected and the null object comes after the request almost imediately back (definately not a after the timeout). The network is stable, ping-response-time is short and does not change much (no relationship to the 'null' objects)

    In my understanding I should get either a valid object - or an exception back...?

    public class Plc {
    
      static TCPMasterConnection con = null; //the connection
    
      public synchronized static ModbusResponse modbus(ModbusRequest req) throws Exception {
        ModbusResponse res=null;
    
        // connect to PLC if never done so far
        if (con==null) {
          con = new TCPMasterConnection(InetAddress.getByName("10.0.0.221"));
          con.setPort(Modbus.DEFAULT_PORT);
          con.connect();     // would automatically happen
          con.setTimeout(1000);
        }
    
        // Prepare the transaction
        ModbusTCPTransaction trans = new ModbusTCPTransaction(con);        //the Modbus transaction
        trans.setRequest(req);
        trans.setRetries(10);
    
        trans.setCheckingValidity(true); // ???
        // trans.setReconnecting(true); // ???
    
        // execute the transaction
        trans.execute();
    
        // get the response
        res =  trans.getResponse();
        System.out.println("...read "+ (res==null ? "NULL!?" :  res.getHexMessage()));
        return res; // this is _sometimes_ null...
      } // modbus
    

    I'm calling that from several small methods to get the desired datatype:

    public static int readRegister(int startReg) throws Exception {
      ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(startReg, 1);
      ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse)modbus(req);
      return res.getRegister(0).getValue();
    }          
    

    single calls work perfectly. I found the problem by 'torturing' it:

      public static void main(String[] args) {
        final int reg = 0;
        final int loopRegStart = 0;
        final int loopRegEnd = loopRegStart + 10000;
        int r=0;
        try {
          for (int i=loopRegStart; i<(loopRegEnd); i++) {
            r = readRegister(i); 
            if (r!=0) System.out.println(i + " = "+r);  
          };
    
          con.close();
          } catch (Exception ex) { ex.printStackTrace();  }
        }//main
    

    the null-object may be returned in the first iterations or after some thousand calls....

    Is this a lack of my understanding, the PLC or the library...?
    Any hint is much appreciated!

     
  • Patrick Legrand

    Patrick Legrand - 2016-03-21

    Retried with a different (simplistic) approach:

    public static void testSimple() throws Exception {
        Register[] r;
        int v=0, i=0;
    
        ModbusTCPMaster modbus = new ModbusTCPMaster("10.0.0.221");
        modbus.connect();
    
        while (i<100000) {
          try {
            r=modbus.readMultipleRegisters(i, 1);
            v=r[0].getValue();
            if (v!=0) System.out.println(i+" = "+v);
            i++;
          } catch(Exception e) { System.out.println("ERROR at pos "+i+": "+e.getMessage()+". Retry!"); modbus.disconnect(); modbus.connect(); }
        } // while
    
    }; // testSimple
    

    this way the code runs thru - even over a high latency vpn.
    hence I can work around the problem. But I still fail to understand how it's possible to ever get 'null' back - I'd expect a valid object or an exception...?

     
  • Julie Haugh

    Julie Haugh - 2016-03-22

    It's hard to tell from the code what may be happening, but I'll answer the question about exceptions -- you may not receive an exception on a timeout or when you receive a malformed packet. The main loop in the execute() method will retry however many times the retries are set for. If they all fail, without some lower level exception occuring, you get back a null and that's normal.

    What can you tell me about the version you're running and anything else. There was a recent change to stop sending a byte of urgent data to verify a connection was still valid. Some Modbus/TCP slaves seem to respond poorly to that.

     
    • Patrick Legrand

      Patrick Legrand - 2016-03-23

      latest code (source) from sourceforge (February 14th).
      Beeing in the same network segment I don't get any problem. 2 routers later once in 50'000 requests and over a vpn and high latency about once every 10'000 requests.
      Doing a disconnect/reconnect and repeat the request seems to recover in 100% of the cases.
      Since the problem happens seldom, I'm able to recognize/catch it and you name it '...and that's normal' I'll think that I'll simply work around it.

       
    • Patrick Legrand

      Patrick Legrand - 2016-03-24

      I thought one more time about "without some lower level exception occuring, you get back a null and that's normal".

      I feel an 'execute'-like function should either return a return-code (e.g. C-style int) or throw an exception (java-style): trying to read a value and not getting a valid object is clearly an error-condition which requires particular treatment.
      The way I understand the code now it either throws an exception or returns 'null' if a problem occurs - and we have to check for both conditions to make sure the result is valid.

      I propose the following change to ModbusTCPTransaction.execute:
      check for null response and treat it as any other exception: repeat the request retryLimit times and if it is still 'null' throw the same ModbusIOException

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.