Avatar for Franzo

Franzo

Member since Mar 2021 • Last active Jun 2021
  • 0 conversations
  • 10 comments

Most recent activity

  • in Bangle.js
    Avatar for Franzo

    Some updates on the tests I have been doing during the week.

    In my attempt to analyze the Command Identifier byte which is different between the two Parameter Update messages, I simplified the app I am using on BangleJS.
    This is its code:

    const kb = require("ble_hid_keyboard");
    
    // Force Bluetooth to use the fastest poll interval available
    NRF.setConnectionInterval(7.5);
    // Enable BLE HID providing an HID report.
    NRF.setServices(undefined, { hid : kb.report });
    
    function drawApp() {
      g.clear();
      g.setFont("6x8",2);
      g.setFontAlign(0,0);
      g.drawString("HID test", 120, 120);
    }
    
    function logPrint(message) {
      const now = new Date();
      Terminal.println(now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + " - " + message);
    }
    
    NRF.on('connect', function(addr) { logPrint("Connected to " + addr); });
    NRF.on('disconnect', function(reason) { logPrint("Disconnected: " + reason); });
    
    // Start!
    drawApp();
    

    The app configures the minimum connection interval and sets the HID report, using the one provided by ble_hid_keyboard module. Then it does nothing else other than printing to terminal every connection and disconnection event. I also simplified the actions I do to reproduce the problem: now I always leave the BangleJS near my PC and control connections and disconnections to the device using the Blueman interface.

    Using this app I am still able to sniff the Bluetooth traffic with Wireshark and see the two Parameter Update messages sent by BangleJS, but I also noticed some other interesting details:

    1. The second Parameter Update message is not always sent by the device after a connection, but when it is present its timestamp is always 41 seconds after the first captured packet (i.e. the command triggered by my click on "Connect to device" on PC).
    2. The second Parameter Update message is not generated when the connection to BangleJS includes the device pairing procedure.
    3. After the connection is established, a momentary disconnection often (about 50% of my tests) occurs before 41 seconds have passed. The app prints on the BangleJS Terminal: Disconnected: 8, which should be the error code for Connection Timeout. After the reconnection has been completed no further traffic is reported by Wireshark, so no second Parameter Update message is present even in this case.

    The low power stuff is handled by the DYNAMIC_INTERVAL_ADJUSTMENT ifdefs, and it should get reset with the code here on disconnect https://github.com/espruino/Espruino/blo­b/master/targets/nrf5x/bluetooth.c#L1148­

    But... maybe something about the way it disconnects when out of range causes that code not to work?

    I, too, think than could be the root cause of the problem... The cases I described in this post tend to happen "alternately", for example: if in a Wireshark capture I see a spontaneous disconnection (case 3), I can almost be sure that in the next capture I will see two Parameter Update messages (case 1). It is as if something from the previous connection does not get correctly reset and keeps affecting the next connection.

  • in Bangle.js
    Avatar for Franzo

    Please could you try adding NRF.setConnectionInterval(7.5) to the top of your app? That'll force Espruino to always use the fastest Bluetooth poll interval available.

    I have done what you asked and I found out something very interesting.

    Wireshark reports the connection interval setting as the first message sent by BangleJS to my PC after connection creation. It is a L2CAP protocol Connection Parameter Update Request packet containing:

    0000   02 01 2e 10 00 0c 00 05 00 12 03 08 00 06 00 06
    0010   00 00 00 90 01
    

    Byte 10 is the Command Identifier and its value is 0x03.

    After the connection is established, keystrokes have a delay of [100 - 150] ms for the key up action. In this state the usual issue of repeated and lost keystrokes can happen, especially if I quickly press the button.

    However, if I wait for ~40 seconds after connection creation Wireshark captures another Connection Parameter Update Request packet sent by BangleJS with the following contents:

    0000   02 01 2e 10 00 0c 00 05 00 12 05 08 00 06 00 06
    0010   00 00 00 90 01
    

    The contents are the same except for byte 10, which is now 0x05.

    After this packet reception, the delay of key up actions drops to [15 - 30] ms and there are no more repeated or lost keystrokes.

    Could it be that the Command Identifier of the first Parameter Update is wrong? I can see from the Wireshark dump that all the requests are accepted with a Connection Parameter Update Response packet sent by my PC, but maybe the Command Identifier 0x03 is actually ignored by the PC BLE controller...

  • in Bangle.js
    Avatar for Franzo

    the Wireshark capture of actual Bluetooth traffic shows the packets are missing

    This one.

    In the capture, the HID commands are classified as Bluetooth Attribute Protocol (ATT) packets and each keystroke is a pair of key down and key up actions with corresponding packets.
    If I send a space keystroke from my app, Wireshark reports first a packet with an ATT value of 00002c0000000000 for key down, then another packet with a value of 0000000000000000 for key up. The second packet is sent ~15 milliseconds after the first one.

    When the issue is happening this sequence is jumbled up because some packets are missing. In addition, for the few successful keystrokes, the delay after which the key up action is sent is much higher (~150 ms).

    @Gordon, have you managed to reproduce the problem with your Linux PC?

  • in Bangle.js
    Avatar for Franzo

    I have done a Wireshark capture to try to get a better idea of what is actually going on when the issue happens. These are the actions I have performed during the capture:

    1. Pair and connect to BangleJS at a safe distance (< 0.5 m).
    2. Send some keystrokes, always keeping myself at a safe distance.
    3. Move away from my PC and wait for disconnection.
    4. Go back to my PC at the same distance as before and wait for reconnection.
    5. Send again some keystrokes until the issue happens.

    I observed that the keystrokes of step 2 correctly alternate the key down and the key up actions, whereas the ones of step 5 quickly lose the correct sequence and the order is messed up. As we correctly guessed, the issues are caused by missing packets, i.e.:

    • "No keystroke" happens when only the key up action is received.
    • "Repeated keystroke" happens when 2 consecutive key down actions are received.

    @Gordon if you are interested in analyzing the .pcap capture file, I can DM it to you. It should not contain any sensitive information but I'd rather avoid publishing it here...

  • in Bangle.js
    Avatar for Franzo

    @Sebastian: I also agree on the lost "release" packet theory: a repeated keystroke can almost always stopped pressing the corresponding button again.
    Regarding the operating distance, I generally use HID and experience this issue when I am at least 2 m from my PC. Only when I stay at a "safe" distance (< 0.5 m) during the whole duration of hidkbd app operation the issue seems not to be happening.
    As already mentioned in my first post, I am pretty sure that the problem lies in the Bluetooth reconnection procedure. If I force a disconnection and wait for reconnection, I can reproduce the bug even at a safe distance. Probably the increase in keystroke misses and repeats rate that you experience during long range operation is the consequence of a reconnection triggered after a momentary lost signal disconnection.

    @Gordon: in my use case (media playback control) the 'key stuck on' problem is much more harmful than the missed key. So yes, I would be very grateful even only for a fix for the repeated keystrokes problem!
    So, if I got this right from your post, in the BLE HID protocol a sort of ACK is expected after each keystroke. If this is true, maybe even the missing initial keypress could wait until a timeout and report a failure as an exception of kb.tap() call. This exception could be caught from user code such as hidkbd and possibly trigger another kb.tap() call or print an error message on screen. This, combined with my reconnection routine described in post #9, should do the trick!
    What do you think? Can this be feasible?

  • in Bangle.js
    Avatar for Franzo

    Thank you for your replies!

    @Sebastian: I am also not very versed in Bluetooth devices, but before buying a BangleJS I used a cheap Bluetooth keyboard to achieve what I am trying to do now (i.e. remote control of media playback on PC). That keyboard never gave me these kind of problems, except a reasonable delay on the first keystroke after a reconnection. This is why I found the behaviour of BangleJS quite unexpected.

    @Gordon: I am using a slightly modified version of hidkbd app, where I only changed the keys sent with ble_hid_keyboard module and added a reconnection routine which calls NRF.wake() when NRF.getSecurityStatus().connected is false. I implemented this routine some time ago because I thought that the repeated keystrokes could have been a sort of "buffering" effect on the commands sent when the device is disconnected, but actually it did not fix the problem at all.
    The issue is reproducible with the hidkbd app too, so I do not think that the problem lies with the changes I made.

    I do not know if the problem is only limited to Linux: I am not using native Windows anymore on my PC, but when I did I often experienced some issues when I tried to reconnect, which could only be solved by removing the BangleJS from the trusted devices list and rediscovering it again. Never seen repeated keystrokes, though.

    As you suggested, I just tried to add a try {...} catch block around the call to kb.tap(). An exception is indeed caught on the next keypress after a repeated one and it says: Error: BLE HID already sending.
    It seems that some sort of communication issue is actually happening...

  • in Bangle.js
    Avatar for Franzo

    Hi,
    I am experiencing exactly the same problems described by @Sebastian in his first post.

    This is my setup:

    • BangleJS Firmware version 2v08 stable.
    • PC OS: Xubuntu 20.04.2
    • PC Kernel version: 5.4.0.66
    • PC Bluetooth adapter: Intel 7260
    • BlueZ version: 5.53

    The problems that happen to me more often are keystrokes not registered and keystrokes repeated several times (sometimes indefinitely until the next key press).
    I found out that the best way to reproduce both problems is following these steps:

    • Assure that the BangleJS is connected to the PC.
    • Wait at least a minute without doing anything on BangleJS.
    • Cause a temporary disconnection on the PC (either due to long distance from the BangleJS or forcing a disconnection using the Bluetooth control interface).
    • Restore the Bluetooth connection.
    • Send several keystrokes.

    The bug persists until I disable and then reactivate Bluetooth on both the PC and the BangleJS device.

    @Sebastian, how did you manage to make HID keyboard work as expected?
    @Gordon, can there possibly be a fix for this problem in any cutting edge firmware version?

Actions