Puck sending same key repeatedly?

Posted on
  • I'm having this odd issue with my pucks (tried 2) where, I guess, for some reason, the puck is repeatedly sending the same key over and over. I've had this issue on 2 separate pucks, and 2 separate PCs, 2 separate Bluetooth dongles.

    This has happened with both Cutting Edge and the last proper v199 release.

    Doesn't happen ALL the time, but often enough where it presents a problem.

    Any ideas?

  • I just tested with Espruino IDE, and eventually this comes up, which just KILLS the button:

    "Uncaught Error: BLE HID already sending" pointing at the end of a function. After that, the button stops responding to HID stuff.

  • more logs:

    Uncaught Error: Got BLE error code 12292
     at line 36 col 8
    in function called from system
    New interpreter error: FIFO_FULL
    WARNING: jsble_exec_pending: Unknown enum type 46
    WARNING: jsble_exec_pending: Unknown enum type 32
  • Either the button is stuck or something else creates jitters - changing signal - that the watch picks up fires the method. Since you tried it on multiple pucks, I do not think that it is cause by some hardware issue. What is the software setup that you nave? Could you please post (part of) your code
    (at least the part that covers the control/invocation path from catching the button press thru the invocation of the sending the press. Did you use a pinMode(,"xxxx") with xxx = "input_pulldown" or "input_pullp" to make the input not float around and catch electro smog?

  • Here's my current code. Previous versions did not have the "sending" check that this now does. I haven't experienced issues with this version of it.

    console.log("Battery: " + E.getBattery() + " " + Puck.getBatteryPercentage());
    var debugText = false;
    var kb = require("ble_hid_keyboard");
    NRF.setServices(undefined, { hid : kb.report });
    var sending = 0;
    function catchButton(e) {
      var keyDown = e.state === true;
      var keyUp = e.state === false;
      var click = false;
      debug_log(keyDown?"key down" : (keyUp? "keyUp" : "broke"));
      if(keyUp) {
    function triggerCommand() {
      try {
        if(!sending) {
          sending = 1;
          NRF.sendHIDReport([0,0,99,0,0,0,0,0], function() {
            NRF.sendHIDReport([0,0,0,0,0,0,0,0], function() {
              setTimeout(function() {
                sending = 0;
              }, 250);
      } catch (e) {
        console.log("caught:" + JSON.stringify(e));
        setTimeout(function() {
          sending = 0;
        }, 250);
    setWatch(catchButton, BTN, {repeat:true, debounce:50, edge:'both' });
    function debug_log(t) {
      if(debugText) console.log(t);
  • Great - thanks for posting up! Do you think it's worth me updating the HID example to add that 'busy' check?

    I guess it's possible that two keys get sent at more or less the same time in such a way that it's then not possible to send the second NRF.sendHIDReport([0,0,0,0,0,0,0,0] which would have 'released' the key?

    Strange about the FIFO_FULL/etc though.

  • The FIFO_FULL thing might have just been my computer shitting itself. After that moment, I couldn't do anything with the Puck's HID stuff at all, even after re-uploading the firmware. A reboot of the PC fixed it.

    Great - thanks for posting up! Do you think it's worth me updating the HID example to add that 'busy' check?

    I guess it's possible that two keys get sent at more or less the same time in such a way that it's then not possible to send the second NRF.sendHIDReport([0,0,0,0,0,0,0,0] which would have 'released' the key?

    Yeah, that seems to be the case. The keys get sent too fast, which breaks the buffer or something. A simple check like that might be good in the example, yeah. It's odd that I didn't experience any issues until recently though.

  • It's odd that I didn't experience any issues until recently though.

    It might have been some recent changes in 'cutting edge' Espruino firmware. Espruino used to always get polled every 20ms when connected, which uses up a bunch of power. Now it polls every 7.5ms which makes everything way faster, but after a minute or so of inactivity it drops down to every 200ms until stuff happens again.

    It means your Puck will now last a year on its battery even when it's connected, but if you just press the button after > 1 minute of inactivity then the sending of the button press and release will take 400ms. It's way more likely that you can press the button twice within that 400ms period :)

    You can turn it back to default behavior with NRF.setConnectionInterval(20) if you need to.

  • So, I've been doing more testing. I've upped the delay to in my setTimeout() to 500 - still getting errors.

    Most of them are caught, so it doesn't brick the button:

    caught:{"message":"Got BLE error code 12292","type":"Error","stack":" at line 38 col 8\n      });\n       ^\n"}

    Per this error code, I've found this other post: https://devzone.nordicsemi.com/f/nordic-­q-a/6222/stability-in-the-uart-communica­tion-over-ble

    Eventually, the button just gives up entirely, the exception can't be caught...

    Uncaught Error: Got BLE error code 12292
     at line 37 col 10
    in function called from system
    New interpreter error: FIFO_FULL
    WARNING: jsble_exec_pending: Unknown enum type 46
    WARNING: jsble_exec_pending: Unknown enum type 46
    WARNING: jsble_exec_pending: Unknown enum type 46
  • That's very odd - 0x3004 is BLE_ERROR_NO_TX_PACKETS.

    Are you using 1v99, or a cutting edge firmware? The newer firmwares take advantage of the fact that they can send more than one TX packet per interval and actually expect that they might hit this error.

    Could you try removing the print/console.log statements from your code? What I think is happening is:

    • Something happens that prints a bunch of data to the console - this uses up the available TX slots in that connection (it's not supposed to, but hey)
    • Then we try and send the HID report - it fails
    • The error is caught and printed to the console, compounding the problem.

    Even so, FIFO_FULL is a very strange error as it implies that a lot of data was coming into Espruino. What were you doing when it happened? To get that purely from pressing the button you'd have to have pressed it 64 times while Espruino was busy executing a function.

  • Firmware is cutting edge from Sept 13 2018.

    Basically, I am actually pressing the button a lot as an intensive test. So every press causes an output. I'll remove the console.logs to see if we get the same behavior.

    We've had cases of spontaneous button bricking. Need to reset and re-upload code. Sometimes, after a period of inactivity the button stops responding to clicks despite being shown as connected as a keyboard.

    In the cases where I've been able to get a log of what happens, it's the same set of errors as I've been getting here. This is what lead me to adding the delay between allowed clicks, make sure it's not sending multiple HID reports at once.

  • Hmm - that is strange. Removing console.log may really help - you could always move the console to a different device, but Espruino will always try and send the data on BLE if it thinks it is connected.

    Does something like NRF.setConnectionInterval(100) fix it for you? It might be related to the connection interval stuff I mentioned.

    Worst case you can add something like this:


    If Espruino really is being unresponsive then using the watchdog would ensure that it always stays working. If you put it in manual mode the hardware itself will reboot unless your code explicitly calls E.kickWatchdog every so often.

  • Instead of using the console - especially when it interferes with resources - and with BLE being the only communication channel (no USB connectivity), I uses blinking of a led or two to communicate where things run through in actively running code. See example for that in this conversation: , in posted code, lines 233..257 - around // logging / LED blinking (beginning w/ setting the variable logging to true and more so to false but still getting some 'logging' done - with application in lines 269, 292, 284, latter two logging error and success with lg(0,aCodeNumber0to9,"codeNumberRepeatin­gAndMatchingMessageAsString") and lg(1,...). It also makes sure that in disconnected state with no console device/display attached - and logging set to false, nothing will fill up buffers and make the system 'die'. May be I should make a module out of it... (by know I should have enough knowledge of git handling... ;-)).

    A module something like that:

    // mutelogger.js module
    // allObjects 20180920_0
    var lng  = false;    // log activities to console
    var cds="";
    var cdl=null, dev1=null, dev2=null; // 'current (code) LED', LED1, LED2
    function lg(ok,cd,obj,override) { // logging / LED blinking
      if (arguments.length === 1) {
        lng = !!ok;
        return lg;
      if (arguments.length === 0) return lng;
      if ((override === undefined) ? lng : override) console.log(obj);
      var l = cds.length;
      cds += "BB"+((ok) ? "G" : "R")+"LB"+blds[cd];
      if (l === 0) bl();
      return lg;
    var blts= {"L":300,"S":80,"P":120,"B":450};
    var blds = ["LLLLL", "SLLLL", "SSLLL", "SSSLL", "SSSSL", "SSSSS", "LSSSS", "LLSSS", "LLLSS", "LLLLS"];
    function bl() {
      var c = cds.charAt(0);
      if (c=="G") { cdl = dev2; cds = cds.substr(1); c = cds.charAt(0); }
      else if (c=="R") { cdl = dev1; cds = cds.substr(1); c = cds.charAt(0); }
      if (c!="B") cdl.set();
          cds = cds.substr(1);
          if (cds.length > 0) setTimeout(bl,1);
    var setup = 
    exports.setup = function(pin1, pin2, logging) {
      lng = !!status == true;
      return lg;

    Usage examples:

    • setup w/ with red error LED1 and green ok LED2 and console output on:

    var lg = require("mutelog").setup(LED1,LED2,1);
    • log error with code 3 (can be 0..9) and matching message:

    lg(0,3,"3: Failed to connect"); // 3 short and 2 long blinks of the red error LED1
    • log success with code 4 (can be 0..9, but not 3, 3 already taken) and matching message:

    lg(1,4,"4: Connect"); // 4 short and 1 long blinks of the green ok LED2

    Override the logger's status for just one log event:

    lg(1,5,"5: Logged to console anyway",1); // overriding an eventual mute status

    Change status to write or not to write to console:

    lg(0); // mute console - switch logging to console off

    Returning the logger's logging status (returning 0 or 1):

    var logging = lg(); // returns 0/1 for not/logging to console

    ...and bonus - as inspired by Smalltalk's default return of a method to return always the object if nothing (different) has to be returned - lg() returns itself - in this case the lg() function - to make cascading - repeated invocation - very concise:

    lg(1).(1,3,"3:message to console").(0).(0,4,"4:message just blinks");

    Btw, this is a first for me to do a cascading of invocations - when object is the method itself (global is the object here global.lg(), but is of no interest).

    The setup allows to use any pin - or led or what ever device is connected to that pin, and even the same... the blinking code is the ultimate information. If you run out of codes with two LEDs - one for error and one for ok, you ignore the color for error or ok information and use red for codes R0..9 and G0..9 and knowing with R... an G... are error and ok messages.

    Any takers for test? ... or even extending it to two digits error/ok codes?

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

Puck sending same key repeatedly?

Posted by Avatar for tako @tako