BLE HID already sending

Posted on
  • Hello,

    I have hooked up a button to my puck.js and emulating HID keyboard clicks on the button press. It works fine for the most part, except once in a few times, it misses sending a key press over with the a 'BLE HID already sending' error.

    error messageBLE HID already sending
    error messageBLE HID already sending
    Uncaught Error: BLE HID already sending
    at line 1 col 55


    in function called from system

    Looks like some of them get past the try-catch but others don't.

    This happens even if I'm doing these button presses slowly, so it is not an issue of too many button presses going through in a short time frame. Does the port need to be flushed or something?

    I tried upgrading to 2v02.6 cutting edge firmware, but the problem still exists.

    The essence of my code can be found below.

    var kb = require("ble_hid_keyboard");
    NRF.setServices(undefined, { hid : });
    var lastButtonState = 0;
    var busy = 0;
    function on_button_pressed() {
      var currentButtonState = digitalRead(D28);
      if ( currentButtonState === 0) {
      else if (currentButtonState === 1) {
      if(lastButtonState !== currentButtonState){
          digitalWrite(LED2, 1);
          lastButtonState = currentButtonState;
                busy = 1;
                if(lastButtonState === 0){
                  kb.tap(kb.KEY.B, 0, function(){});
                }else if(lastButtonState === 1){
                  kb.tap(kb.KEY.A, 0, function(){});
                busy = 0;
            console.log("error message " + err.message);
            busy = 0;
          digitalWrite(LED2, 0);
    setInterval(function() {
    }, 5);
  • Hi - I'd be pretty sure your issue really is that the data is being sent too quickly.

    In newer Espruino builds, after a few minutes of inactivity it drops down to a lower speed connection to save battery power - which means (IIRC) about 200ms connection intervals, so 400ms to send a single 'tap' over HID - and because you send on press and release you'd have to keep the button held for at least 0.5 sec each time.

    You can force the connection interval to stay fast with NRF.setConnectionInterval(7.5) but it doesn't really solve the underlying problem.

    Because of the way you're checking for a button press there's no 'debouncing', so you could quite easily end up sending two taps as well (It'll also burn through the battery because you're waking Puck.js up 200 times a second).

    Can you try what's used in the examples on and use setWatch instead as it's more power efficient and handles debouncing? It's easy to extend it to work with button press and release to get what you want:

    function btnPressed(e) {
      currentButtonState = e.state;
    setWatch(btnPressed, BTN, {edge:"both",repeat:true,debounce:50});

    Then to handle sending multiple HID events that might get queued up, you probably want something like:

    var queue = [];
    var busy = false;
    function sendTap(key) {
      if (busy) return queue.push(key);
      busy = true;
      kb.tap(key, 0, function(){
        busy = false;
        if (queue.length) sendTap(queue.shift());

    So now, if sendTap gets called multiple times it'll just queue up keypressed and send them when it's able to

  • Hi Gordon,

    Thank you very much for your reply. I appreciate it.
    When I started the project, I was using setWatch, but the latency between when I press the button and when I receive the callback was in the order of seconds and made it unusable for my purpose. That is why I moved to checking button state in an interval. Is there a way to reduce the latency of the callback?

    Setting NRF.setConnectionInterval(7.5) seems to help a bit, but the error still shows up less frequently than before.

    Thanks for the queue idea. I will give that a shot.

  • @ayoganandan1984,

    take a look at this conversation about PUCK Ble HID keyboard... your challenges ring for me the same bell. Timeouts and Intervals - all time driven things - are not that satisfactorily / predictable. If event drivenness can be achieved, conversation loop is much tighter/shorter/expedient.

    Debouncing is a real world issue... that's why most time I do not go for the press of a button, but for a release of the button... and to be really sure, I make it a simple, force-driven flip-flop: a single shot watch for the press, then a check in a bit and when still pressed, I setup a single shot for the release, and there release runs the chore and then starts over with the cycle with setting up the single shot watch for the press...

    Another practical approach is to get and keep the time of the event of the press - you get it with the event object - and keep it in a (global) variable, for example, xyzPressLastTime, which I initialize with 0. When I get a press and before venturing in honoring it, I compare the time if the current press with the one of the last press and decide: that's too quick, it cannot be real, and then just ignore the press - the 'too quick' I keep in a configurable variable. With that mechanism you can go for the press event to do something and at the same time prevent that it is not done multiple times in a non reasonable / impossible short time, as cause,. for example, by bouncing.

  • It's very odd about the latency issues. Try just:

    setWatch(function(e) {
    }, BTN, {edge:"both",repeat:true,debounce:50});

    and you should see the LED lights almost instantly (after 50ms since that is the debounce time used here). There's no way it should be taking seconds - sounds like there's something else going on in your code there.

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

BLE HID already sending

Posted by Avatar for ayoganandan1984 @ayoganandan1984