Remote code update

Posted on
  • I am wanting to update code over GSM. I have seen a few discussions on this but they are a little old. Is there a working example of this for the Pico? I assume the extra flash page could hold the code that it's always run on boot? Any pointers welcomed.

  • Are you talking about updating firmware or updating the current espruino script?

    If it is the latter, the telnet module allows you to connect via ip, so if the GSM is up, you should be able to connect the in the web i.e., connect via the ip rather than serial.

    Sorry, I have only tested on the esp8266 (in which the wifi is always connected). With GSM I guess you'll need to have oninit() that will see that network up. I'm also unsure on how you would know what ip it is on - perhaps you could get it to send that to a website via a http get?

  • I think one of the simplest methods would be to use the extra page of flash as you say and to write a 'bootloader' in JavaScript.

    Something like:

    var addr = 0x08000000 + 384*1024;
    try {
      var code = E.memoryArea(addr+8, peek32(addr));
      var hash = 0;
      for (var i=0;i<code.length;i++) hash += String.charCodeAt(i);
      if (hash != peek32(addr+4)) throw "Bad hash";
      eval(code) 
    } catch (e) {
      // fallback if the code doesn't load for some reason?
    }
    

    So the first word is the length, second is a very dodgy hash to try and check that the code is valid (it could/should probably be improved!), and then there's the data.

    This is done from memory though, so may have some bugs I'm afraid.

    You could then use the flash library to write the code when you received/validated it over GSM:

    var f = require("Flash");
    var addr = 0x08000000 + 384*1024;
    
    f.erasePage(addr); // remove everything
    connection.on('data', function(d) {
      f.write(d, addr);
      addr += d.length;
    });
    

    Hope that helps!

  • Great - thanks for that, a helpful starting point.

  • Am only just getting on to implementing this now !

    So if I have say V1 of my code save() into the Pico (along with the above bootloader code in onInit() ?)

    1. What is the best way for me to grab the correct V2 minified code that I would put on my server for the pico to download and write into flash (which would be run thru eval) ?

    2. In the fallback scenario - When the new code is run via eval, I assume the existing V1 code would have already loaded at that point ? Do I need to get rid of it from RAM first somehow ?

    Thanks

  • I'd actually avoid save()ing your code at all and would just flash the bootloader, with some failsafe code if the firmware update fails... So maybe the bootloader & firmware updater, all in one.

    ... or I guess you could use the V1 as a fallback if needs be, but I'd try and keep the fallback as simple as possible, and ship it with something that the bootloader can load up on to ensure it works correctly!

    What is the best way for me to grab the correct V2 minified code

    • Install espruino from NPM: https://www.npmjs.com/package/espruino
    • Then run espruino -p path_to_espruino_serial_port --minify -o out.js your_input_file.js
    • And out.js should contain the final file that you can upload

    In the fallback scenario

    Yes, that'd be why you don't include the full V1 code unless you have to :)

  • My only concern around not having the V1 code in there as a fallback, is that if the V2 download fails and the unit reboots, it is then a non-functional unit until it can successfully download code.

    For our 24x7 remote logging application - this is not really an acceptable possibility.

    So either I need a way of removing all the V1 code from RAM before running V2, or could I as part of the download new code process do this ?

    • erasePage()
    • write a dump of the current running code into Flash
    • then follow by writing the V2 code (downloaded) into Flash
    • If V2 downloads and verifies I can write to my EEPROM that the V2 code is valid to run - so the bootloader knows which version to load.

    There would still be some risks around this, but probably acceptable for our application

  • Ahh ok. Personally I'd say rewriting the main flash would be a bad idea - if there were a problem, you could brick everything.

    Maybe:

    • Turn on 'Save on Send' in the IDE - this'll save the JS code to flash as text (rather than saving an image of RAM to flash).
    • Put all of your V1 code (if possible) inside a function, so that you then call that function to initialise everything and you're sorted.
    • Call that function in the fallback of the bootloader

    That way, your V1 code isn't taking up any RAM at all until it's called - so you don't even need to unload it.

  • hi.

    Any final solution on that ? Can you share please.

    My current idea that all IoT devices (Espruino) that are connected to local Wifi will automatically update JS script:

    1. (pull) devices automatically check if there is any update script on network and upload it and restart.
    2. (push) implement some UDP broadcast msg with http link to the JS file to update current script.

    It must be safe enough, like ... in case script failing it must return to last script that worked or at least the device AP must be available so sending another script should be still possible.

  • This would be extremely valuable. If anyone already has this implemented I would love to hear. If I get to implement this myself I will share it here.

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

Remote code update

Posted by Avatar for jonreid @jonreid

Actions