Aaron0127 (Customer) asked a question.

Modbus TCP connection refused

Hi all,

 

I have an application which read digital inputs, high speed counter inputs and digital and analog outputs every 25ms using libmodbus library on a Linux OS PC. I’m using ClICK PLC koyo model. I’m using modbus PLC protocol and set timeout as server to be 1s.

For example,

  1. result = modbus_read_bits(mb, di_io_map[0].reg_addr, 7, di_values);
  2.  
  3. result = modbus_read_registers(mb, ai_io_map[0].reg_addr, 2, ai_value);

 

I make connection this way:

 

  1. mb = modbus_new_tcp("192.168.1.77", 502);
  2. int s = modbus_tcp_listen(mb, 1);
  3. modbus_tcp_accept(mb, &s);
  4.  
  5. if (modbus_connect(mb) == -1)
  6. {
  7. LOG_ERROR("Connection failed: %s", modbus_strerror(errno));
  8. }

I’m able to read and write data to the PLC. But after some time, usually about 1 hour or 2 hours, the PLC lost connection. I can see the PLC LEDs are still on. Error message printed on terminal using API modbus_strerror(errno) is “Connection refused”.

 

My application tries to reconnect to PLC every 3s with same code above. But still, the PLC refused the connection request.

 

I use my windows laptop to connect to it and got time out message.

 

For once, I did leave my application run long enough, after 10 minutes 30 seconds of rejecting connection, PLC allows connection.

In addition, if I power off the PLC and power it on again, it accepts connection request straight away.

I don’t know the cause of this issue. Could it be a pending port number issue?

 


  • ADC TechnologyGroup_01 (AutomationDirect)

    Looks like you might be using "libmodbus" ? Can you provide a complete code example of your test which reproduces the issue? The CLICK can support 3 connections from Clients. If your code does not gracefully close these TCP connections they will be left half-open and must timeout. The status of CLICK System Bit SC92 "_Port_1_Connection_Limit" would indicate this situation. A wireshark capture would also be helpful.

    • Aaron0127 (Customer)

      Hi, thank you for reply.

      Yes, I'm using libmodbus library.

       

      I wrote a simplified version of our PLC code,

      1. modbus_t *mb;
      2.  
      3. static void PlcThreadFunction(void* object)
      4. {
      5. pthread* th = (pthread*)object;
      6. bool comm_error = false;
      7. while (PLC::operation.active)
      8. {
      9. if(!comm_error)
      10. {
      11. result = modbus_read_bits(mb, di_io_map[0].reg_addr, 7, di_values);
      12. if (result == -1) comm_error = true;
      13.  
      14. result = modbus_write_bits(mb, do_io_map[0].reg_addr, 6, do_values);
      15. ai_value_f = modbus_get_float_abcd(ai_value);
      16. if (result == -1) comm_error = true;
      17.  
      18. result = modbus_read_registers(mb, ai_io_map[0].reg_addr, 2, ai_value);
      19. if (result == -1) comm_error = true;
      20.  
      21. result = modbus_read_registers(mb, co_io_map[index].reg_addr, 2, ci_value);
      22. counted_pulses = modbus_get_float_abcd(ci_value);
      23. if (result == -1) comm_error = true;
      24.  
      25. modbus_set_float_badc((float)value, ao_value);
      26. result = modbus_write_register(mb, ao_io_map[i].reg_addr, *ao_value);
      27. if (result == -1) comm_error = true;
      28.  
      29. if (comm_error)
      30. {
      31. modbus_close(mb);
      32. modbus_free(mb);
      33. }
      34. }
      35. else
      36. {
      37. mb = modbus_new_tcp("192.168.1.77", 502);
      38. int s = modbus_tcp_listen(mb, 1);
      39. modbus_tcp_accept(mb, &s);
      40.  
      41. if (modbus_connect(mb) == -1)
      42. {
      43. LOG_ERROR("PLC fail to reconnect");
      44. }
      45. else
      46. {
      47. LOG_ERROR("PLC reconnected!");
      48. comm_error = false;
      49. }
      50. }
      51.  
      52. if (!comm_error)
      53. {
      54. pthread->usleep(25000); // Every 25ms
      55. }
      56. else
      57. {
      58. pthread->sleep(5); // Every 5 s
      59. }
      60. }
      61. }
      62.  
      63.  
      64. static void InitialiseHardware()
      65. {
      66. while (!ok)
      67. {
      68. mb = modbus_new_tcp("192.168.1.77", 502);
      69. int s = modbus_tcp_listen(mb, 1);
      70. modbus_tcp_accept(mb, &s);
      71.  
      72. if (modbus_connect(mb) == -1)
      73. {
      74. LOG_ERROR("Connection failed: %s", modbus_strerror(errno));
      75. modbus_free(mb);
      76. ok = false;
      77. }
      78. else
      79. {
      80. ok = true;
      81. PLC::operation.active = true;
      82. }
      83.  
      84. }
      85. }
      86.  
      87. void StopPlc()
      88. {
      89. if (kdaq_thread)
      90. {
      91. while (kdaq_thread->Active())
      92. {
      93. usleep(50000);
      94. }
      95.  
      96. modbus_close(mb);
      97. modbus_free(mb);
      98.  
      99. delete kdaq_thread;
      100. kdaq_thread = NULL;
      101. }
      102. }

      StopPlc() is called, when the user closes the app, or user uses keyboard to signal the termination of the app, like "Ctrl + z" and "Ctrl + c".

      Expand Post
      • ADC TechnologyGroup_01 (AutomationDirect)

        Can you please also provide the exact CLICK CPU Part Number? Firmware version? Using Port1? Any expansion modules? What is the status of the System Bit (SC92) during your situation? Can you provide the Ladder project? Is the Ladder performing any communications instructions?

      • Aaron0127 (Customer)

        The CLICK PLC module is CLICK Koyo, C0-12DRE-2-D, C0-16CDD2. Firmware version is Ver3.41. Yes I'm using port 1, the Ethernet port. There is one expansion module, C0-16CDD2.

         

        I didn't read SC92 status bit. Is it necessary? Our ladder logic program does not provide any perform any communications instructions.

      • ADC TechnologyGroup_01 (AutomationDirect)

        Your usage of modbus_tcp_listen() and modbus_tcp_accept() look out of place. Those are used in the libmodbus Server examples: unit-test-server.c and random-test-server.c But the Client examples are arranged differently. Is there a purpose to create a separate listener on the same port?

         

        In the last Write appears to be a Float register, but you are using the Single Register Write. Floats are 32-bit, 2 Registers. So instead of modbus_write_register() you need to be using modbus_write_registers() and include the Length.

         

        A Wireshark capture of your normal state and also your error state would be helpful.

        1. if(!comm_error)
        2. {
        3. result = modbus_read_bits(mb, di_io_map[0].reg_addr, 7, di_values);
        4. if (result == -1) comm_error = true;
        5. result = modbus_write_bits(mb, do_io_map[0].reg_addr, 6, do_values);
        6. if (result == -1) comm_error = true;
        7. result = modbus_read_registers(mb, ai_io_map[0].reg_addr, 2, ai_value);
        8. ai_value_f = modbus_get_float_abcd(ai_value);
        9. if (result == -1) comm_error = true;
        10. result = modbus_read_registers(mb, co_io_map[index].reg_addr, 2, ci_value);
        11. counted_pulses = modbus_get_float_abcd(ci_value);
        12. if (result == -1) comm_error = true;
        13. modbus_set_float_badc((float)value, ao_value);
        14. result = modbus_write_registers(mb, ao_io_map[i].reg_addr,2, *ao_value);
        15. if (result == -1) comm_error = true;
        16. if (comm_error)
        17. {
        18. modbus_close(mb);
        19. modbus_free(mb);
        20. }
        21. }

         

        Expand Post