Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incompatible and not pairable #11

Open
erichstuder opened this issue Oct 31, 2021 · 18 comments
Open

Incompatible and not pairable #11

erichstuder opened this issue Oct 31, 2021 · 18 comments

Comments

@erichstuder
Copy link

Hello

In the arduino IDE 1.8.13 the examples are shown as "INCOMPATIBLE" although I have selected the Arduino Nano 33 BLE.
But I can compile both examples "ble_shining_kb" and "ble_mouse" it and upload it to the Arduino Nano 33 BLE.
Then on my Android and Windows device I see for example the shining keyboard but can't connect to it.
And also the Arduino Nano 33 BLE shows an error with slowly turning its LED on and off.
I'm using the examples as is. (No modifications)

So my questions:

  • Why are the examples shown as incompatible although I'm using the right hardware?
  • What could be the reason I can't connect?
@tcoppex
Copy link
Owner

tcoppex commented Nov 2, 2021

Hi @erichstuder,

Thanks for the feedbacks, I have just pushed a branch that should fix the compatibility issue that was put aside for a while, hit me back if you still have an issue on that.

For the connection issue I'm not sure. I've quickly test it on my Android and it rant fine. It's okay the led flicker when searching for a signal, it is supposed to loop faster when an issue arises though. Maybe try it with the new version and tell me what you've got.

Cheers

@erichstuder
Copy link
Author

The "INCOMPATIBLE" Problem in the Arduino IDE seems to be solved.
Thank you!

But pairing the device is still not possible.
On my windows 10 device it tries to connect but then just says I should try again.
On my arduino device though there is now an error message that the pairing was not possible due to a wrong pin or access code.
I'm using a german device:
"Kopplung mit Shining Keyboard war nicht möglich, weil die eingegebene PIN oder Zugangscode falsch ist"

Do I have to enter a pin? If yes, how am I supposed to do that?

Regards
erichstuder

@sudomihirjoshi
Copy link

I am having the same problem while connecting my Arduino Nano 33 BLE HID mouse with ubuntu or Android phone. Any idea how to solve this?

@tcoppex
Copy link
Owner

tcoppex commented Nov 9, 2021

Thanks you both for your feedbacks, I'll try to investigate this when possible.

I have not check this but I suspect the culprit to be this line :

gap.manageConnectionParametersUpdateRequest(true);

Try to comment it or set it to false and see what you get.

@erichstuder
Copy link
Author

erichstuder commented Nov 10, 2021

Hello

I tried both with this line:

  • commenting out
  • setting to false

The behavior didn't change.

Regards

@tcoppex
Copy link
Owner

tcoppex commented Nov 10, 2021

Okay thanks.

I check this again on both Android and Linux Mint : the keyboard works fine in both case but the mouse failed most of the time. One reason seems to be the connection_time() for the demo mode whose behavior is not reliable anymore :

if (bleMouse.connection_time() < DEMO_DURATION_MS)

Change this to true and this should now always work on Android, but still fails on Desktop.

I'll look into it.

@erichstuder
Copy link
Author

erichstuder commented Nov 13, 2021

Okay thanks.

I check this again on both Android and Linux Mint : the keyboard works fine in both case but the mouse failed most of the time. One reason seems to be the connection_time() for the demo mode whose behavior is not reliable anymore :

if (bleMouse.connection_time() < DEMO_DURATION_MS)

Change this to true and this should now always work on Android, but still fails on Desktop.
I'll look into it.

I tried that, but still have the same behaviour on Android and Win10.

I played around a bit with ble_shining_kb.ino.
It is connected for a short time, but then looses connection again (bleKb.connected() is true for a short time).
The connection lost seems not to be due to an error (bleKb.has_error() is never true).

Regards

@tcoppex
Copy link
Owner

tcoppex commented Nov 13, 2021

Hey eric,

I reproduced the stall in both Windows and Linux a few days ago, I have yet to find where this come from as it has worked in the past for the same settings, it works okay on Android though. On Linux I made it connect without any effects for the mouse, while the keyboard still work fine which makes me wonder.

I'll keep you updated if I find anything.

Cheers.

@sudomihirjoshi
Copy link

I'm using this for a HID mouse. BLE mouse with Linux as well as Android phone were working great till recently when I changed my OS and Had to reinstall Arduino IDE. The bluetooth kept immediately disconnecting for the PC and the android device gave an error "Cannot pair with device because of invalid PIN or Passkey"
I uninstalled the arduino IDE and downloaded it from arduino website instead of Ubuntu software. I got the older version of board manager "Arduino Mbed OS Nano Boards" version 2.1.0. This with the tcoppex's code from april 2021 has my HID mouse running very well like before.
I don't know exactly which of these changes did the job, but hope this helps diagnose the problem.

@tcoppex
Copy link
Owner

tcoppex commented Nov 15, 2021

Thanks for the hint @sudomihirjoshi,

Yes there is several issues with version 1.3.0 at the moment. I'm working on a fix for the last mbed os nano board version (currently 2.5.2).

@tcoppex tcoppex mentioned this issue Nov 16, 2021
@afpineda
Copy link

Same problem here.
Hope this info to be useful.

I'm trying to pair my Nano 33 BLE with my PC (Windows 10). My Bluetooth dongle (Pc-side) uses "CSR Harmony" comm stack.

  • First of all, the arduino device does not show a name, but a MAC address.
  • Pairing failed with a "no pairing response was received" error message, after 15 seconds or so.

@Zuzon
Copy link

Zuzon commented Dec 9, 2021

I'm with same problem. To get it up I was forced to downgrade Mbed BLE Hid to version 1.2.0 and Mbed OS Nano boards to version 2.1.0 (tried 2.2.0, not working).

@tcoppex problems starts with Mbed os 2.2.0, hope that info will help you.

@tcoppex
Copy link
Owner

tcoppex commented Dec 9, 2021

Thanks for the info @Zuzon.

I'm letting go of the 1.3.0 and trying to figure out how to make it works on the last board version for the next one, I'm not working on this often though and last time I really dig into it it didn't advance much.

So I cannot say for sure when an update will come. Any PR is welcome though !

@afpineda
Copy link

I've been investigating the issue on my own. I think that Arduino Nano33BLE core (or maybe, Mbed 5 itself) is faulty.
No matter how you configure the SecurityManager, the pairing protocol ends up with "SEC_STATUS_UNSPECIFIED" at the "pairingResult" event, in the peripheral's side. In the Central's side, it ends up with a timeout (tested both on Android/nRF app and Windows 10 with an USB BT 5.0 dongle).
Please, could someone confirm my findings?
I don't know where to report this bug. Nobody cares about pairing because it's not needed anymore for device-to-device communication. However, Windows API does not allow to retrieve services and characteristics if the device is not paired (I also investigated this part of the story). Stuck here.

@tcoppex
Copy link
Owner

tcoppex commented Dec 27, 2021

Hey @afpineda, thank you for reporting your findings.

I don't believe it's the nano directly (the nrf512 chip) as previous version of the mbed SDK worked fine. It's supposedly changes in the API, especially the 6.0, and as yourself I believed in my prior investigations that it was related to security settings.

You might find further help in the mbed os ble example repository here.

@afpineda
Copy link

I managed to update Arduino Mbed core to the latest version at https://github.com/arduino/ArduinoCore-mbed. Then, I compiled your suggested example (wich is the same at MBED's API site) as is. It exhibits the same behavior.

A minimal "Arudinoish" modified code (see below) shows the same SEC_STATUS_UNSPECIFIED pairing result. I reported the bug to ArduinoCore-mbed with no success (for now), but it may be a bug in the very API of MBED OS.

#include <mbed.h>
#include <Arduino.h>
#include <BLE.h>

using namespace mbed;
using namespace events;

events::EventQueue queue;


static const char DEVICE_NAME[] = "PairingTest";

using std::literals::chrono_literals::operator""ms;


/** Base class for both peripheral and central. The same class that provides
    the logic for the application also implements the SecurityManagerEventHandler
    which is the interface used by the Security Manager to communicate events
    back to the applications. You can provide overrides for a selection of events
    your application is interested in.
*/
class SecurityDemo : private mbed::NonCopyable<SecurityDemo>,
  public SecurityManager::EventHandler,
  public ble::Gap::EventHandler
{
  public:
    SecurityDemo(BLE &ble, events::EventQueue &event_queue) :
      _ble(ble), _event_queue(event_queue) { };

    virtual ~SecurityDemo()
    {
      _ble.onEventsToProcess(nullptr);
    };

    /** Start BLE interface initialisation */
    void run()
    {
      /* this will inform us off all events so we can schedule their handling
         using our event queue */
      _ble.onEventsToProcess(makeFunctionPointer(this, &SecurityDemo::schedule_ble_events));

      /* handle gap events */
      _ble.gap().setEventHandler(this);

      if (_ble.hasInitialized()) {
        /* ble instance already initialised, skip init and start activity */
        start();
      } else {
        ble_error_t error = _ble.init(this, &SecurityDemo::on_init_complete);

        if (error) {
          print_error(error, "Error returned by BLE::init");
          return;
        }
      }

      /* this will not return until shutdown */
      //_event_queue.dispatch_forever();
      Serial.println("run() OK");
    };

    /** Override to start chosen activity when the system starts */
    virtual void start() = 0;

    /* callbacks */

    /** This is called when BLE interface is initialised and starts the demonstration */
    void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
    {
      ble_error_t error;

      if (event->error) {
        Serial.println("Error during the initialisation");
        return;
      }

      /* for use by tools we print out own address and also use it
         to seed RNG as the address is unique */
      print_local_address();


      /* This path will be used to store bonding information but will fallback
             to storing in memory if file access fails (for example due to lack of a filesystem) */
      const char* db_path = "/fs/bt_sec_db";

      error = _ble.securityManager().init(
                /* enableBonding */ true,
                /* requireMITM */ false,
                /* iocaps */ SecurityManager::IO_CAPS_NONE,
                /* passkey */ nullptr,
                /* signing */ false,
                /* dbFilepath */ db_path
              );

      if (error) {
        print_error(error, "Error during initialising security manager\r\n");
        return;
      }

      /* This tells the stack to generate a pairingRequest event which will require
         this application to respond before pairing can proceed. Setting it to false
         will automatically accept pairing. */
      _ble.securityManager().setPairingRequestAuthorisation(true);

#if MBED_CONF_APP_FILESYSTEM_SUPPORT
      error = _ble.securityManager().preserveBondingStateOnReset(true);

      if (error) {
        print_error(error, "Error during preserveBondingStateOnReset %d\r\n");
      }
#endif // MBED_CONF_APP_FILESYSTEM_SUPPORT

      /* this demo switches between being master and slave */
      _ble.securityManager().setHintFutureRoleReversal(true);

      /* Tell the security manager to use methods in this class to inform us
         of any events. Class needs to implement SecurityManagerEventHandler. */
      _ble.securityManager().setSecurityManagerEventHandler(this);

      /* gap events also handled by this class */
      _ble.gap().setEventHandler(this);

      error = _ble.gap().enablePrivacy(true);
      if (error) {
        print_error(error, "Error enabling privacy.\r\n");
        return;
      }

      /* continuation is in onPrivacyEnabled() */
    };

    /** Schedule processing of events from the BLE in the event queue. */
    void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
    {
      _event_queue.call([&ble_instance = context->ble] { ble_instance.processEvents(); });
    };

  private:
    /* SecurityManager Event handler */

    /** Respond to a pairing request. This will be called by the stack
       when a pairing request arrives and expects the application to
       call acceptPairingRequest or cancelPairingRequest */
    void pairingRequest(ble::connection_handle_t connectionHandle) override
    {
      Serial.println("Pairing requested - authorising");
      _ble.securityManager().acceptPairingRequest(connectionHandle);
    }

    /** Inform the application of pairing */
    void pairingResult(
      ble::connection_handle_t connectionHandle,
      SecurityManager::SecurityCompletionStatus_t result
    ) override
    {
      if (result == SecurityManager::SEC_STATUS_SUCCESS) {
        Serial.println("Pairing successful");
        _bonded = true;
      } else {
        Serial.print("Pairing failed with result ");
        Serial.println(result);
      }
    }

    /** Inform the application of change in encryption status. This will be
        communicated through the serial port */
    void linkEncryptionResult(ble::connection_handle_t connectionHandle, ble::link_encryption_t result) override
    {
      if (result == ble::link_encryption_t::ENCRYPTED) {
        Serial.println("Link ENCRYPTED");
      } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
        Serial.println("Link ENCRYPTED_WITH_MITM");
      } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) {
        Serial.println("Link NOT_ENCRYPTED");
      }
    }

    void onPrivacyEnabled() override
    {
      /* all initialisation complete, start our main activity */
      start();
    }

    /* Gap Event handler */

    /** This is called by Gap to notify the application we connected */
    void onConnectionComplete(const ble::ConnectionCompleteEvent &event) override
    {
      Serial.print("Connected to peer: ");
      print_address(event.getPeerAddress().data());
      if (event.getPeerResolvablePrivateAddress() != ble::address_t()) {
        Serial.print("Peer random resolvable address: ");
        print_address(event.getPeerResolvablePrivateAddress().data());
      }

      _handle = event.getConnectionHandle();

      if (_bonded) {
        Serial.println("Bonded!");
      } else {
        /* start bonding */
        Serial.println("Bonding");
        ble_error_t error = _ble.securityManager().setLinkSecurity(
                              _handle,
                              SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM
                            );
        if (error) {
          print_error(error, "Failed to set link security\r\n");
          _ble.gap().disconnect(_handle, ble::local_disconnection_reason_t::USER_TERMINATION);
        }
      }
    };

    /** This is called by Gap to notify the application we disconnected */
    void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) override
    {
      if (_bonded) {
        /* we have connected to and bonded with the other device, from now
           on we will use the second start function and stay in the same role
           as peripheral or central */
        Serial.println("Disconnected.");
        //_event_queue.call_in(demoDelay, [this] { start(); });
      } else {
        Serial.println("Failed to bond.");
        //_event_queue.break_dispatch();
      }
    };

    void onScanTimeout(const ble::ScanTimeoutEvent &) override
    {
      /* if we failed to find the other device, abort so that we change roles */
      Serial.println("Scan timeout");
      //        _event_queue.break_dispatch();
    }

    void onAdvertisingEnd(const ble::AdvertisingEndEvent &event) override
    {
      if (!event.isConnected()) {
        Serial.println("No device connected to us");
        //_event_queue.break_dispatch();
      }
    }

  private:
    void print_local_address()
    {
      /* show what address we are using now */
      ble::own_address_type_t addr_type;
      ble::address_t addr;
      _ble.gap().getAddress(addr_type, addr);
      Serial.println("Device address: ");
      print_address(addr);
      static bool _seeded = false;
      if (!_seeded) {
        _seeded = true;
        /* use the address as a seed */
        uint8_t* random_data = addr.data();
        srand(*((unsigned int*)random_data));
      }
    }

  protected:
    BLE &_ble;
    events::EventQueue &_event_queue;
    ble::connection_handle_t _handle = 0;
    bool _bonded = false;

    void print_address(ble::address_t addr) {
      Serial.print("--");
    }

    void print_error(ble_error_t error, char *msg)
    {
      Serial.print("ERROR: ");
      Serial.print((uint8_t)error);
      Serial.print(" - ");
      Serial.println(msg);
    }
};

class SecurityPeripheral : public SecurityDemo {
  public:
    SecurityPeripheral(BLE &ble, events::EventQueue &event_queue)
      : SecurityDemo(ble, event_queue) { }

    /** Set up and start advertising accepting anyone */
    void start() override
    {
      ble::peripheral_privacy_configuration_t privacy_configuration = {
        /* use_non_resolvable_random_address */ false,
        ble::peripheral_privacy_configuration_t::PERFORM_PAIRING_PROCEDURE
      };

      Serial.println("At Start()");
      if (_bonded) {
        /** advertise and filter based on known devices */
        Serial.println("We are bonded, we will only accept known devices");
        privacy_configuration.resolution_strategy =
          ble::peripheral_privacy_configuration_t::REJECT_NON_RESOLVED_ADDRESS;
      }

      _ble.gap().setPeripheralPrivacyConfiguration(&privacy_configuration);

      start_advertising();
    };

  private:
    void start_advertising()
    {
      uint8_t adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
      /* use the helper to build the payload */
      ble::AdvertisingDataBuilder adv_data_builder(adv_buffer);

      adv_data_builder.setFlags();
      adv_data_builder.setName(DEVICE_NAME);

      /* Set payload for the set */
      ble_error_t error = _ble.gap().setAdvertisingPayload(
                            ble::LEGACY_ADVERTISING_HANDLE,
                            adv_data_builder.getAdvertisingData()
                          );

      if (error) {
        print_error(error, "Gap::setAdvertisingPayload() failed");
        return;
      }

      ble::AdvertisingParameters adv_parameters(
        ble::advertising_type_t::CONNECTABLE_UNDIRECTED
      );

      error = _ble.gap().setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_parameters);

      if (error) {
        print_error(error, "Gap::setAdvertisingParameters() failed");
        return;
      }

      if (_bonded) {
        /* if we bonded it means we have found the other device, from now on
           wait at each step until completion */
        error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
      } else {

        error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
      }

      if (error) {
        print_error(error, "Gap::startAdvertising() failed");
        return;
      }

      Serial.println("Advertising...");
    }

};

SecurityPeripheral *peripheral;

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(1000);
  //  mbed_trace_init();

  BLE& bleInstance = BLE::Instance();

#if MBED_CONF_APP_FILESYSTEM_SUPPORT
  /* if filesystem creation fails or there is no filesystem the security manager
     will fallback to storing the security database in memory */
  if (!create_filesystem()) {
    Serial.println("Filesystem creation failed, will use memory storage");
  }
#endif

  Serial.println("START");
  peripheral = new SecurityPeripheral(bleInstance, queue);
  peripheral->run();
}

void loop() {
  queue.dispatch_once();
  //Serial.print(".");
}

@erichstuder
Copy link
Author

Zuzon suggested a versions mix:

I'm with same problem. To get it up I was forced to downgrade Mbed BLE Hid to version 1.2.0 and Mbed OS Nano boards to version 2.1.0 (tried 2.2.0, not working).

@tcoppex problems starts with Mbed os 2.2.0, hope that info will help you.

I tried it out with this versions.
It seems to work some how a bit better.
But the issue I have with this versions combination is that my phone turns off bluetooth immediately after the pairing (Zenfone 8).
Havent found a good explanation why my phone is doing this so far.
Other Bluetooth connections work fine.
So this workaround is not working for me.
Just wanted to let you know.

@ufocia
Copy link

ufocia commented Jan 26, 2023

This may be the same issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants