Problems with small packet transfers with WiFi TCP connection
Posted: Tue Dec 31, 2024 1:39 pm
Hi, I'm having problems with very slow transaction turnaround when using an ESP32 Dev module to communication with some hardware using modbus over TCP. I use the Arduino framework in platformio/VSCode
To simplify everything for the purpose of this post, I created two simple projects:
Both use an ESP32 Dev module, with one as the client, and one as the server to simulate the real device.
The client opens a connection, then writes a small packet of data and waits for the response. It repeats that 10 times and then closes the connection.
The server waits for a connection and then just echos back any packets that it receives.
The problem is that the time for each of the 10 transactions takes too long. In my real application I have to poll 10 registers from the device every 5 seconds, but it takes longer than that to complete each block of registers.
Below is a sample of the serial monitor output from the client. The number in brackets at the end of each line is the number of milliseconds it took between issuing the request and receiving the response:
The strange thing is, the delays seem to be quantum like. i.e. it's either 3000, 600 or ~14. (maybe that is a clue to the problem?).
The last few (10-20 ms) are fine, but it is very rare that I get that.
I have tried using setNoDelay() and flush() hoping that would fix it but seems to make no difference.
Am I doing something wrong? Or is there a different approach I should take?
I've run out of ideas and hope someone can help me or suggest a solution.
Below is my the test code:
To simplify everything for the purpose of this post, I created two simple projects:
Both use an ESP32 Dev module, with one as the client, and one as the server to simulate the real device.
The client opens a connection, then writes a small packet of data and waits for the response. It repeats that 10 times and then closes the connection.
The server waits for a connection and then just echos back any packets that it receives.
The problem is that the time for each of the 10 transactions takes too long. In my real application I have to poll 10 registers from the device every 5 seconds, but it takes longer than that to complete each block of registers.
Below is a sample of the serial monitor output from the client. The number in brackets at the end of each line is the number of milliseconds it took between issuing the request and receiving the response:
Code: Select all
Connection Open.
Recv: 00 01 00 00 00 06 01 04 13 87 00 00 ( 612 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 01 ( 3083 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 02 ( 603 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 03 ( 614 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 04 ( 717 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 05 ( 518 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 06 ( 607 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 07 ( 614 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 08 ( 615 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 09 ( 614 )
Connection closed.
Connection Open.
Recv: 00 01 00 00 00 06 01 04 13 87 00 00 ( 613 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 01 ( 614 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 02 ( 60 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 03 ( 10 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 04 ( 12 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 05 ( 10 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 06 ( 14 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 07 ( 18 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 08 ( 11 )
Recv: 00 01 00 00 00 06 01 04 13 87 00 09 ( 15 )
Connection closed.
The last few (10-20 ms) are fine, but it is very rare that I get that.
I have tried using setNoDelay() and flush() hoping that would fix it but seems to make no difference.
Am I doing something wrong? Or is there a different approach I should take?
I've run out of ideas and hope someone can help me or suggest a solution.
Below is my the test code:
Code: Select all
// Server Test
#include <Arduino.h>
#include <WiFi.h>
const char *ssid = "mySSID";
const char *password = "MyPassword";
WiFiServer server(502);
#define LED_RED 5
#define LED_GRN 4
#define G_BUFFER_SIZE 1024
uint8_t gRxBuff[ G_BUFFER_SIZE ];
uint16_t gRxBuffSize;
//------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
pinMode( LED_RED, OUTPUT); // set the LED pin mode
pinMode( LED_GRN, OUTPUT); // set the LED pin mode
digitalWrite( LED_RED, HIGH ); // off
digitalWrite( LED_GRN, HIGH ); // off
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Looking for Wifi..");
WiFi.begin( ssid, password );
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
digitalWrite( LED_GRN, false );
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
//------------------------------------------------------------------------------
void loop()
{
WiFiClient client = server.accept(); // listen for incoming clients
if (client) // if you get a client,
{
client.setNoDelay(true);
digitalWrite( LED_RED, LOW ); // ON
Serial.println("New Client."); // print a message out the serial port
gRxBuffSize = 0;
while (client.connected()) // loop while the client's connected
{
while ( client.available() && gRxBuffSize < ( G_BUFFER_SIZE -1 ) )
{
gRxBuff[ gRxBuffSize++ ] = client.read();
}
if ( gRxBuffSize != 0 )
{
client.write( gRxBuff, gRxBuffSize );
client.flush();
}
gRxBuffSize = 0;
}
// close the connection:
client.stop();
Serial.println("Client Disconnected.");
digitalWrite( LED_RED, HIGH ); // OFF
}
}
Code: Select all
// Client Test
#include <Arduino.h>
#include <WiFi.h>
const char *ssid = "MySSID";
const char *password = "MyPassword";
const char *Host = "192.168.2.21"; // IP of server
const int Port = 502;
uint32_t TimeStamp;
char TxBuff[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x01, 0x04, 0x13, 0x87, 0x00, 0x01 };
#define TX_SIZE (sizeof(TxBuff))
//------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
while (!Serial)
{
delay(100);
}
delay(3000); //Give time for serial monitor to start up again after upload
Serial.println("Starting...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
//------------------------------------------------------------------------------
void GetResponse(WiFiClient *client)
{
unsigned long timeout = millis();
while (client->available() == 0)
{
if (millis() - timeout > 5000)
{
Serial.println(">>> Client Timeout !");
client->stop();
return;
}
}
char ch;
Serial.print("Recv: ");
while (client->available())
{
ch = client->read();
Serial.printf( "%02X ", ch);
}
Serial.printf( " ( %d )\r\n", millis() - TimeStamp );
}
//------------------------------------------------------------------------------
void loop()
{
if ( !digitalRead(0) ) // button pressed?
{
WiFiClient client;
if ( client.connect(Host, Port) )
{
Serial.println("Connection Open.");
client.setNoDelay(true);
for( uint8_t i = 0; i < 10; i++ )
{
TxBuff[TX_SIZE-1] = i;
TimeStamp = millis();
client.write( TxBuff, TX_SIZE );
client.flush();
GetResponse(&client);
}
client.stop();
Serial.println("Connection closed.");
}
else
{
Serial.println("Connection fail.");
return;
}
delay(500); // for button debounce
}
}