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

HID connection fails to pair with iOS #8

Open
sttwarrior opened this issue Apr 11, 2021 · 15 comments
Open

HID connection fails to pair with iOS #8

sttwarrior opened this issue Apr 11, 2021 · 15 comments

Comments

@sttwarrior
Copy link

Hi, I have been trying to use the shining keyboard example on iOS but failed to. The pairing with my iPhone or iPad breaks very soon. I read a few documents from Apple, wondering if it's because the transmission is not encrypted. Also when I use LightBlue to test on the shining keyboard, the pairing breaks, too, and LightBlue reported error: the data is staled. If would be great if you can look into it!

@tcoppex
Copy link
Owner

tcoppex commented Apr 12, 2021

Hi @sttwarrior,

Unfortunately I don't have access to an iOS device to test it out, but your point seems valid, you might want to look at this part to manage secure connection :

// Initialized Security manager with no Man-in-the-middle (MITM) protection.

As the comment states, enabling Man in The Middle (MTM) protection made the device fails to connect in subsequent connections (after the first pairing), we might have to configure other parts I have not figured yet.

Thanks for the feedback.

@kylethorson
Copy link

I'm trying this out on two iOS devices right now. I've noticed the same issue, where the bluetooth connects then quickly disconnects. When connecting it confirms if I want to pair the device. At this point the LED goes dim, so the board thinks it's connected. I found that if I don't hit "pair" right away, let it sit for 5-10 seconds, then hit "pair" it stays paired. The shining keyboard example worked on both my iphone and ipad.

@sttwarrior
Copy link
Author

Hi @tcoppex thanks for getting back to me. I will try to play around it and see if I can figure it out.
Also, thank you, @kylethorson, for sharing the hack — that is exactly the phenomenon I found. Unfortunately, I cannot use your finding to reproduce the same effect on my side; I tried letting it sit for different time spans but still could not make it work :(
However, it reminds me that the device did successfully pair with my iPad once when I tested the shining keyboard example last week. Afterwards, I could no longer connect them.

@tcoppex
Copy link
Owner

tcoppex commented Apr 14, 2021

If it has been paired but did not work afterwards a cumbersome but working fix is to unpair / remove the device between each use.

@sttwarrior
Copy link
Author

Hi, for Windows and Android, it has been paired; for iOS, it cannot pair but will just disconnect. kylethorson's method is somehow un-reproducible with my devices (nano 33 BLE and iPhone Xs 14.4.2)

@kylethorson
Copy link

Hello,

So I played around with this for a while, and I found a way to get it to pair consistently with iOS devices. It was pretty simple, all that I ended up having to do was add a single line in to the Mbed_BLE_HID.cpp file. It still seems to work with other devices as well, I tested it on my android phone without issue.

void MbedBleHID::postInitialization(BLE &ble)
{
  if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
    hasError_ = true;
    return;
  }

  // Add the required BLE services for the HID-over-GATT Profile.
  services_.deviceInformation = std::make_unique<DeviceInformationService>(ble,
    kManufacturerName_.c_str(),
    kVersionString_.c_str(),    // Model Number
    kVersionString_.c_str(),    // Serial Number
    kVersionString_.c_str(),    // Hardware Revision
    kVersionString_.c_str(),    // Firmware Revision
    kVersionString_.c_str()     // Software Revision
  );
  services_.battery = std::make_unique<BatteryService>(ble, kDefaultBatteryLevel); //
  services_.hid = CreateHIDService(ble);

  // Initialized Security manager with no Man-in-the-middle (MITM) protection.
  // @note: When bonding is enabled subsequent pairing after the initial one
  //        fail, which might be a security parameters issue. 
  ble.securityManager().init(
    false,      // disable bonding.
    false,      // disable MITM protection.
    SecurityManager::IO_CAPS_NONE
  );

  // GAP events callbacks.
  Gap &gap = ble.gap();
  gap.setEventHandler(this);

  gap.manageConnectionParametersUpdateRequest(true); //<-----------------Allows pairing with iOS

  // GAP Advertising parameters.
  {
    using namespace ble;

    gap.setAdvertisingPayload(
      LEGACY_ADVERTISING_HANDLE,
      AdvertisingDataSimpleBuilder<LEGACY_ADVERTISING_MAX_SIZE>()
        .setFlags(adv_data_flags_t::BREDR_NOT_SUPPORTED 
                | adv_data_flags_t::LE_GENERAL_DISCOVERABLE
        )
        .setName(kDeviceName_.c_str(), true)
        .setAppearance(services_.hid->appearance())
        .setLocalService(GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE)
        .getAdvertisingData()
    );

    gap.setAdvertisingParameters(
      LEGACY_ADVERTISING_HANDLE,
      AdvertisingParameters(
          advertising_type_t::CONNECTABLE_UNDIRECTED, 
          adv_interval_t(millisecond_t(1000))
        )
        .setPrimaryInterval(
          conn_interval_t(millisecond_t(15)), 
          conn_interval_t(millisecond_t(50))
        )
        .setOwnAddressType(own_address_type_t::RANDOM)
        .setPhy(phy_t::LE_1M, phy_t::LE_CODED)
    );
  }

  startAdvertising();
}

@tcoppex
Copy link
Owner

tcoppex commented Apr 15, 2021

Very nice, thanks @kylethorson.

If you want to submit a PR go ahead, or I'll add the line with a new version later.

Cheers

@sttwarrior
Copy link
Author

sttwarrior commented Apr 16, 2021

Hi @kylethorson, it's amazing! I confirm this can also work on my devices, including my iPhone (iOS 14+), Windows 10, and Android 8.0+. Could I know how you found this out? I am really surprised at how simple and elegant your final solution is. I have been looking into the security side, but it seems I was totally on the wrong track of it.

@tcoppex
Copy link
Owner

tcoppex commented Apr 18, 2021

Sooo I have done some tests and it does not work that well for me on Android, at least using the Arduino IDE. Via platformio everything seem good so that's probably a versionning issue.

I'll postpone the fix until I can figure this one out.

@tcoppex
Copy link
Owner

tcoppex commented Apr 18, 2021

Ok, I've looked into it and that might do the trick, I still have weird issues from time to time though.
If you can check 366f896 (on branch bug-ios-pairing) and tell me if that work on your sides that'll be great.

Cheers

@sttwarrior
Copy link
Author

sttwarrior commented Apr 23, 2021

Hi @kylethorson @tcoppex, I found an issue about this trick. Although gap.manageConnectionParametersUpdateRequest(true); can successfully connect the device with iOS consistently across all iOS family (iPad, iPhone, and Mac), it will cause the bluetooth connection to break after about a minute on both windows and iOS. When I remove that line, the device can stably pair with Windows, but for sure, cannot connect to iOS again. Here's my hunch: probably some parameters are missing when the connection is refreshed. I have been working on it for a few days but so far haven't had any progress. It would be great if you can also check on this. Thanks!

@tcoppex
Copy link
Owner

tcoppex commented Apr 23, 2021

I've got this same issue, that's why I was reluctant to push it right away. Maybe with preprocessors to detect mac OS / iOS as temporary fix.

Thanks.

@sttwarrior
Copy link
Author

Hi, thanks for your feedback! I feel your work become even more respectful now haha. Diving into the realm of Bluetooth makes itself even more intimidating. I'll still play around it and let you know if I find anything helpful.

@bobkelley22
Copy link

Same connection problem for me. If I downgrade the Arduino Mbed OS Nano Boards Board Manager to Version 3.0.1 then it connects and holds.

@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

5 participants