Avatar for cha0s

cha0s

Member since Mar 2021 • Last active Mar 2021
  • 2 conversations
  • 7 comments

Ethical hacker likes privacy :)

Most recent activity

  • in Bangle.js
    Avatar for cha0s

    Hey Gordon, would you mind just pointing me towards a link where I could start if I theoretically had brass balls and wanted to try modifying my own firmware?

  • in Bangle.js
    Avatar for cha0s

    Espruino doesn't support destructuring

    Oooh, yeah I did discover that because in my PR I had const {clock: clockApp} = ... and it died. I missed that one.

    call load("clock_app_name.js")

    It seems this is essentially having the same effect?

    load the random clock on the lcdPower on event?

    I did try that first! The thing is, it's better to have a little bit of flicker when the watch is going to sleep than when the watch is waking up. 99% of the time in the Real World™ I won't even see the flicker when the watch goes off, because I got what I needed and am not looking anymore. On the other hand, I will see it flicker every time before showing the clock, and that will (and did) drive me nuts :)

    it would be pretty easy to call unload() and then eval() a new clock app

    I did think about an approach like this but it's pretty intrusive in that 1. every clock app needs to conform and 2. it seems rather trivial to screw this up in any given clock app (even if there is an unload function), leading to leaks...

    Thanks for responding :) I think the tl;dr for now is that what I have is the best that it can be without other deeper changes (e.g. firmware). I'm just happy I was able to get a random watch face!

  • in Bangle.js
    Avatar for cha0s

    So this brings me to the final hackish """solution""" I came up with for keeping the display on during initial bootloading:

    if (require("Storage").read(".bootrn")) {
      require("Storage").erase(".bootrn");
      Bangle.setLCDPower(0);
    }
    Bangle.on("lcdPower", function onLcdPower(on) {
      if (!on && " random" === clockApp) {
        Bangle.removeListener("lcdPower", onLcdPower);
        require("Storage").write(".bootrn", "1");
        load();
      }
    });
    

    When powering off, a 1-byte file is written to .bootrn and when bootloading, the existence of that file is checked. I don't need to tell you that this is an ugly hack... but it works :)

    So anyway this was my journey thus far in trying to accomplish a real-time random clock face.

    Question:

    Is there any way less invasive than calling load() to accomplish this, as I have? The entire flicker hack can be removed if so. I tried things to get around this, e.g. wrapping the clock/child application in an IIFE, evaluating it, and then deleteing the function. Nothing besides load() seemed to reliably do the trick without a bunch of memory leakage.

    Also, the limit for this forum is kinda low. I'm only replying to continue the thread like this because I ran out of characters, lol.

    Anyways, I'll attach the bootloader.js and settings.js in case anyone wants to mess around with it.

    P.S. I was scared to load a different bootloader to my watch but I went for it!

  • in Bangle.js
    Avatar for cha0s

    There's a random clock app, but the way it works is that you have to reload the bootloader manually to actually flush the new random face. That isn't what I want -- I want a real-time random watch face that will show me a different face every time I wake up the display.

    This has proven to be rather more difficult than I expected, but I have finally come up with something that, while hackish, is actually functional. I figured I'd share it here instead of making a PR, because I'm pretty sure it would never actually go into the code as-is. Anyway,

    The easier of the changes was modifying the settings app to allow a random clock. This was accomplished by simply adding an else case to the existing code:

    if (clockApps.length === 0) {
      clockMenu["No Clocks Found"] = () => { };
    } else {
      clockMenu[`${settings.clock === " random" ? "* " : ""}[random]`] = () => {
        if (settings.clock !== " random") {
          settings.clock = " random";
          updateSettings();
          showMainMenu();
        }
      };
    }
    

    NB: I used " random" because the clockApp is a string name of the application set, and I think adding a leading space ensures that there won't be a collision, but I would appreciate guidance if I'm wrong about that.

    The bootloader part was a little more tricky (and I'm still not 100% satisfied, though I'd say it does work about 90% of the way I'd like it to). First off I set about refactoring the code just a bit to make selecting a random clock easier.

    const clockApp = (require("Storage").readJSON("setting.js­on",1) || {}).clock;
    const evaluateCurrentClockApp = () => {
      const allClockApps = () => (
        require("Storage").list(/\.info$/)
          .map((file) => {
            const app = require("Storage").readJSON(file,1);
            if (app && app.type == "clock") {
              return app;
            }
          })
          .filter((x) => x)
      );
      const clockNotFound = `
        E.showMessage("No Clock Found");
        setWatch(() => {
          Bangle.showLauncher();
        }, BTN2, {repeat:false,edge:"falling"});)
      `;
      const currentClockApp = () => {
        if (" random" === clockApp) {
          const apps = allClockApps();
          return apps.length > 0
            ? require("Storage").read(apps[Math.floor(­Math.random() * apps.length)].src)
            : clockNotFound;
        } else if (clockApp) {
          return require("Storage").read(clockApp);
        }
        // Fallback: first clock app we discover on the system
        const [discoveredApp] = allClockApps().sort((a, b) => a.sortorder - b.sortorder);
        return discoveredApp
          ? require("Storage").read(discoveredApp.sr­c)
          // Fallback: not found
          : clockNotFound;
      };
      delete evaluateCurrentClockApp;
      eval(currentClockApp());
    };
    

    Instead of running

          eval(clockApp);
          delete clockApp;
    

    to enter the clock app as before, we just: evaluateCurrentClockApp();.

    I was also made aware of the fact that all code in the bootloader persists through the passing of execution to the clock -- that is why delete evaluateCurrentClockApp; is at the end of the function. I think it's pretty crazy that you can delete a function that is currently in calling scope, but it actually works and I verified by trace() in the web IDE that it does indeed clean up the memory.

    So this is fairly straightforward, but we end up at the original problem: this runs once when the bootloader is executed, but then the selected "random" clock stays as the watch face unless the bootloader is manually run again (e.g. long press BTN3).

    I tried a couple solutions to this problem, but the one that seems the most promising is this: set an LCD power off listener in the bootloader. When the LCD is powered off and the current clock app is set as random, reload the bootloader:

    Bangle.on("lcdPower", function onLcdPower(on) {
      if (!on && " random" === clockApp) {
        Bangle.removeListener("lcdPower", onLcdPower);
        load();
      }
    });
    

    This actually works fairly well for what it does... the only problem is that reloading the bootloader turns the LCD back on, so you can probably guess what happens next: a never-ending loop of the LCD going off, coming back on with a random clock face, going off, coming back on, etc. Still, I was kinda happy when it happened :)

    After this happened, I tried this:

    Bangle.setLCDPower(0);
    Bangle.on("lcdPower", function onLcdPower(on) {
      if (!on && " random" === clockApp) {
        Bangle.removeListener("lcdPower", onLcdPower);
        load();
      }
    });
    

    This actually solves the never-ending wake loop, but it introduces another problem: the LCD screen is off upon initial execution. It's honestly a small price to pay for a true random clock face in my opinion, but I wanted to do better. This is also when I really noticed how after the LCD turns off there is a flicker due to reloading the bootloader, before my LCD power off occurs. Annoying, but acceptable (for me).

    • 4 comments
    • 942 views
  • in Bangle.js
    Avatar for cha0s

    Well, after taking her apart (why else would I get a hackable watch, right?!) I am thinking that there is no way around this. The viewport seems too small to show the entire screen... At least with the degrees along the edge. I may investigate removing these, as I will probably never ever ever utilize them (also I could just code a digital one).

    Interested if anyone has any feedback, regardless.

  • in Bangle.js
    Avatar for cha0s

    Hey all,

    I got my Bangle today and have been taking it for a test run.

    Unfortunately, it seems that the screen is off-center thereby making it hard/impossible to see the upper corners of the screen.

    I attached a picture of me sending a test text from gadget bridge. As you can see, the "test" text is almost entirely obscured :(

    Is this normal, or did I get a lemon?

Actions