when it is safe to save()?

Posted on
  • I tried for the first time to call save() when my code in DS-D6 watch is somewhat usable but after saving, the console and my code stopped working. When connecting via Bluetooth I see ->Bluetooth on serial and I can also see switching back message when disconnecting bluetooth but I cannot enter any commands (both in serial and bluetooth console) and also my code (setWatch - touch button to show time) is not working anymore.

    After power cycle it boots into console prompt but after few seconds it freezes.So I guess it is maybe some setWatch which is triggering something not initialized? I managed to type reset() quickly after another powercycle so it is OK now.

    The answer in FAQ says that timers, watches, and even pin state is restored however it also says " For certain things (like initialising connected hardware like displays) you'll want to run some code when Espruino starts up".

    This feature of restoring "timers, watches, and even pin state" seems a bit dangerous to me because even some pin state may make sense only with some prior hardware initialization.

    Would it be useful or even doable for save() to just save code without any other state that runs code (timers,..)?

    To me it means that I should be either extra careful in all my watches and timers to check for uninitialized or simply random state (which could be tricky with attached hardware with its own state) or better I should not start anything before running save() - just call reset(), load pure code without starting/initializing anything and then run save(). Also I see command history is saved too probably eating memory (as all my code is pasted there line by line), can this be cleared before running save?

    Apart from the faq question there is also https://www.espruino.com/Reference#l__global_save with no hints or more details. Is there some other turorial or ducumentation related to this?

    EDIT: BTW, the saving and loading itself went fine, when saving it compressed fine and did fit into memory so there was no issue with that.

    EDIT2: Oh, found also this https://www.espruino.com/Saving with some Gotchas
    but still I don't understand why it stopped working imediatelly after calling save()

  • I think https://www.espruino.com/Saving probably covers this, but:

    This feature of restoring "timers, watches, and even pin state" seems a bit dangerous to me

    It didn't used to, but it got added because that's what users asked for.

    The idea is that it's what the average user would expect - as you start doing more serious stuff you'll probably start moving towards upload+save without running onInit first, or even saving directly to flash.

    Would it be useful or even doable for save() to just save code without any other state that runs code (timers,..)?

    Go to the Web IDE, Communications, Save on send, and choose to save directly to flash. I think this is what you're after...

    Also I see command history is saved too probably eating memory

    Command history is deleted automatically as and when memory runs low :)

    save with no hints or more detail

    Thanks for the hint - I'll make sure that links to https://www.espruino.com/Saving . If you think that could have anything added that cleared up the situation a bit then I'd be really interested to hear though.

  • ...sometimes users ask for killer app - in this case: killer function - that turns out to be a (potential) product killer feature. There are too many dependencies that are not necessarily understood to blindly apply save() anytime. I'm with @fanoush on that, because the system state may be in a non-resumable state, and more so, when peripherals have initializations as well, it is good practice to put all initializations into an onInit() triggered path. I know that Espruino does a good job in restoring pin modes and one time initializations of its (communication) appliances, such as assigning pins and modes and speeds, etc. But that's about it. I allow myself to save those. But for me, any xyz.connect() or a like and object initializations belong into the onInit() triggered path. If this save() function poses too much risk() - as experience over time may indicate - only save on send should survive, because it ensures that nothing has run yet.

  • If you think that could have anything added that cleared up the situation a bit then I'd be really interested to hear

    Well after also reading the Saving page it is a bit more clear but still from all of this I did not get the idea that it is dangerous and definitely not what I wanted to use or that I should be extra careful before using it. The Summary in Saving page starts with

    Just type save() on the left-hand side of the IDE and the current state of Espruino including all saved code will be written so that it is loaded at boot time.

    and then hints that there are maybe better ways and then pros and cons are discussed but nothing that would warn me that this automatic save needs serious thinking when to call it in all but nontrivial cases. So I'd like to see some bigger warning there.

    The API reference says

    When Espruino powers on, it will resume from where it was when you typed save(). If you want code to be executed right after loading (for instance to initialise devices connected to Espruino), add an init event handler to E with E.on('init', function() { ... your_code ... });. This will then be automatically executed by Espruino every time it starts.

    This does not explain potential issues. Also BTW is the on init function always guaranteed to run before e.g. my just restored setInterval will fire? Should I set E.on(init) before calling save() so it gets saved too? This may not be clear from those sentences.

    I would add something like this to save() API reference

    Please note that if you have watches and intervals already set at the time of save, they will continue to run after resume so use the on init method to restore hardware to expected state before they will run again. If you omit this it may lead to unexpected and possibly serious failures if your code does not handle such state properly. This method is targeted for simple use cases where it will 'just work' however it may not be the best for more complex scenarios. For more details and alternatives see page Saving. See dump() to understand what gets saved.

  • Also BTW is the on init function always guaranteed to run before e.g. my just restored setInterval will fire?

    Yes.

    Should I set E.on(init) before calling save() so it gets saved too?

    If you want to run a function at boot that way rather than using onInit then yes...

    After your last post I actually modified the save() docs, they're just not in the reference yet. I've also just tried to add your comments from the last post - so they now read: https://github.com/espruino/Espruino/blob/master/src/jswrap_interactive.c#L167

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

when it is safe to save()?

Posted by Avatar for fanoush @fanoush

Actions