-
• #2
I cannot give you an answer but I can maybe give you a workaround. Instead of using onInit(), maybe try to make your own init function, with some delay before execution:
function myInit() { //cut-paste here the content of onInit() } setTimeout(myInit,500);
Without knowing exactly why, with this trick, I was able to let most of my scripts work even when invoked from flash. FYI, I had the same behaviour with some I2C displays .
-
• #3
There are things (1) that are initialized/executed at upload of the code, and there are things (2) that have to be re-initialized on power up. The
save()
command though saves everything, but on power down certain things (2) get lost.Configurations/settings - for example pin modes - get saved AND are then restored before
onInit()
and E.on("init", function(){...})``` is called.Post your code, then we can do an analysis. Take also a look at simple explanation how to save code that espruino run on start? conversation.
-
• #4
Gents, thanks a lot, I think I have to study the post you mention before asking dumb questions! I think my problem is reinit at power up. So, I study and come back to you.
-
• #5
Hello Experts,
I read the thread you mentioned above, and I am trying to turn its content into a set of design and understanding statements. Could you tell me if I correctly understand the way it works? I hope I won’t confuse others with silly ideas...
These statements ensure that after doing a save() of the software, unplugging the Espruino to un-power it, re-powering it, the software will startup and reach a deterministic state at the end of the onInit() execution.
1 - Global constants are declared as var XXX= xxx. At re-power up, they will be reloaded from flash with their value as they were initialized the first time when the software has been downloaded from the IDE and subsequently executed from top down to bottom.
2 - Global variables are initialized the first time the program is downloaded to Espruino from the IDE (as said in 1). On save(), their current value is saved in flash. At power up, global variables are reset with the values stored in flash (due to the last save()). So, if they have been changed by program execution and not re-saved, their current value is lost and replaced by the flash previously saved value.
3 - On save() execution, function declaration and global code are saved in the flash memory. An instantiated module like ‘var modulevar = require(xxx)’ is saved and is recovered with full instantiation and capability at re-power up (like any other global variable previously saved) .
4 - At powerup, the following operations take place (in order) :
a/ Global variables and code is downloaded from flash memory to ram. There is no execution from top to bottom of the code. So initialization done in the global context is never replayed after the first IDE download and execution.
b/ onInit() function is invoked
c/ when onInit() ends, the system goes to 'Idle' if no event is present in the JavaScript queue (We define 'Idle' as a state where no event is present in the event queue and any processing triggered by previous events is terminated).
5 - onInit() must ensure that at its end, all variables are in the required state.
6 - As consequence of 5, onInit() function must take care of changing global variables to desired values if the saved values are no longer relevant.
7 - onInit() is executed in a time period (init must not last forever! ) and must ensure consistency inside its own execution scope. Javascript is event oriented and not sequence oriented. It means that programmer is responsible for dependencies during asynchronous execution. Two patterns are available to ensure sequential execution (and therefore ensure dependencies constraints):
a/nesting callbacks that will execute in order - called when previous conditions are met-,
or,
b/place initialization statements in time order using timeout function which call initialization functions in order of increasing timeout values.May be there are other ideas I have not reported.
I think my code follow these rules, but it doesn't work! (yet).
Thanks a lot for your help.
GeekBot
-
• #6
Pretty much sums up the application part...
Regarding the restore from FLASH: it is everything as it was at the moment when
save()
was executed - not just the global vars - including the cache which holds the modules (and the config of the MC, such as ports, etc... More about that later).Think of
save()
as the hibernate function some PCs have (or a computer VM): everything is 'saved' when going to hibernate. When coming back, everything is restored (with the PC it is every time you put it to hibernate and restore is from last saved state, with Espruino it is just the one time of save and the restore is always from the initial save.One thing you left out in your list: BEFORE a) happens, chip configs - most importantly, port configs - are restored...
And to be accureate,
var moduleVar = require("xxx");
is a personal practice... You could actually leave that away and use anywhere where you need the module `require("...");
, because the cache that holds on to the module code is part of the RAM and saved / restored as well, andrequire()
is the vehicle to get to the modules in that cache... . The use by a variable is more general (and can hide different ways of that 'require("...");', because when the module is actually a class, for example, a Person class, and you 'store' it in the variablevar Person = require("Person");
, then the use later on in the code is much more obvious, for example,var person1 = new Person(...);
andvar person2 = new Person(...);
Notice the casing: classes start with UpperCase, variables start lowerCase - both are camelCased. This is a good practice to be clear about what is a Reference to a Class and a reference to an instance of a Class.Good practice is not to save something dynamic, such as a timeout or interval. Therefore
setTimeout(...)
andsetInterval(...)
should never be executed on upload... put them always into theonInuit(){...}
orE.on("init",function(){...});
. Same is for creating a connection (latter not totally true, because Wifi settings can be saved too and Espruino automatically connects using the Wifi settings on startup...).(Personally - and in general - I do not like the fact that hardware initialization/restore - such as port modes - is part of the power up; but with well defined power-on behavior and resource strapped Espruino, it is very helpful - in various ways...
Btw, you are thinking 'Arduino' style - no offense to be taken here... The coding model is totally different... (Espruino almost bents itself over, because it has now an option in the setting that lets it almost behave the same: after upload completion, the upload makes a save, and then behaves like the invocation of onInit() or invocations of E.on("init",...).
-
• #7
@allObjects, thank you for these detailed explanations, I understand how it works.
However, I am still turning around my problem. I believe my code follows to what is explained above.
Test 1: I plug Espruino, download the code and type onInit() : it works.
Test 2: I plug Espruino, download the code, save(), unplug replug : doesn't start correctly
Test 3: I plug Espruino, download the code, save(), unplug replug : doesn't start correctly, in the IDE click on top left icon to reconnect the IDE to Espruino, magically it starts to work correctly.What happens when I click on the connection icon in the IDE?
Thanks again
GeekBot -
• #8
There was a time when USB was unplugged and console.log() was used, the console.log (serial) buffer was filled and Espruino hanged... But as said, this was a while ago...
There is something else you need to know: if you use a string variable with the module name in require(), such as
var moduleName = "moduleName"; var module = require(moduleName);
instead of a string literal in require(), such as
var module = require("moduleName");
then the upload cannot (recursively) discover ***in the source code by string search for 'require("...")' the required modules and does not upload them into the cache (before uploading that particular source code); and when it comes to the runtime - the actual execution of the require(...) - Espruino cannot find the module in the cache and then tries to find it in THE (or A) connected SD card... But that error shows in a very distinctive error message about no (SD card) file system mounted where the module could be found...
The option to use a variable instead of string literal for requiring a module and prevent loading of the module into the cache at upload time is intentional, because this allows to enable runtime/dynamic module selection, but it requires the module to be accessible in runtime available - mounted - file system.
Again, have to make this point: Espruino/JavaScript is a totally different runtime concept! When for modules the cache concept is used, it does not mean that actual code (bytes of)(virtual) machine or source code is moved around (from cache space into execution space) - like from a file cache, as you have in, for example a PC operating system. The cache caches the object - like an interpreted/executed function definition, which is just referenced... nothing is moved around (like in virtual machine memory cache of objects of the virtual machine).
For Espruino, this means that
var moduleName = "moduleName"; require(moduleName) === require("moduleName") // true
shows that the things left and right of the === are one of the same thing: identical.
What are the symptoms you get of this not starting correctly?
-
• #9
I have found the problem. It's a mix up between Serial1 and USB console. Forcing the console on USB did the trick. So now the system is working in the same way, connected to IDE or disconnected. Thanks for your help and explanations.
GeekBot -
• #10
There you go... and that answers your questions: the difference is that console is connected differently... (I interpret it that if USB data connectivity - IDE conneted - is discovered, console is routed/forced to USB, otherwise not and has all kinds of adverse effects... on serial1(?)).
-
• #11
Just to add - if you call
onInit
manually, thensave
, if you're addingsetInterval
and stuff like that you might find that you end up with two of them. You can add code to cancel them, or you can try and remember not to runonInit
when you're about to save your code.
Hello,
My program works like a charm when I click on the download button and type onInit().
If I download and type save(), the program is copied to the flash memory (no error, everything ok (apparently)).
But it doesn't execute the same. Symptoms are linked to timing, for instance I get timeout on AT commands.
What can be different between IDE (ram) execution and flash execution ?
Any clue ?
Thanks a lot
GeekBot