NRF.setServices .. onWrite called twice

Posted on
  • Hi,

    there is NRF.setServices and I have no trouble setting up a custom service and characteristics when executing code in the IDE, and use it thereafter. Then I tried to put this in a .boot.js file and an issue pops up: the writable characteristic calls onWrite twice each time a message arrives.

    So I thought its because setServices is called multiple times (e.g. after long-press BTN3), but even the following doesn't solve it:

    setTimeout(() => {
      var cc = require('concom');
    
      cc.t = (0|cc.t) + 1;
    
      function has_service(sid, cid) {
        var svc = {};
        svc[cid] = {};
        var svcs = {};
        svcs[sid] = svc;
        try {
          NRF.updateServices(svcs);
        } catch (e) {
          return false;
        }
        return true;
      }
    
      if (has_service(0xf011, 0xf012)) return;
    
      NRF.setServices({
        0xf011: {
          0xf012: {
            maxLen: 53,
            writable: true,
            onWrite: (e) => cc.read(new Uint8Array(e.data))
          },
          0xf013: {
            maxLen: 53,
            notify: true
          }
        }
      });
    }, 3 * 1000);
    

    When I run its parts individually, everything works (e.g. first has_service returns false, then setServices, then has_service returns true) and I get one onWrite per message. When I do a hard reset with this in the boot file and write to the characteristic, onWrite gets called twice.

    It would be great if anyone could shed some light on this :)

    edit: .t is 1

  • I'm not sure what to suggest here I'm afraid... The way setServices works it shouldn't really be able to call the handler twice. What if you add some kind of 'print' statement inside onWrite: (e) => cc.read(new Uint8Array(e.data)) just in case your cc.read method is doing something internally?

    You could also check on your watch to ensure your code isn't in there twice (eg in two separate files). You could check with:

    require("Storage").list().forEach(f=>{
      if (require("Storage").read(f).includes("0x­f012")) print(f);
    });
    

    If it's ok, it should be in just .boot0 and in your app.boot.js file

  • I found the issue, and its not Espruino/Bangle. The callback isn't called twice (should have count it earlier) but the returned message on Nordic UART is processed twice on the remote side (Arch Linux, Intel 7260, Bluez 5.66). But only if I didn't remove the device using bluetoothctl after a reset.

    Sorry for the distraction!

    For future reference: when the custom characteristic is added, and my Bluez already knows about the Nordic UART from previous discover, it would immediately disconnect after connect. So I'm forced to remove and rediscover. If, however, it knows about the custom characteristic and the custom characteristic is added during a reset, it wouldn't disconnect after connect but process incoming messages twice. Or at least thats what I see and I'm able to reproduce. Remove and rediscover solves the issue for me.

  • when the custom characteristic is added, and my Bluez already knows about the Nordic UART from previous discover, it would immediately disconnect after connect. So I'm forced to remove and rediscover.

    That's a good one to know... I had occasionally got into an odd state that required removal of the device (and IIRC that is somewhere in the bluetooth troubleshooting docs) but I didn't know why!

    Out of interest, how do you remove? Just with the OS's Bluetooth Menu, or via some command-line? I find the OS menu very difficult as it's got about 1000 devices in it for me!

  • With bluetoothctls shell you can execute remove {MAC} as well as scan le, devices, scan off. And as a last resort power off and power on. It does remember previous commands but won't autocomplete afaik. I assume there are cmdline arguments for scripting.

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

NRF.setServices .. onWrite called twice

Posted by Avatar for !evil @!evil

Actions