-
• #2
Wed 2017.08.02
@user79451 have you considered a watchdog timer?
While this can be done easily with hardware, a software equivalent could be used. While I can't speak for whether this will work in your case, this implementation (non Espruino though) seems to be what you are after. When the watchdog function is not called, it triggers a separate event, such as a reset.
https://gist.github.com/rsbohn/1359687
Keep us posted on your success.
Robin -
• #3
Hi,
You can use http://www.espruino.com/FlashEEPROM to write data to flash memory, so data can be kept even after reset.
There is a proper hardware watchdog timer in most microcontrollers that you can use as well - once set up, if it's not called every so often then it'll reset the device.
Espruino has two modes - one is automatic (if the interpreter doesn't return to the 'idle' state then it'll reboot), and the other requires you to manually 'kick' it:
E.enableWatchdog(0.5); // automatic mode while(1); // Espruino will reboot because it has not been idle for 0.5 sec
E.enableWatchdog(1, false); setInterval(function() { if (everything_ok) E.kickWatchdog(); }, 500); /* Espruino will now reset if everything_ok is false, or if the interval fails to be called */
This wasn't implemented on Puck.js until this morning (it'll be in firmware 1v94), but if you install the latest firmware from http://www.espruino.com/binaries/travis/master/ it should have the feature in it.
-
• #4
Very nice!
Of course my first line of defense should be proper programming on my side. I really didn't want to do this (show my beginner programming..) but somehow this code below makes my Puck restart within a day. Driving me nuts..
Basically a guarding program that check for the absence of light and the presence of a magnet. It puts the result in the bluetooth name. There is an extra feature that checks for the presence of a bluetooth name 'base'. At the moment it just adds a ">" to the front when it isn't there, eventually it should do a NRF.sleep() when it is out of reach of the base to save battery.
It sets a message "LM:LM", the first two tell whether it has seen light or lost the magnet during the running time of the puck, the second pair shows whether it sees light now or whether the magnet is absent right now. Good news would be "--:--". (It also adds the time, free memory and battery for debugging.)
I am assuming something is wrong with the function notifyBase(statusMessage), where I look for the base and set the advertisement. It is asynchronous I know that, is it being run on top of itself maybe, should I be catching errors?
var firstLightAlarm; //keep track of whether there has been a light alarm var firstMagnetAlarm; //keep track of whether there has been a magnet alarm var timeStart, timeNow; clearWatch(); // just to make sure I don't keep stacking watches and intervals clearInterval(); //check for light(light>.2) or loss of magnet (strength<10000) function doCheck() { var lightLevel = Puck.light(); var seeLight = lightLevel > 0.2; var mag = Puck.mag(); var magForce = Math.sqrt(mag.x * mag.x + mag.y * mag.y + mag.z * mag.z ); var lostMagnet = magForce !== 0 && magForce < 10000; statusMessage = setStatus(seeLight, lightLevel, lostMagnet, magForce); notifyBase(statusMessage); // go set the advertisement as statusMessage } // construct a status message out of sensor values, history, time. //LM:L- means "Seen light and lost magnet in the past, at the moment seeing light, but have the magnet close. function setStatus(seeLight,lightLevel,lostMagnet,magForce) { var statusMessage; var secondsRunning = Math.floor(getTime() - timeStart); firstLightAlarm = firstLightAlarm || seeLight; firstMagnetAlarm = firstMagnetAlarm || lostMagnet; statusMessage = (firstLightAlarm ? "L" : "-") + (firstMagnetAlarm ? "M" : "-") + ":" + (seeLight ? "L" : "-") + (lostMagnet ? "M " : "- ") + "T=" + Math.floor(secondsRunning/(60))+ //minutes since initialization //" L="+Math.floor(lightLevel * 500)+ //" M="+Math.floor(magForce/100) + " "+ //watch out for growing string error " B="+Puck.getBatteryPercentage()+ " FR=" + process.memory().free; console.log(statusMessage); return statusMessage; } // Set BLE advertisement if 'base' present. When base not present Puck would normally stop advertising It now just adds a > in front of the status. function notifyBase(statusMessage){ NRF.findDevices(function(devices){ var foundBase=false; for (var i = 0; i < devices.length; i++){ var name = devices[i].name; if( name == "base"){ foundBase= true; break;} } if (foundBase){NRF.setAdvertising({},{name:statusMessage});} else {NRF.setAdvertising({},{name:">" + statusMessage});} //temporary, without base it should stay quiet },1000); } //main program, sets the 4s interval to do a check function onInit() { firstLightAlarm = false; firstMagnetAlarm = false; timeStart = getTime(); digitalPulse(LED1,1,100); clearInterval(); // otherwise you run out of memory on many button presses setTimeout(function(){ setInterval(function(){doCheck();}, 4000); },2000); // 2s timout to place Puck without triggering early alarm } //click button to re-initialise. setWatch( function () { onInit();}, BTN, { repeat:true, edge:'falling', debounce : 50 } ); onInit();
-
• #5
From what I can see, your code looks fine. Could you try using one of those latest builds of the firmware linked above? I found some issues recently with
findDevices
that could potentially be causing this.When the device crashes, can you connect to it at all?
-
• #6
I have seen it do a restart. When I had the program saved it ended up stuck in the end. Without anything saved it came back up with its original 'Puck.js a000' bluetooth name!
Could that mean the battery is being depleted and coming back up after a while? I see the battery measure going down reasonably fast, enough to reach zero in a 6-8 hours.
Later on battery levels show higher levels again. Does setting Bluetooth search and advertising take that much battery? More than the cell can deliver constantly. That wouldn't be too bad as it is doing the check every 4 seconds now, could be every 4 hours later...
Will upgrade the firmware and set it off running now.
Nothing wrong in my code, now that is unexpected :)
-
• #7
Ahh - it could well be a battery issue - keeping the radio receiving all the time takes up quite a lot of power. I just measured and it's around 12mA - so if
findDevices
were on constantly it'd drain a 200mAh battery in 16hours. It's still some way off your 8 hours running it for 1 in 4 seconds, but it could explain a lot.CR2032s don't like high current draw, so it's possible that it would die and then come back enough to boot into an unprogrammed Espruino environment.
-
• #8
The battery was already at half I would say. Guess the findDevices is something to do sporadically.
Do I understand correctly that setting the advertising doesn't cost as much battery as does findDevices? Advertising is limited to once every 315ms or something, while findDevices is a constant operation?
-
• #9
Yes, absolutely. There's some info here: http://www.espruino.com/Puck.js#power-consumption
Basically advertising uses very little power - it's only using the radio for a fraction of a millisecond, every 300ms. When you have a connection, it uses the radio more often = more power, but you can use
NRF.setLowPowerConnection(..)
to use a slower connection speed that uses less power.It's really only things that keep the radio or CPU on for a long time that use the power (plus the LEDs, obviously). If I'm honest I didn't realise that
findDevices
drew as much power as it does!
Is there a way to make the Puck more resilient to programming errors in the long run? Have it automatically reboot or something?
If for some reason it hangs, could it be automatically rebooted while not losing logged data? Can logged data be saved to flash while running a program?