Hi, I've spent many hours now setting up the tests and investigating different settings. Note: this code doesn't do anything with the incoming data, just counts the bytes.
The good news is that with 'well matched' settings the pipe/stream will flow all the way from the ipdHandler to the req.on('data',... in your own code. More on what 'well matched' means later.
The bad news is that under default settings (i.e. 115200 baud usart to ESP8266 and a 64 byte CHUNK size in socketserver.c) the netCallbacks.recv never gets the chance to get going: the ipdHandler (or more likely the ser.on("data",... in AT.js) dominates and buffers all the incoming serial data from the ESP8266 into sockData[sckt] before the netCallbacks.recv gets going. The memory pressure doubles (more or less) on the following calls to netCallbacks.recv as it tries to remove a 64 byte chunk from the beginning of sockData[sckt]
if (sockData[sckt]) {
/** INSTRUMENTED =>**/ var len = sockData[sckt].length;
var r;
if (sockData[sckt].length > maxLen) {
r = sockData[sckt].substr(0,maxLen);
sockData[sckt] = sockData[sckt].substr(maxLen);
} else {
that second .substr(...) is the culprit as it makes a copy of the whole buffer (less 64 (maxlen) bytes).
On a pico running only the attached code, the maximum http message body (file upload) is just a bit less than 20K before an out-of-memory error occurs. I've attached a log generated from my instrumented copy of ESP8266WIFI_0v25 (also attached) where you can see that netCallbacks.recv only gets invoked once or twice by the time ipdHandler has buffered the whole http message.
If you play around with dropping the baud rate down to say 9600 you can see that while the serial data is arriving, netCallbacks.recv gets invoked only every ~500ms.
So what are some 'well matched' settings?
Well I'd been playing around with compiling my own build of Espruino just to play around with the CHUNK size in socketserver.c.
So as an example: a CHUNK size of 1460 matched with a baudrate of 19200 gets the stream flowing nicely (actually I can bring the baudrate upto 24000 with this chunk size) and the maximum size of the sockData[sckt] never gets much larger than the CHUNK size. This isn't exactly a fantastic baudrate, but I can stream in a file of any size (tested upto 300K, but saw that the buffer always stayed small), although I'm just counting the bytes and nothing more 'busy'.
So what next?
flow control isn't an option as the ESP8266 only does hardware flow control with AT firmware, and the USART2 on the Pico doesn't support hardware flow control
using a bigger CHUNK size and a low baudrate might be an option, memory permitting for a given project
rewriting the ESP8266WIFI_0v25 module in native code in Espruino for better memory efficiency (one and only one copy of the data until it is consumed?) and optimising the balance between receiving serial data and scheduling javaScript execution
if this isn't an option and we have to acknowledge the maximum buffer size that can be achieved with sockData then the memory pressure can be managed by using an index into the buffer for the start of the next chunk, and only removing delivered chunks when the buffer is at least half consumed(?)
Espruino is a JavaScript interpreter for low-power Microcontrollers. This site is both a support community for Espruino and a place to share what you are working on.
Hi, I've spent many hours now setting up the tests and investigating different settings. Note: this code doesn't do anything with the incoming data, just counts the bytes.
The good news is that with 'well matched' settings the pipe/stream will flow all the way from the
ipdHandler
to thereq.on('data',...
in your own code. More on what 'well matched' means later.The bad news is that under default settings (i.e. 115200 baud usart to ESP8266 and a 64 byte
CHUNK
size insocketserver.c
) thenetCallbacks.recv
never gets the chance to get going: theipdHandler
(or more likely theser.on("data",...
inAT.js
) dominates and buffers all the incoming serial data from the ESP8266 intosockData[sckt]
before thenetCallbacks.recv
gets going. The memory pressure doubles (more or less) on the following calls tonetCallbacks.recv
as it tries to remove a 64 byte chunk from the beginning ofsockData[sckt]
that second
.substr(...)
is the culprit as it makes a copy of the whole buffer (less 64 (maxlen) bytes).On a pico running only the attached code, the maximum http message body (file upload) is just a bit less than 20K before an out-of-memory error occurs. I've attached a log generated from my instrumented copy of ESP8266WIFI_0v25 (also attached) where you can see that
netCallbacks.recv
only gets invoked once or twice by the timeipdHandler
has buffered the whole http message.If you play around with dropping the baud rate down to say
9600
you can see that while the serial data is arriving,netCallbacks.recv
gets invoked only every ~500ms.So what are some 'well matched' settings?
Well I'd been playing around with compiling my own build of
Espruino
just to play around with theCHUNK
size insocketserver.c
.So as an example: a
CHUNK
size of 1460 matched with a baudrate of 19200 gets the stream flowing nicely (actually I can bring the baudrate upto 24000 with this chunk size) and the maximum size of thesockData[sckt]
never gets much larger than theCHUNK
size. This isn't exactly a fantastic baudrate, but I can stream in a file of any size (tested upto 300K, but saw that the buffer always stayed small), although I'm just counting the bytes and nothing more 'busy'.So what next?
sockData
then the memory pressure can be managed by using an index into the buffer for the start of the next chunk, and only removing delivered chunks when the buffer is at least half consumed(?)3 Attachments