How to go about tracking down this error? #523
Replies: 25 comments
-
Posted at 2016-01-13 by @gfwilliams Can you post up your code? The error is in the ESP8266 library, but that's probably not at fault - there's just so little memory available that it can't allocate memory when it needs it, and it crashes. If you want to write to a file, I'd write it a bit at a time - each time you get new data, add it to the end. You might be able to use pipe... There's an example of transmitting a file on the Internet page:
You might just be able to reverse that to:
but I haven't tried it... |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-13 by DrAzzy Can you post the code that's doing it? Also - you're working with an Espruino board (or some other STM32 board running Espruino) connected to an ESP8266, right? (as opposed to running it on the ESP8266 itself - which is still a little rough, and is really tight on memory) |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-13 by @gfwilliams Actually I just dug this out of some personal code I had:
It works fine - the only problem is that you end up with the HTTP 'boundary' on the end of the file - so if you care about that then it probably makes sense to handle it with |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-13 by @gfwilliams And I just tweaked it:
So now it handles boundaries correctly, and allows multiple files to be uploaded in one go. ... I guess this should be a module of some kind? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-14 by Snerkle Thanks for all the thought provoking input. I'll try to summarise what I've learnt in the past 24 hours.
So there are plenty of places where you could run out of memory with this behaviour, basically because the code doesn't let you process and discard each incoming chunk of data as it arrives, but buffers it and then chunks it up after it is all buffered. Ideally the ESP8266WIFI_0v25 module and/or the AT module need to be redesigned to behave as a stream, and not just to emulate a stream by actually buffering everything and then chucking out from the buffer. I hope all this makes sense. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-14 by @gfwilliams Well, ideally the Network API would allow data to be 'pushed' into it. However I still think the problem is in the way you're using the HTTP code - we need to see your code. So the way Espruino works is:
So if Espruino isn't busy, it keeps going round the idle loop, emptying the buffers and everything is fine. However, if your code is taking too long to execute, Espruino doesn't go around the idle loop enough times, and data builds up in the buffers (probably To be honest I don't see how redesigning the ESP8266 network will help in this case. It'll mean that the data that comes in just gets pushed straight to your code, where it won't be handled fast enough and Espruino will still fail with out of memory, just in a different place. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-14 by Snerkle Ok, I'll post my code tomorrow when I get back to my computer. I'm not doing anything time consuming, I'm actually just buffering the data again for now until I solve this problem and can then work more like a pipe/stream. I take your last point and am inclined to agree. What I was expecting to see was each of the three bullet-pointed steps happen mostly sequentially for each incoming packet of data, so overall it's like a stream or pipe with only a little buffering to keep things moving. I'll also send the output from my instrumentation so you can see this happening. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-14 by @gfwilliams
Are you using a high baud rate, or is this still at 115200 baud? It looks to me like it starts as soon as data starts being received (so it doesn't have to have go to the end of an IPD packet). However it tries to be 'up to date' with the characters coming in from the UART before it moves on. It could be Espruino's handling of input data (rather than anything network-related) that's causing problems. For example it currently does:
But I imagine what could happen is if characters keep coming in, it calls javascript with something a bit like:
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-15 by Snerkle 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
that second If you play around with dropping the baud rate down to say So what are some 'well matched' settings? So what next?
Attachments: |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-15 by @gfwilliams Not sure I really understand this... so you have:
So it should be reporting back every single time it gets more data in? But it actually reports:
I'd have expected I think one solution would be to change the |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-15 by Snerkle OK I see your confusion: with the instrumentation in So if I understand you right: If I have this right, then P.S. the My other crazy plan, that I will ask a few question of @tve to qualify if it is worth the effort, is to to run Espruino on the ESP8266 which implements the SDK's flow control for TCP sockets |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-15 by @gfwilliams
I'm extremely surprised at that - if so then there's some very big, deep-seated problem. As I'd said above, the idle loop in Espruino will only process 128 items from the input queue (4 chars in each item, so 512 chars total) before carrying on - and then it will call into the socket handling code. So yes, it should run more often than once every 500ms, and the max stored data should be around 512 bytes. Honestly, I think running custom firmware on the ESP8266 is overkill :) This really should be pretty simple to fix. Of course if the ESP8266 firmware could implement flow control, that'd be pretty cool - but it really shouldn't be needed. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-15 by Snerkle I'll produce another log for you (attached), or you can try it for yourself: if you drop the baudrate in the test down to 9600, you'll see you get more
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-15 by @gfwilliams Just looking at this now - yes, there's something going wrong with the idle loop. While it counts events as it should, it's not counting when it can fire off a whole batch of events in a go. As a result it limits to 128 calls on I've just fixed that, but the limit of 64 bytes for a call to recv is still too few, so I'll make some changes to the network API too. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-15 by @gfwilliams I've pushed some code, so the latest GitHub builds will at least have the idle loop bug fixed, and have big enough buffers for HTTP/Sockets so that data gets drained quickly enough. However, now I increased the buffer sizes, I encountered an issue where |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-19 by @gfwilliams Ok, the HTTP server now only closes once Content-Length bytes have been received (as of the latest Git build) |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-19 by Snerkle OK, I've been doing a lot of testing in the meantime and found:
If I drop the baudrate of the ESP8266 usart down to 19200, I can make things work fairly reliably. But this speed isn't ideal for more than a proof-of-concept. The other thing I see happen (sometimes) is long (2 seconds plus) pauses that I assume are garbage collection. Sometimes the streaming of data survives this, sometimes it doesn't and again incoming serial packets from the ESP8266 to get dropped Is there a way to request the GC to pause and unpause upon request? My write speed to my SD card is effectively ~650000 bps so the file writing shouldn't be an issue for incoming data at 115200 bps, but something is blocking the serial interrupt and a few packets always get dropped at speeds over 19200 i.e. 38400 or higher. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-19 by @gfwilliams That's odd - GC is actually extremely quick (just a few milliseconds) so I doubt that's the issue. Since Serial and USB share the same input buffer, could it be that there's just a big flood of data, and the serial buffer gets so full it can't even accept characters from USB? Glad it's working with pipe anyway - since effectively 512 bytes get buffered, you've got ~44ms at 115200 baud in which to write the data out (in practice it's less though). How are you connecting the SD card? Is it possible that you could get a bit more out of it using hardware SPI with a higher baud rate. Having said that, hardware SPI uses interrupts to handle the received characters, and it's possible that those interrupts end up blocking the serial interrupts and you lose data. You could try with software SPI, which might be a tad slower but wouldn't use interrupts so might mean you don't end up losing data? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-20 by Snerkle OK, I've tried both hardware and software SPI and end up with the same problem: I've opened a new post to follow that issue separately, although I believe it is now the root cause of my problems with dropping incoming packets of serial data from the ESP8266. Meanwhile I'll let you know that the last binary/build that I can use is e54a6b982545da111b2f24d725fb30b0279c11da , anything after that has a regression error when trying to require a module
you'll notice that \xFF character on line 3 that isn't there, and I don't get this error with the build linked just above. I like where its heading with detecting the end of the body by comparing the bytes received with the Content-Length header. This is what I've been doing in my javaScript in the I'd like to propose a few things at this point:1. can the (new)
I would try and add it myself but I still haven't got my head around handling jsVars in the Espruino source code. This would remove the trouble of having to make a new build to try out different socket buffer sizes. 2. I propose it is a good opportunity to introduce the
The upshot of this approach is that the http server does not and should not have to issue a I've noticed a lot of the sample/tutorial code for an http server does this 'early' Gosh this post got long but I really hope to make this work on the Espruino so I can complete my larger project, which by the way is an attempt to implement a light-weight, modular express (V4) like http router for the Espruino to simplify building http server apps along with my first http server app which would be a web based UI to manage content on an attached SD storage card, including drag-and-drop file uploads - so you can see why reliably receiving long http request bodies is important to me. I've got everything else working quite well, its just receiving long request bodies that is still causing problems. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-20 by @allObjects I'm not sure about the purpose of ESP8266 standalone/combined with Espruino board to be fully fledged Web (app) servers... Yes, it is nice to have the http(s) protocol and then routing available to support modular application builds. MCs are usually used to 'just' gather some sensor's values and then transmit them in a lean way to the requester through a mediator, which complements the raw data with the shoe shine that is needed for a neat presentation. The transmitted document can be a complete html document but the 'UI-meat' comes from a third party - a UI resource server that provides the 'tons' of html(5 - html, css, js, any UI and other library/framework standard/custom code) to create a nice UI (and single page app) in the client / browser. I'd like to keep the distributed MCs that gather the sensor data as lean as possible with the least of dependencies and changes, and then 'fully load' a classical Web (app) server with all the resources - and with CORS - it is even possible to write the data on those readily equipped servers, or flip the roles completely: deliver everything but the IoT sensor data from a regular Web (app) server and make an CORS enabled ajax call to ESP8266/Espruino to get the data. There was a while ago this conversation about Shiny Web UI which was covering such subjects. @Snerkle, I don't have an exact understanding of all the requirements and constraints you are pursuing to satisfy, but as an MC I would be pretty overwhelmed... In the this post I show an approach to keep the html doc sent from the IoT device as slim as possible without sacrificing the consumer UI. In order to have it a standalone example that everyone can run just off the forum, I emulate the (temperature) sensor reading with this anonymous function in the setInterval() from lines 16 thru 23, which - when implemented - will make a slim ajax call (back) to the ESP8266/Espruino to just get the raw sensor data. The UI library/framework I'm using in the example is dojotoolkit.org pulled in from ajax.googleapis.com. Any other smart library or framework will do too. Nice about dojo is the AMD implementation: the code in line 4 pulls only a minimum: the loader / require.js which then allows to pull into (and cache in) the browser what else is needed, as beginning with line 7. The example the html body includes all UI layout... what makes it still a fatter 'file' then needed: putting the body content into an AMD module and load it from a regular Web (app) server - he same as one would put on the library/framework - allows even more a slimming down of what 'has to live in Espruino... which could the make an SD card obsolete... and all your related problems goners... |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-20 by @gfwilliams
I made some changes that should have generally increased speed/efficiency, but I tested them last night with a Pico and ESP8266 and they worked fine. And just tested them again, and they still work. Maybe it's the builds... I'll check.
Any reason? Looks like I left that debug print in by accident though - it's fixed now. Odd about the pipe ending - it's supposed to close when the close event is sent. That works when running a build on the PC, but it looks like on the Pico characters still get lost, and so the amount of data received doesn't equal content length. You could probably check that? If you run
I don't think that would help? When I looked at the data flowing through the system on my build it only seems to be pulling ~150 characters each time around the idle loop, far less than the 536 buffer size. I'm just against adding extra complexity that realistically will never be used, especially with code size being such an issue at the moment. If you want to try stuff out, it's really not that hard to build Espruino in a VM.
So in I could definitely change it to fire off an Timeouts are something else that needs looking at - there's nothing implemented there at the moment at all. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-20 by Snerkle Thanks for your interest @allObjects. The results so far have been very fruitful and the journey has enabled me to make a number of contributions to the Espruino project in the form of bug fixes, functional improvements and some enhancements that have been readily accepted and implemented. Making Espruino better for everyone, hopefully. So forgive me if I feel that you are suggesting I am trying to do something for which this MC isn't intended, because I disagree. Once I find its limits then I will know what use-cases I will choose this MC for, and for what use-cases I will need to choose something else. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-20 by Snerkle Thanks @gordon, I'll try it again with the next build you post up and see if the problems are gone. I agree with you on the buffer size, and have now observed the same thing myself. I have been doing my own build's in a VM using your guide. One extra step was required from memory because recent releases of Ubuntu omit a package now for VM installs which is where the USB serial device mapping magic happens, I think the package is I will look at how node behaves at Its a shame about the SD file writing occasionally blocking the incoming serial coms. I'd really hoped to come up with a working solution. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-20 by @gfwilliams ... just tried a build from here and that works fine too (albeit without the 'close' event). So I'm not sure what happened for you - maybe there is a 'dead' build in there somewhere though. I wonder what happens if you try lower baud rates now? It might be it's quite a bit more reliable. For the VM image - please could you issue a PR for the changes in the readme file? I guess maybe a lot of people had it running previously but then never bothered to get it working with USB (they just built the image). |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-20 by tve IMHO the 'end' event would be a good addition. Right now it's somewhat painful and error prone to determine when a complete HTTP request has been received. @allObjects: I would have to disagree with your assessment about what uC's are capable of. I totally agree that an architecture where pretty raw data from many nodes is aggregated makes a ton of sense. But while this is what I like to build myself as well, I also like to make the uC nodes that have actuators stand-alone 'cause there's nothing more frustrating than having your entire house/greenhouse/... being inoperable because the central server crashed or otherwise failed. Or not daring to upgrade the central server 'cause so much now depends on it. What makes stand-alone http servers practical is the fact that all the UI can be shoved into browser-side JavaScript. I do that with esp-link and the constraints on the UI are pretty minimal at this point. The uC end up exchanging simple json or binary requests with a central uC and the browser alike. All that's needed is enough flash to hold the minified and compressed JS for the UI and be able to ship it to the browser. If you skip large libraries, such as jquery and bootstrap that's actually pretty easy to do. The upshot of all this is that I'm gravitating towards uC nodes that work with a central node and that have a simple stand-alone UI. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-13 by Snerkle
I am using a pico with an ESP8266 for wifi.
I'm writing code that buffers the body of in incoming http request and attempts to write it to a file.
For small files (around 1-2K) it works. As soon as I try with a larger file I get the following error, I think its while I'm still buffering the body of the request.
I'm at a bit of a loss of how to go about tracking this down as it looks like its somewhere in the ESP8266WIFI_0v25 or the AT library. I could be wrong, but it doesn't look like any of my code.
Any help would be appreciated.
Beta Was this translation helpful? Give feedback.
All reactions