• Hi.

    I am trying to fiddle proof a bangle.Js 2 as i want to use it for various reminders for my 4 year old.

    As part of that i would really like to control for how long a interval one must hold the button before a reboot is triggered as the default one seems quite low for my situation.

    I have however some difficulties locating the actual code triggering the reboot.
    I can locate the firmware code in https://github.com/espruino/Espruino/blo­b/912aecb676c78e8fc0282775b46c7ad48c428a­30/targets/nrf5x_dfu/main.c where nrf_dfu_enter_check seems to be running directly after the reboot (controlling if we boot without loading code etc.)

    But what i need is really the trigger for the reboot. I have also looked in the bangle JS code but to no avail. There seems to be a E.Reboot function which trigges the reboot, but i fail to see anythign calling that.

    Can someone help on where the trigger code for a reboot is?

  • Hi - is it the full reboot you're worried about? Rather than just the change in apps?

    The full reboot is actually handled by the watchdog timer, which I believe is set up in https://github.com/espruino/Espruino/blo­b/912aecb676c78e8fc0282775b46c7ad48c428a­30/targets/nrf5x_dfu/main.c#L207

    When you hold the button, it stops kicking the watchdog and then eventually the watchdog times out and reboots the device.

    As far as I know once it's set you're stuck with it until the next reboot, so you would have to update the bootloader to fix it.

    ... or you could modify the Bangle.js code to just kick the watchdog for longer after the button is pressed (but you run the risk that if that code were to break, you would be unable to hard-reboot the bangle)

  • or you could modify the Bangle.js code to just kick the watchdog for longer after the button is pressed (but you run the risk that if that code were to break, you would be unable to hard-reboot the bangle)

    if you would schedule one timeout at button press to kick once after e.g. 4 seconds it could work to increase to 5+4 seconds and could be safer than setInterval or some random kicking, something like this (just remove print parts)

    var wdTm;
    setWatch(function(e) {
      if (wdTm) {clearTimeout(wdTm);wdTm=0;print("WD kick cleared");}
      if (e.state){
      wdTm = setTimeout(()=>{E.kickWatchdog();wdTm=0;­print("WD kicked");},4000);
      print("BTN Pressed");
      }
    }, BTN, {edge:"both", debounce:50, repeat:true});
    

    however I am not sure how this works when apps are started/killed and where this piece of code should be to work all the time

  • Perfect this is what i was looking for

    For me it seems best to simply update the bootloader to have a higher timeout on the watchdog.

    I will also do some work on a custom clock that locksdown the app code side, but that seems easier for me. My real problem was getting my head around the bootloader/firmware code.

    Thanks for guiding me in the right direction

  • For me it seems best to simply update the bootloader to have a higher timeout on the watchdog.

    Yes. It is just that replacing bootloader is not trivial and is a bit risky without having SWD debugger but yes this is the most sensible solution. Once the watchdog is started the interval NRF_WDT->CRV cannot be changed so bootloader is the only place to change it.

    BTW the code kicking watchdog is here
    https://github.com/espruino/Espruino/blo­b/master/libs/banglejs/jswrap_bangle.c#L­1093
    it is inside if (!(jshPinGetValue(BTN1_PININDEX) )) so some variation of one time delayed kick even if button is held longer than some time could be implemented there too.

  • if you would schedule one timeout at button press to kick once after e.g. 4 seconds it could work to increase to 5+4 seconds and could be safer than setInterval or some random kicking

    That's a really neat fix! That would make a nice app.

    To handle the app reload case I guess all you need is in the boot code you do another setTimeout(...) to kick the watchdog

  • Hi

    So i tried this as i after thinking found it quite neat.

    As i wanted to kick the watchdog several times i tried something a little more elaborate - as you can see below.

    Key problem is that it does not work. Initially i set the interval to 3000 miliseconds and it would never get called. Now it is at 500 and it get's called and kicks the watchdog twice.
    After that none of the debug lines is printing more.
    So it seems to me that there is some code which after the button has been pressed between 1 and 1,5 seconds will effectively clear all intervals and times.

    I also tested directly with your code example and it has the same problem. The function set in setTimeout never gets called.

    I have nothing but a blank v15 firmware running on the watch (i have uploaded an additional app, but this happens on the standard clock without my app have ever been opened)

    let wdTm;
    let wdKc;
    let wdBw;
    if (wdBw) {
      clearWatch(wdBw);
      wdBw=0;
    }
    wdBw = setWatch(function(e) {
        if (wdTm) {
          clearInterval(wdTm);
          wdTm=0;
          console.log("WD clear");
          //print("WD kick cleared");
        }
      wdKc=0;
      console.log("button touched");
      if (e.state){
          console.log("setting interval");
        wdTm = setInterval(function () {
            console.log("in interval");
            if (BTN.read() && wdKc < 7) {
              E.kickWatchdog();
              console.log("watchdog kicked");
              wdKc++;
            } else {
              clearInterval(wdTm);
              console.log("WD clear by interval");
            }
        },500);
        console.log("interval set");
        }
    }, BTN, {edge:"both", debounce:50, repeat:true});
    
  • So it seems to me that there is some code which after the button has been pressed between 1 and 1,5 seconds will effectively clear all intervals and times.

    Ahh - yes, this is the app reload code.

    The button does two things:

    • If held for ~2 secs it loads the default clock face
    • If held for ~10 secs it resets the device

    The code will stop the ~10 second timer from happening, but not the 2 sec one. So the watch will still reload the default clock face which will then stop your code from running.

    If your code was 'boot code' then it would run even after the reload.

    So for example if you write setInterval(E.kickWatchdog,1000); to noreboot.boot.js then long-pressing the button will not reboot the watch (but it will still cause the default clock app to reload).

  • So i should have written this but i actually started trying with it as boot code, but that did not work at all.

    I can call setWatch in the boot file, but the watch function never gets activated.
    Initially i could not figure out if boot code could not write to console, so i tried running it with debug information going to a logfile instead, and you can see the code getting executed at boot time but the setWatch on BTN nevers runs.

    Can there be somewhere in the initializing code which clears all watches and which could run after my boot code?

    Also the reload of the default clock face in 2 secs, where is that controlled as i might want to tingle with that as well

  • but the setWatch on BTN nevers runs.

    The issue could be that the button is already pressed when the Bangle reboots? So you don't get a watch event because there was no state change.

    Instead you might also want a if (BTN.read()) E.kickWatchdog()

  • Also the reload of the default clock face in 2 secs, where is that controlled as i might want to tingle with that as well

    That one is in jswrap_bangle.c as well, in the peripheralPollHandler. It could be a neat thing to allow users to change - and I guess if we're doing that we could allow the reboot one to be changed as well (in a similar way to what's being done in JS code)...

  • Ok, I've just added Bangle.setOptions({btnLoadTimeout:...}) to cutting edge builds. I'd forgot about this but you should also be able to do: E.enableWatchdog(5); which will set the watchdog to 'automatic' mode - so it's called automatically in the idle loop. As a result you'll only be able to long-press reboot if the Bangle's code really has locked up and you hold the button.

    So do:

    Bangle.setOptions({btnLoadTimeout:0});
    E.enableWatchdog(5);
    

    with cutting edge firmwares and you're sorted

  • Thanks. What constitues a cutting edge firmware?

    In terms of the other things i cut down my code to below and put in in timer.boot.js and now it "works" meaning that if i boot my bangle then the code will push the reboot down the line as long as i have not done anything but stay on the default clock.

    But if i boot the bangle, enter the launcher, go back to the default clock or boot the bangle and use the ~2 sec button push to reload the clock then the code will not work.
    Can it be true that some of these actions will kill boot code or maybe just clear any intervals?

    In timer.boot.js
    let wdKc;
    let wdBw;
    if (wdBw) {
      clearInterval(wdBw);
      wdBw=0;
    }
    wdKc=0;
    wdBw = setInterval(function () {
      
      if (BTN.read()) {
        if (wdKc < 3) {
    		E.kickWatchdog();
    		wdKc++;
    	}
      } else {
    	  wdKc = 0;
      }
    }, 4000);
    
  • What constitues a cutting edge firmware?

    You can see them listed at https://www.espruino.com/Download#bangle­js2 - it's what gets built from the absolute latest code on GitHub.

    Can it be true that some of these actions will kill boot code or maybe just clear any intervals?

    No - the boot code should always get loaded unless you do the very specific https://www.espruino.com/Bangle.js2#rese­tting-without-loading-any-code

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

Bangle.js 2: Control length of button press before reboot

Posted by Avatar for AskHolme @AskHolme

Actions