ESP32 does not send more than 2048 bytes correctly
xennex22 opened this issue · comments
There is a problem sending more than 2048 bytes via TCP in ARM_WIFI_SocketSendTo
The logic to break the transmit data into chunks of 2048 bytes or less does not decrement to original data size.
There's a loop to send to data to the ESP32
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Lines 3363 to 3366 in 5207888
But nowhere does len
get decremented. The inner loop counters do get decremented/incremented.
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Lines 3427 to 3428 in 5207888
So if I transmit 2050 bytes rather then sending 2048 bytes then 2 bytes the function just keeps trying to send 2048 bytes until eventually it fails.
The return value from ARM_WIFI_SocketSendTo
has a problem too, as it checks if the last chunk size (max 2048) is equal to the total tx size (may be over 2048)
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Lines 3444 to 3446 in 5207888
And this is done in the inner of two loops, so as soon as one chunk is tx then the rval is set, which exists the outer loop, which then compares the total tx with the rval and fails.
Hi,
implementation is a bit confusing due to its complexity, but what happens in line
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Line 3364 in 5207888
is only a check when application called the driver with len argument equal to zero. According to ARM_WIFI_SocketSendTo documentation this is allowed to check (pool) if the socket is ready to send data.
Since ESP32 can only send 2048 bytes with a single AT+CIPSEND command, initial count is limited to 2048 bytes:
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Lines 3367 to 3375 in 5207888
which are then loaded into ESP32 internal buffer:
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Lines 3399 to 3401 in 5207888
and the total number of byte transferred is incremented while loading buffer:
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Line 3427 in 5207888
When the transfer is done and "SEND OK" is received from ESP32, the number of total bytes sent is checked:
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Lines 3444 to 3446 in 5207888
If this check is not true, the whole process will be repeated. Any additional number of bytes left from 2048 is then sent with next AT+CIPSEND command.
If you can understand my pseudocode:
len = the total number of bytes to transmit
num = 0
while(len > 0) {
cnt = the minimum of 2048 and the len
send 'AT+CIPSEND' + cnt
wait for 'OK'
while (cnt != 0) {
n = minimum of data to send and AT buffer size
n = number of bytes sent
num += n
cnt -= n
}
wait for 'SEND OK'
return number of bytes sent if (num == len)
}
So if we hand simulate with len = 2050
initialize:
len = 2050
num = 0
loop 1:
cnt = 2048
n = 2048
num = 2048
cnt = 0
*** len is unchanged at 2050 ***
loop 2:
cnt = 2048 *** not 2 since len is never decremented ***
n = 2048 *** buffer overflow ***
num = 4096
cnt = 0
num != len so we loop forever
...
You are absolutely right! Many thanks for insisting and providing additional explanation! For some reason I just didn't see it...
I'll fix that.
My fix:
uint32_t tx_size = len;
...
if (cnt > tx_size) { cnt = tx_size; }
...
tx_size -= n;
The check within the loop was modified to
CMSIS-Driver/WiFi/ESP32/WiFi_ESP32.c
Lines 3321 to 3323 in 7f340e0
It should do the job.
I've confirmed the fix works for me.