|
My project (as an option) emulates a serial port over WiFi, which works Ok mostly. But sometimes a WiFi packet is lost and requires a resend, this introduces quite a large delay and the legacy software being used thinks the serial port has garbled the data and requests a resend... Now, being TCP/IP, it eventually does a resend itself and the data-stream is uncorrupted - but the resend request due to the timeout then has a 2nd packet come in with the same data again... There's not really a way to fix the legacy software to skip it since it's a reasonable thing to happen in some modes, and at least without a fairly big re-write (since my project is a bit of an emulation platform, it's not something anyone would want to do also). Even so, I have changed the software's timeout value (it's quite large now, in the order of seconds) which has mostly fixed the issue I'm seeing. Sometimes, however, the WiFi in my area is really busy and I still get a resend request (TCP/IP may have internally done a few retry attempts itself, but all were lost). I'm sort of at my limit on what I'm prepared to do on the legacy side... So, my question is, is there something I can change easily to make the stack retry more often within the second or two I now have available? Thanks for any ideas anyone has. |
Replies: 3 comments 3 replies
|
(I forgot to mention, it's entirely possible the PC side connection also has the same issue sending data to the Pico, but I guess this is a case of one thing at a time and the Pico might be easier to change first.) |
|
This isn't really wifi related so much as LWIP and the TCPIP stack. Try disabling Nagle setDefaultNoDelay(true) before any connections: arduino-pico/libraries/WiFi/src/WiFiClient.h Lines 123 to 130 in da88e3c You might look at some of the internal LWIP TCP_ timers or MSS, but those need a recompile of the libpico blob. The LWIP upstream docs list all these but do require some low level knowledge of TCPIP. Alternatively UDP might be better than TCP but needs an app rewrite if the current value you're sending is more important than getting every report. |
|
Thanks for the tip. I'm actually relying on Nagle to collect characters one by one (how the emulation works) and when there's a 10ms delay after the last character is buffered - I flush(). Anyway, I've come up with this (it compiles - but it's not tested): /* Edit library header WiFiClient.h so _client is moved from protected into public
ClientContext* _client;
protected:
*/
#include <lwip/tcp.h> // We need the structure for tcp_pcb
#include <include/ClientContext.h> // We need the class for getPCB()
static void boostwfc () { // This may need to be called often to reset the two values over time
tcp_pcb* pcb = wfc._client->getPCB(); // rto and sv = LWIP_TCP_RTO_TIME / TCP_SLOW_INTERVAL
pcb->sv = 2; // TCP_SLOW_INTERVAL is (2 * TCP_TMR_INTERVAL) [TCP_TMR_INTERVAL = 250]
pcb->rto = 2; // LWIP_TCP_RTO_TIME is [3 seconds] 3000 / (2 * 250) = 6
}I'll see how it works later tonight. It does show a resend isn't done for 3 seconds though, the comment in the options header says this can be made 1 second for high performance networks - which I believe is what my hack does. EDIT: Swapped the order of the #include files |
Thanks for the tip. I'm actually relying on Nagle to collect characters one by one (how the emulation works) and when there's a 10ms delay after the last character is buffered - I flush(). Anyway, I've come up with this (it compiles - but it's not tested):