Bangle.drawWidgets hangs app

Posted on
  • I have been wrestling with my app mysteriously hanging, requiring a long press of BTNs 1 and 2, and believe I have tracked the problem down to Bangle.drawWidgets. It happens randomly and I have only ever seen it happen when both GPS and HRM power are enabled. The widgets I currently have loaded are Bluetooth Widget, Battery Level Widget (with percentage) and RAM Widget. The following code demonstrates the problem:

    var ctr = 0;
    g.clear();
    Bangle.loadWidgets();
    Bangle.drawWidgets();
    Bangle.setGPSPower(1);
    Bangle.setHRMPower(1);
    setInterval(function(){
      g.reset();
      g.setFont("6x8", 3);
      g.drawString(ctr.toString(),60,60,true);­
      if(ctr++%10 == 0){
        g.reset();
        Bangle.drawWidgets();
      }
      g.flip();
    },100);
    

    When it hangs, which can take anywhere up to an hour, the count is always a multiple of 10 (e.g. 16140 in my final test just now) - hence my assertion that drawWidgets is triggering the problem - and the only widget remaining visible is the bluetooth symbol. The app hangs on both the current stable firmware and bleeding edge. Nothing is logged on the console and memory usage (when running test code above) was stable at 22%.

  • What about if you do not have the second - conditioned - .reset() in the mix? Is it required? Resetting a dispaly driver chip requires often abiding some timing / sequence constraints. My guts point in the direction that the second reset happens too quickly after the first one. This setup of the double reset every 10th time of executing the interval body code could cause the issue. What though still puzzle's me is the observation that this happens only when both GPS and HRM are powered.

    EDIT: mixed .reset() up with .clear() - as @NebbishHacker points out in next post #3.

  • I'm pretty sure g.reset() only resets the state of the Graphics object - not the display driver chip.

  • I don't think drawWidgets itself does anything that is likely to hang (unless a widget itself calls drawWidgets?). The most likely culprit is one of the widgets you'd have loaded.

    When it hangs, what happens if you press Ctrl-C? Can you break out of it? If so it should hopefully either pop into debug mode or give you a stack trace of where the issue is.

  • @NebbishHacker, I see the point you're making.

  • I've been able to reproduce the issue a couple times and I got your exact symptoms - no logs, only the bluetooth widget frozen, completely unresponsive until I reset by holding BTN1+BTN2.

    Looking at the content of the WIDGETS array on my watch, I see that the order of the widgets is bluetooth, batpc, ram. The fact that the ram widgets is consistently the only one visible when it freezes is makes me suspect the issue might somehow be triggered by the battery (with percentage) widget.

    I modified your code a bit because I'm impatient, and now it generally hangs within 5 minutes:

    var ctr = 0;
    g.clear();
    Bangle.loadWidgets();
    Bangle.drawWidgets();
    Bangle.setGPSPower(1);
    Bangle.setHRMPower(1);
    setInterval(function(){
      g.reset();
      g.setFont("6x8", 3);
      g.drawString(ctr.toString(),60,60,true);­
      ctr++;
      Bangle.drawWidgets();
      g.flip();
    },1);
    
  • Took out the second g.reset() and it still hung, at 19220 this time. I have previously had the app hang without RAM Widget loaded so the fact that it hangs with the Bluetooth widget displayed would seem to implicate Battery Level Widget (with percentage). Running another test just now, will see if I can get anywhere with Ctrl-C.

    edit: I see suspicion about Battery Level Widget is growing :D

  • I reinstalled Battery Level Widget (with percentage) in order to make it show up last in the list, and now when it freezes the bluetooth and ram widgets are both visible but the battery level widget still isn't. This once again reinforces my suspicion that the battery widget is involved.

  • Even more damning: the code still hangs if you replace Bangle.drawWidgets(); with WIDGETS["batpc"].draw();

  • Looks like the issue is in E.getBattery(). This freezes:

    var ctr = 0;
    g.clear();
    Bangle.setHRMPower(1);
    g.setFont("6x8", 3);
    setInterval(function(){
      g.drawString(ctr.toString(),60,60,true);­
      ctr++;
      E.getBattery();
    },1);
    

    Ctrl-C does nothing.

    Edit: the call to setGPSPower isn't needed to get the hang.

  • Nice work. Yes, hangs for me very quickly, no response to Ctrl-C in IDE console.

  • Wow, thanks for narrowing this down!

    I know what the problem is now. It's because the heart rate monitor uses the ADC (analog to digital converter) from an interrupt, and the E.getBattery is using it in the main event loop.

    Occasionally you can get in a state where getBattery starts the ADC and waits, but then the HRM jumps in and tries to use it, and I imagine at some point one or other of them gets confused.

    I just filed a bug for it at https://github.com/espruino/Espruino/iss­ues/1861 but I'm off this week so unlikely to get it fixed during that time. I think realistically it's going to need a firmware fix, but you may be able to work around it with:

    Bangle._setHRMPower = Bangle.setHRMPower;
    Bangle.setHRMPower = function(p) {
      Bangle._HRM = p;
      Bangle._setHRMPower(p);
    };
    E._getBattery = E.getBattery();
    E.getBattery = function() {
      Bangle._setHRMPower(0);
      var b = E._getBattery();
      Bangle._setHRMPower(Bangle._HRM);
      return b;
    }
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Bangle.drawWidgets hangs app

Posted by Avatar for skm @skm

Actions