The peripheral_nfc_pairing sample code pairs and connects, but Android shows a "Couldn't pair" message

I have been trying to use the `nrf\samples\bluetooth\peripheral_nfc_pairing` sample code on the nRF Connect SDK v3.0.2 to connect to a Samsung Galaxy A16 5G phone.

The NFC pairing seems to work, and the connection is working. However, every time the pairing is done, after 20 seconds, I get a message pop-up toast from the Android OS saying "Couldn't pair with Nordic_NFC_pairing". See the screenshot below that shows the pop-up and the bonded connected state of the nRF Connect app. I have also tried clearing the bonded devices on both the nrf5340dk and the phone, but it looks the same.

I have seen people reporting a similar issue before:

Given that the items above are all very old. I was wondering if there are any updates on this.

How do you suggest that I hide the pop-up toast message?

Parents
  • Hi Martin, 
    I'm sorry for the late response. I was on vacation last 2 weeks.
    From what I can see in the trace the link was encrypted meaning the pairing was successful. Was the connection kept after bonding or it terminated after a few seconds ? 
    I will take a closer look at the ticket next week. 

  • It never terminates. The connection is stable. I mentioned earlier that if the error doesn't appear, we would never sense that something is wrong.

    It seems like even though the whole bonding and connection is complete, the Android phone still has more procedures that are not handled.

    We may be able to go faster if you would try the sample code (on nrf5340) yourself on any Android phone and tell me if you can reproduce it, and you would be able to try different configurations.

  • Hi Martin, 
    Was it "couldn't pair" or "couldn't connect" pop up that you saw ? 


    I think the "couldn't connect" was from our nRF Connect app. I think it's the result of the "connecting to... " pop up. They may not be the same problem. 

    Do you see the "couldn't connect" when you don't use nRF Connect app ?

  • Copying from my earlier comment: All Samsung phones use the message "Couldn't pair with Nordic_NFC_pairing" and other phones use the message "Could not connect Nordic_NFC_pairing"

    Yes, I do see the pop-up when I don't have any apps open, meaning that it is coming directly from the Android OS.

  • Hello,

    Here is my explanation.

    The connection is stable. I mentioned earlier that if the error doesn't appear, we would never sense that something is wrong.

    On Android (and iOS) each app can connect to a Bluetooth device independently, even using multiple clients (BluetoothGatt objects). The system is maintaining the physical connection and provides a 'virtual' connection to each client. Disconnecting from one client does not mean terminating the connection, just closing that virtual connection. Received notification is forwarded to all clients that "listen" to the given characteristic, but each client can send and read values independently.

    When you tap a device with NFC pairing sample the Android system starts pairing. Natively, it can support number of services, like HID, FIDO and perhaps some more. To pair it needs to connect. Connection event is broadcasted to all apps, including nRF Connect, which intercepts it and creates another virtual connection of its own. It also listens to bond state changes, so the app shows "BONDING..." and "BONDED". As you say, this app (and any other that would have similar behavior) behaves as expected.

    However, the system, when pairing is complete, performs service discovery, checks that your device does not have any supported services (NFC pairing sample has only Device Information service), so it disconnects. Instead of doing it silently, it shows a toast: "Could not connect. Nordic_FC_pairing". This is incorrect and it should not have done that.

    Regarding "Coundn't pair with ...", it is either the same error, just with different wording, or the pairing fails on some phones. I wasn't able to reproduce that error yet.

  • Also, the NFC pairing sample does not allow to reconnect to the device without creating new encryption keys. Every time you tap NFC with a phone it starts a new bonding process. Instead, it would be better that with existing keys the firmware should either use direct advertising or regular and allow reconnection without the need for NFC tapping.

    This may need for unwanted consequences, e.g. failing re-pairing if bond already exists, or when trying to bond with another phone. I recommend re-flashing the device each time or making sure the bond information is erased, and "forgetting" the device, or even restarting Bluetooth, on Android before each try.

  • Thanks for the detailed description. Is there a configuration on the NFC pairing that would only do "pairing" and not start a service discovery or connection?
    Alternatively, can we simulate/fake a supported service for the Android phone so it wouldn't fail?

Reply Children
  • Hi,

    Regarding the first part - it will always start a service discovery, as the system is looking for service which it may support, like HID.

    Regartding the second part - this is a very interesting question. First of all, I would search for the code that displays the error message. I found where "Couldn't pair with ..." is sent: https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java;l=459 (and there's a listener added to BluetoothUtils that shows a Toast if the Settings app is in background).
    This one, however, is more interesting, as it shows which service is the Android looking for:
    https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Nfc/NfcNci/src/com/android/nfc/handover/BluetoothPeripheralHandover.java;l=466?q=connect_peripheral_failed 

    Seems like only for HID service, and if found, it will show a toast saying Connected (which may be better, than Cannot Connect). Try adding an empty (?) HID Service.

  • I tried adding pieces of the HIDs Keyboard sample into the NFC pairing in a way that I can see the service and its characteristics inside nrf Connect app. But sadly, the error still shows up.

    Here is my patch: 

    diff --git a/samples/bluetooth/peripheral_nfc_pairing/prj.conf b/samples/bluetooth/peripheral_nfc_pairing/prj.conf
    index ad1e05fea..e4481aa6c 100644
    --- a/samples/bluetooth/peripheral_nfc_pairing/prj.conf
    +++ b/samples/bluetooth/peripheral_nfc_pairing/prj.conf
    @@ -29,6 +29,11 @@ CONFIG_BT_SMP_SC_PAIR_ONLY=n
     CONFIG_BT_PERIPHERAL=y
     CONFIG_BT_DEVICE_NAME="Nordic_NFC_pairing"
     
    +CONFIG_BT_HIDS=y
    +CONFIG_BT_CONN_CTX=y
    +CONFIG_BT_GATT_UUID16_POOL_SIZE=40
    +CONFIG_BT_GATT_CHRC_POOL_SIZE=20
    +
     CONFIG_BT_DIS=y
     CONFIG_BT_DIS_MANUF_NAME=y
     CONFIG_BT_DIS_MANUF_NAME_STR="NordicSemiconductor"
    diff --git a/samples/bluetooth/peripheral_nfc_pairing/src/main.c b/samples/bluetooth/peripheral_nfc_pairing/src/main.c
    index e05510a03..1378cbb79 100644
    --- a/samples/bluetooth/peripheral_nfc_pairing/src/main.c
    +++ b/samples/bluetooth/peripheral_nfc_pairing/src/main.c
    @@ -10,6 +10,7 @@
     #include <zephyr/bluetooth/conn.h>
     #include <zephyr/bluetooth/uuid.h>
     #include <zephyr/bluetooth/gatt.h>
    +#include <bluetooth/services/hids.h>
     
     #include <dk_buttons_and_leds.h>
     
    @@ -56,9 +57,23 @@ K_MSGQ_DEFINE(bonds_queue,
     	      CONFIG_BT_MAX_PAIRED,
     	      4);
     
    +/* HIDS instance. */
    +#define OUTPUT_REPORT_MAX_LEN  1
    +#define INPUT_REPORT_KEYS_MAX_LEN (1 + 1 + 6)
    +#define BASE_USB_HID_SPEC_VERSION 0x0101
    +#define INPUT_REP_KEYS_IDX     0
    +#define INPUT_REP_KEYS_REF_ID  0
    +#define OUTPUT_REP_KEYS_IDX    0
    +#define OUTPUT_REP_KEYS_REF_ID 0
    +BT_HIDS_DEF(hids_obj,
    +	    OUTPUT_REPORT_MAX_LEN,
    +	    INPUT_REPORT_KEYS_MAX_LEN);
    +
     static const struct bt_data ad[] = {
     	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
     	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    +	BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HIDS_VAL),
    +					  BT_UUID_16_ENCODE(BT_UUID_BAS_VAL))
     };
     
     static struct k_poll_signal pair_signal;
    @@ -362,6 +377,124 @@ static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
     	.pairing_failed = pairing_failed
     };
     
    +static void hids_outp_rep_handler(struct bt_hids_rep *rep,
    +				  struct bt_conn *conn,
    +				  bool write)
    +{
    +	if (!write) {
    +		printk("Output report read\n");
    +		return;
    +	};
    +	printk("Output report has been received \n");
    +}
    +
    +static void hids_boot_kb_outp_rep_handler(struct bt_hids_rep *rep,
    +					  struct bt_conn *conn,
    +					  bool write)
    +{
    +	if (!write) {
    +		printk("Output report read\n");
    +		return;
    +	};
    +	printk("Boot Keyboard Output report has been received \n");
    +}
    +
    +static void hids_pm_evt_handler(enum bt_hids_pm_evt evt,
    +				struct bt_conn *conn)
    +{
    +	printk("HIDs event received %i\n", evt);
    +}
    +
    +static void hid_init(void)
    +{
    +	int err;
    +	struct bt_hids_init_param    hids_init_obj = { 0 };
    +	struct bt_hids_inp_rep       *hids_inp_rep;
    +	struct bt_hids_outp_feat_rep *hids_outp_rep;
    +
    +	static const uint8_t report_map[] = {
    +		0x05, 0x01,       /* Usage Page (Generic Desktop) */
    +		0x09, 0x06,       /* Usage (Keyboard) */
    +		0xA1, 0x01,       /* Collection (Application) */
    +
    +		/* Keys */
    +#if INPUT_REP_KEYS_REF_ID
    +		0x85, INPUT_REP_KEYS_REF_ID,
    +#endif
    +		0x05, 0x07,       /* Usage Page (Key Codes) */
    +		0x19, 0xe0,       /* Usage Minimum (224) */
    +		0x29, 0xe7,       /* Usage Maximum (231) */
    +		0x15, 0x00,       /* Logical Minimum (0) */
    +		0x25, 0x01,       /* Logical Maximum (1) */
    +		0x75, 0x01,       /* Report Size (1) */
    +		0x95, 0x08,       /* Report Count (8) */
    +		0x81, 0x02,       /* Input (Data, Variable, Absolute) */
    +
    +		0x95, 0x01,       /* Report Count (1) */
    +		0x75, 0x08,       /* Report Size (8) */
    +		0x81, 0x01,       /* Input (Constant) reserved byte(1) */
    +
    +		0x95, 0x06,       /* Report Count (6) */
    +		0x75, 0x08,       /* Report Size (8) */
    +		0x15, 0x00,       /* Logical Minimum (0) */
    +		0x25, 0x65,       /* Logical Maximum (101) */
    +		0x05, 0x07,       /* Usage Page (Key codes) */
    +		0x19, 0x00,       /* Usage Minimum (0) */
    +		0x29, 0x65,       /* Usage Maximum (101) */
    +		0x81, 0x00,       /* Input (Data, Array) Key array(6 bytes) */
    +
    +		/* LED */
    +#if OUTPUT_REP_KEYS_REF_ID
    +		0x85, OUTPUT_REP_KEYS_REF_ID,
    +#endif
    +		0x95, 0x05,       /* Report Count (5) */
    +		0x75, 0x01,       /* Report Size (1) */
    +		0x05, 0x08,       /* Usage Page (Page# for LEDs) */
    +		0x19, 0x01,       /* Usage Minimum (1) */
    +		0x29, 0x05,       /* Usage Maximum (5) */
    +		0x91, 0x02,       /* Output (Data, Variable, Absolute), */
    +				  /* Led report */
    +		0x95, 0x01,       /* Report Count (1) */
    +		0x75, 0x03,       /* Report Size (3) */
    +		0x91, 0x01,       /* Output (Data, Variable, Absolute), */
    +				  /* Led report padding */
    +
    +		0xC0              /* End Collection (Application) */
    +	};
    +
    +	hids_init_obj.rep_map.data = report_map;
    +	hids_init_obj.rep_map.size = sizeof(report_map);
    +
    +	hids_init_obj.info.bcd_hid = BASE_USB_HID_SPEC_VERSION;
    +	hids_init_obj.info.b_country_code = 0x00;
    +	hids_init_obj.info.flags = (BT_HIDS_REMOTE_WAKE |
    +				    BT_HIDS_NORMALLY_CONNECTABLE);
    +
    +	hids_inp_rep =
    +		&hids_init_obj.inp_rep_group_init.reports[INPUT_REP_KEYS_IDX];
    +	hids_inp_rep->size = INPUT_REPORT_KEYS_MAX_LEN;
    +	hids_inp_rep->id = INPUT_REP_KEYS_REF_ID;
    +	hids_init_obj.inp_rep_group_init.cnt++;
    +
    +	hids_outp_rep =
    +		&hids_init_obj.outp_rep_group_init.reports[OUTPUT_REP_KEYS_IDX];
    +	hids_outp_rep->size = OUTPUT_REPORT_MAX_LEN;
    +	hids_outp_rep->id = OUTPUT_REP_KEYS_REF_ID;
    +	hids_outp_rep->handler = hids_outp_rep_handler;
    +	hids_init_obj.outp_rep_group_init.cnt++;
    +
    +	hids_init_obj.is_kb = true;
    +	hids_init_obj.boot_kb_outp_rep_handler = hids_boot_kb_outp_rep_handler;
    +	hids_init_obj.pm_evt_handler = hids_pm_evt_handler;
    +
    +	err = bt_hids_init(&hids_obj, &hids_init_obj);
    +	if (err) {
    +		printk("Failed to initialize HIDs\n");
    +	} else {
    +		printk("Initialized HIDs\n");
    +	}
    +}
    +
     static void connected(struct bt_conn *conn, uint8_t err)
     {
     	char addr[BT_ADDR_LE_STR_LEN];
    @@ -385,6 +518,14 @@ static void connected(struct bt_conn *conn, uint8_t err)
     	printk("Connected %s\n", addr);
     	dk_set_led_on(CON_STATUS_LED);
     
    +	err = bt_hids_connected(&hids_obj, conn);
    +	if (err) {
    +		printk("Failed to notify HID service about connection\n");
    +		return;
    +	} else {
    +		printk("Notified HID service about connection\n");
    +	}
    +
     	if (conn_cnt < CONFIG_BT_MAX_CONN) {
     		advertising_start();
     	}
    @@ -737,6 +878,8 @@ int main(void)
     		return 0;
     	}
     
    +	hid_init();
    +
     	err = bt_enable(NULL);
     	if (err) {
     		printk("Bluetooth init failed (err %d)\n", err);
    

Related