-
• #2
How long before it stops? I know things have to yield to the watchdog timer on ESP8266 so the OS can run wifi - perhaps this is related to that?
-
• #3
Would you be able to attach a file of your JavaScript source as edited in the Web IDE. I for one would be interested to load your program and have a go with dump().
-
• #4
dump ends up writing to the UART non-stop at whatever rate the UART cranks stuff out until the WDT hits and then the esp resets. If you can increase the baud rate you may get more.
Unfortunately there is no easy fix. -
• #5
Thank you for taking the time to look into this. Here is the code:
var pinButton = NodeMCU.D3; var pinLed = NodeMCU.D7; var pinRelay = NodeMCU.D6; var statusRelay = false; var statusAlarm = null; var statusAlarmRunning = false; // Initalisation of pins var initializePins = function() { console.log("Initialize pins..."); pinMode(pinRelay, "output"); pinMode(pinButton, "input"); pinMode(pinLed, 'output'); }; var initializeButton = function() { setWatch( longButtonPress, pinButton, { repeat:true, debounce: 2000, edge:"falling"} ); setWatch( buttonPressed, pinButton, { repeat:true, debounce: 70, edge:"falling"} ); }; var buttonPressed = function() { console.log("short press"); statusRelay = !statusRelay; digitalWrite(pinRelay, statusRelay); digitalWrite(pinLed,!statusRelay); }; var longButtonPress=function(){ console.log('long press'); // ESP8266.reboot(); }; function init() { initializeButton(); initServer(); setInterval(function(){ console.log(process.memory()); }, 100000); require("ESP8266").setLog(2); } function playAlarm() { statusAlarmRunning = !statusAlarmRunning; console.log("Toggle relay: " + statusAlarmRunning); digitalWrite(pinRelay, statusAlarmRunning); } function initServer() { var http = require("http"); initializePins(); console.log("Initalizing server instance..."); http.createServer(function (req, res){ var request = url.parse(req.url, true); var action = request.query; if (action) { var target = ""; var setting = ""; for (var key in action){ if (action.hasOwnProperty(key)) { target = key.toLowerCase(); setting = action[key].toLowerCase(); if (statusAlarm !== null) { clearInterval(statusAlarm); statusAlarmRunning = false; statusAlarm = null; } switch(target) { case "switch" : if (setting === "on") { // switch relay on console.log("Switch relay ON"); digitalWrite(pinRelay, 1); digitalWrite(pinLed,0); break; } else if (setting === "off"){ // switch relay off console.log("Switch relay OFF"); digitalWrite(pinRelay, 0); digitalWrite(pinLed,1); break; } else if (setting === "toggle") { statusRelay = !statusRelay; console.log("Switch: Toggle to " + statusRelay); digitalWrite(pinRelay, (statusRelay === true) ? 1 : 0); digitalWrite(pinLed, (statusRelay === true) ? 0 : 1); break; } break; case "status" : console.log("Switch status: " + statusRelay); break; case "alarm" : if (!statusAlarm) { statusAlarm = setInterval(playAlarm, 300); } break; } } } target = null; setting = null; } res.writeHead(200); res.end("Hello World"); }).listen(8080); } E.on('init', function() { init();});
-
• #6
Hi Ollie, not much time... see the code I posted. I could try to see if it related, but what do you mean with 'I know things have to yield to the watchdog timer'? Do I need to change something or somewhere?
-
• #7
@CrashingDutchman ... The ESP8266 is primarily designed to be a processor for WiFi based applications. In the ESP8266 everything runs on a "single thread" meaning that there is no real multi-tasking for applications. If an application "keeps control" for too long, then other areas of code are starved for attention. In the WiFi and networking world, such timings are critical. If the WiFi or networking code that is implemented inside the ESP8266 doesn't get control often enough, then it can break its contracts with other networking partners. In an attempt to detect this, the ESP8266 runs a periodic timer which causes a hardware interrupt to occur. This timer is apparently reset each time control is given to the necessary time sensitive portions of the ESP8266 code. If the timer fires, then it means that we haven't given control to the ESP8266 soon enough. The ESP8266 treats this as a problem and basically reboots itself in the hope that what ever was congesting access to the networking code will have "gone away".
In our story here, Espruino is itself the application running inside the ESP8266. Espruino then interprets your scripts to provide the model of running JavaScript. The internals of Espruino must give control back to ESP8266 networking often enough to satisfy its timing requirements.
Now ... imagine a complex function such as "dump()". What mr @tve is saying is that in his understanding, dump() is working through Espruino memory, building a text output and writing that as quickly as possible through the relatively slow serial output. This is a logic path within the Espruino implementation. If that logic path takes longer than maximum time we are allowed to spend outside of ESP8266 networking, the timer goes off and we abandon what we were doing. This timer is also known as the "watchdog timer".
I'm more than certain that there are gross inaccuracies in my description here and please forgive me for that ... but hopefully it supplies a bit of the background that might be useful to you. The bottom line though ... is it isn't your code that is the problem nor can you change anything in your JavaScript code to fix it ... unfortunately it is currently "just one of those things" in the current implementation of Espruino on the ESP8266.
Work is starting up to port Espruino to the new ESP32 devices ... which may alleviate this issue. The ESP32 is a dual core device where (typically) one core is dedicated to networking and the other core dedicated to the user application (Espruino in our story). This will simplify dramatically many of the technical obstacles. However, I would not anticipate a useful build of Espruino on ESP32 nor great availability of the devices until summer 2017 (it may be sooner, but I'd rather lower expectations than otherwise).
-
• #9
Just to add to this - Espruino is designed for 'normal' microcontroller systems where most IO processing happens in interrupts. When systems work like that, having a long-running function isn't a problem at all.
The Nordic bluetooth chips are a great example of this - they handle all the Bluetooth/IO stuff in interrupts and everything 'just works'.
However on ESP8266 a lot happens in tasks that are all executed at the same priority level. If one task (eg. Espruino) takes too long it can mess up WiFi, so they added a watchdog timer that resets the system if that happens.
There's not really much of a way around it - you can add multi-tasking, but then that uses up a bunch of memory for an execution stack and means that you don't have enough to run a sensible amount of JS code. At the end of the day Espruino+ESP8266 is never going to be perfect - but I think for a lot of things it's more than good enough.
When I do a dump() on an ESP8266 (that runs my code perfectly well) it doesn't show all the JS code. At some point the console just stops listing the code and the cursor stays at end of line.
When I do a carriage return (on keyboard), the prompt comes back.
I checked the console log, but nothing strange there.
Any ideas what could cause this?