emelianov / modbus-esp8266

Most complete Modbus library for Arduino. A library that allows your Arduino board to communicate via Modbus protocol, acting as a master, slave or both. Supports network transport (Modbus TCP) and Serial line/RS-485 (Modbus RTU). Supports Modbus TCP Security for ESP8266/ESP32.
Other
497 stars 182 forks source link

E4 timeout error - RTU master to TCP bridge #330

Closed profi-max closed 5 months ago

profi-max commented 5 months ago

Thanks to the author for the library. But I had a problem when repeating the example. Periodically an E4 error occurs. Please help. I use ArduinoIDE + ESP8266 Modbus RTU as master at SoftwareSerial <-bridge-> TCP server The code below works, but very often an error occurs E4 (timeout raises function cbRtuTrans()) , after which the work completely stops.

/*
  ModbusRTU ESP8266/ESP32
  ModbusTCP to ModbusRTU bridge with on-device ModbusRTU simulator
*/
#ifdef ESP8266
 #include <ESP8266WiFi.h>
#else //ESP32
 #include <WiFi.h>
#endif
#include <ModbusTCP.h>
#include <ModbusRTU.h>
#include <SoftwareSerial.h>
SoftwareSerial S;
#include <StreamBuf.h>

ModbusRTU rtu;
ModbusTCP tcp;
IPAddress srcIp;
uint16_t transRunning = 0;  // Currently executed ModbusTCP transaction
uint8_t slaveRunning = 0;   // Current request slave

bool cbTcpTrans(Modbus::ResultCode event, uint16_t transactionId, void* data) { // Modbus Transaction callback
  if (event != Modbus::EX_SUCCESS)                  // If transaction got an error
    Serial.printf("Modbus TCP result: %02X, Mem: %d\n", event, ESP.getFreeHeap());  // Display Modbus error code (222527)
  if (event == Modbus::EX_TIMEOUT) {    // If Transaction timeout took place
    tcp.disconnect(tcp.eventSource());          // Close connection
    transRunning = 0;
    slaveRunning = 0;
  }
  return true;
}

bool cbRtuTrans(Modbus::ResultCode event, uint16_t transactionId, void* data) {
    if (event != Modbus::EX_SUCCESS)                  // If transaction got an error
      Serial.printf("Modbus RTU result: %02X, Mem: %d\n", event, ESP.getFreeHeap());  // Display Modbus error code (222527)
    return true;
}

// Callback receives raw data 
Modbus::ResultCode cbTcpRaw(uint8_t* data, uint8_t len, void* custom) {
  auto src = (Modbus::frame_arg_t*) custom;

  Serial.print("TCP IP in - ");
  Serial.print(IPAddress(src->ipaddr));
  Serial.printf(" Fn: %02X, len: %d \n\r", data[0], len);

  if (transRunning) { // Note that we can't process new requests from TCP-side while waiting for responce from RTU-side.
    tcp.setTransactionId(src->transactionId); // Set transaction id as per incoming request
    tcp.errorResponce(IPAddress(src->ipaddr), (Modbus::FunctionCode)data[0], Modbus::EX_SLAVE_DEVICE_BUSY);
    return Modbus::EX_SLAVE_DEVICE_BUSY;
  }

  rtu.rawRequest(src->unitId, data, len, cbRtuTrans);

  if (!src->unitId) { // If broadcast request (no responce from slave is expected)
    tcp.setTransactionId(src->transactionId); // Set transaction id as per incoming request
    tcp.errorResponce(IPAddress(src->ipaddr), (Modbus::FunctionCode)data[0], Modbus::EX_ACKNOWLEDGE);

    transRunning = 0;
    slaveRunning = 0;
    return Modbus::EX_ACKNOWLEDGE;
  }

  srcIp = IPAddress(src->ipaddr);
  slaveRunning = src->unitId;
  transRunning = src->transactionId;
   return Modbus::EX_SUCCESS;  
}

// Callback receives raw data from ModbusTCP and sends it on behalf of slave (slaveRunning) to master
Modbus::ResultCode cbRtuRaw(uint8_t* data, uint8_t len, void* custom) {
  auto src = (Modbus::frame_arg_t*) custom;
  if (!transRunning) // Unexpected incoming data
      return Modbus::EX_PASSTHROUGH;
  tcp.setTransactionId(transRunning); // Set transaction id as per incoming request
  uint16_t succeed = tcp.rawResponce(srcIp, data, len, slaveRunning);
  if (!succeed){
    Serial.print("TCP IP out - failed");
  }
  Serial.printf("RTU Slave: %d, Fn: %02X, len: %d, ", src->slaveId, data[0], len);
  Serial.print("Response TCP IP: ");
  Serial.println(srcIp);

  transRunning = 0;
  slaveRunning = 0;
  return Modbus::EX_PASSTHROUGH;
}

void setup() {
  S.begin(115200, SWSERIAL_8N1, 13, 15);
  Serial.begin(115000);
  WiFi.begin("Zyxel2", "mypass12345");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  tcp.server(); // Initialize ModbusTCP to pracess as server
  tcp.onRaw(cbTcpRaw); // Assign raw data processing callback

  rtu.begin(&S);  
  rtu.master(); // Initialize ModbusRTU as master
  rtu.onRaw(cbRtuRaw); // Assign raw data processing callback
}

void loop() { 
  rtu.task();
  tcp.task();
  yield();
}

Terminal messagese:

RTU Slave: 1, Fn: 03, len: 22, Response TCP IP: 192.168.1.78
TCP IP in - 192.168.1.78 Fn: 03, len: 5
RTU Slave: 1, Fn: 03, len: 22, Response TCP IP: 192.168.1.78
TCP IP in - 192.168.1.78 Fn: 03, len: 5
RTU Slave: 1, Fn: 03, len: 22, Response TCP IP: 192.168.1.78
TCP IP in - 192.168.1.78 Fn: 03, len: 5 
Modbus RTU result: E4, Mem: 46600
TCP IP in - 192.168.1.78 Fn: 03, len: 5 
TCP IP in - 192.168.1.78 Fn: 03, len: 5 

But if I change the code to be confident in equipment and RTU side, then the error never arises.

bool cbRead(Modbus::ResultCode event, uint16_t transactionId, void* data) {
  Serial.printf_P("Request Read result: 0x%02X, Mem: %d\n", event, ESP.getFreeHeap());
  return true;
}

void loop() { 
 static uint16_t buffer1[100];
  memset(buffer1, 0, 32);
  if (!rtu.slave()) 
    rtu.readHreg(1, 0, buffer1, 16, cbRead);
  rtu.task();
/////////  tcp.task();
  yield();
}

The trick like this didn't help me:

#ifdef MODBUSIP_MAX_READMS //if the macro MODBUSIP_MAX_READMS is defined 
#undef MODBUSIP_MAX_READMS//un-define it
#define MODBUSIP_MAX_READMS 300//redefine it with the new value
#endif 
profi-max commented 5 months ago

I transferred the project to the VSCode+Platformio to be able to change the library files. Unfortunately, E4 error remains. With defines:

#define MODBUSIP_DEBUG
#define MODBUSRTU_DEBUG
#define MODBUSRTU_MAX_READMS 300

Terminal messages:

TCP IP in - 192.168.1.78 Fn: 03, len: 5
3 0 0 0 A
3 14 1 F4 0 C8 A AB 5 5F F 8 D 98 0 1 0 B 0 0 0 0 A6 A6
RTU Slave: 1, Fn: 03, len: 22, Response TCP IP: 192.168.1.78
0: Bytes available 12
TCP IP in - 192.168.1.78 Fn: 03, len: 5
3 0 0 0 A
3 14 1 F4 0 C8 A AB 5 5F F 8 D 98 0 1 0 B 0 0 0 0 A6 A6
RTU Slave: 1, Fn: 03, len: 22, Response TCP IP: 192.168.1.78
0: Bytes available 12
TCP IP in - 192.168.1.78 Fn: 03, len: 5
3 0 0 0 A
3 14 1 F4 0 C8 A D5 5 67 E AB D 98 0 1 0 B 0 0 0 0 F6 BB
RTU Slave: 1, Fn: 03, len: 22, Response TCP IP: 192.168.1.78
0: Bytes available 12
TCP IP in - 192.168.1.78 Fn: 03, len: 5
3 0 0 0 A
3 14 1 F4 0 C8 A D5 5 67 E AB D 98 0 1 0 B 0 0 0 7D F7 
Modbus RTU result: E4, Mem: 47072
0: Bytes available 12
TCP IP in - 192.168.1.78 Fn: 03, len: 5
0: Bytes available 12
TCP IP in - 192.168.1.78 Fn: 03, len: 5
profi-max commented 5 months ago

Unfortunately, the problem did not solve.