Peripheral is connected to two Centrals, each with two Gatt Services, occurred mtu exchange fail.

Hello,

I am using three nrf52840 DKs to test sending gatt notify data. They are one peripheral and two central.

When they each have only one Gatt Customer Service, peripheral can connect to both centrals at the same time and successfully send gatt notify data to them.

But when they both have two Gatt Customer Services, when peripheral connects to the second central, the first central will crash, and the second central will have mtu exchange fail (-14).

Is it possible for one peripheral to connect to two centrals at the same time, one central to register two Gatt Services, and then send gatt_notify at the same time?

  • Hi,

    Multiple connections in the peripheral role is possible and supported, but then your application needs to properly support it. So you need to keep track of the connections, and make all connection related API calls with the correct connection object (bt_conn struct) which is typically the first argument, etc. As you see something happen on one link when you do something on the other link, that indocate to me that perhaps you do not have a clean handling of the connections in your application?

  • Thank you for your reply.

    I don’t quite understand what you mean. Do you mean that some steps were not completed when I connected?

    These are what I do when connected:

    void connected(struct bt_conn *conn, uint8_t err)
    {
    	LOG_INF("connected");
    	char addr[BT_ADDR_LE_STR_LEN];
    	static struct bt_gatt_exchange_params exchange_params;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (err != 0) {
    		LOG_INF("Failed to connect to %s (%u)", addr, err);
    		return;
    	}
    
    	LOG_INF("Connected to %s", addr);
    
    	exchange_params.func = exchange_func;
    	err = bt_gatt_exchange_mtu(conn, &exchange_params);
    	if (err) {
    		LOG_INF("MTU exchange failed (err %d)", err);
    	}
    	memcpy(&uuid, &test_uuid.uuid, sizeof(uuid));
    	discover_params.uuid = &uuid.uuid;
        discover_params.func = discover_func;
    	discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
    	discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
    	discover_params.type = BT_GATT_DISCOVER_PRIMARY;
        err = bt_gatt_discover(conn,&discover_params);
    	if (err) {
    		LOG_ERR("Discover failed(err %d)\n", err);
    		return;
    	}
    #if CONFIG_TWO_GATT_SERVICE
    	memcpy(&uuid_2, &test_uuid_2.uuid, sizeof(uuid_2));
    	discover_params_2.uuid = &uuid_2.uuid;
        discover_params_2.func = discover_func_2;
    	discover_params_2.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
    	discover_params_2.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
    	discover_params_2.type = BT_GATT_DISCOVER_PRIMARY;
        err = bt_gatt_discover(conn,&discover_params_2);
    	if (err) {
    		LOG_ERR("Discover failed(err %d)\n", err);
    		return;
    	}
    #endif
    }

    If I set CONFIG_TWO_GATT_SERVICE to n, peripheral can successfully connect to two centrals.

    But if I set CONFIG_TWO_GATT_SERVICE to y, the error I mentioned above will occur when peripheral connects to the second central.

  • Hi,

    I don't know anything more than you have written, so the reason for my initial question was to ask if you handle multiple connections properly in your peripheral application (as most smaples are only designed for a single connection).

    The code snippet you have shown here is that from the central or peripheral side? (I ask as a GATT client can be present on both)? And do you have logs from both sentrals and the peripheral you can share that may shed some light on this? For instance, what happens on the first central when it "crashes"? And what happens on the peripheral side? Knowing more about the implemetnation would be usefull as well.

  • The code I shown is from the peripheral side.

    I added CONFIG_BT_MAX_CONN=2 and CONFIG_BT_MAX_PAIRED=2 to the peripheral application so that it can connect to two centrals at the same time.

    After the peripheral is connected to the central, it will continuously transmit data to the central, and the central will also output the received data to the log.

    When the second central device connected, the first central device stopped outputting logs and didn't seem to be doing anything, so I thought it "crashes".

    At this time, peripheral does not output any special message.

    I will share the detailed logs and code next week.

  • Hello,

    Here are the logs of each of the three devices when the peripheral is connected to the first central and transmits data stably, and the second central is powered on and connected.

    The peripheral:

    [00:00:55.102,142] <inf> main: Connection 1 Gatt Notify Service 2 return:0
    [00:00:55.109,039] <inf> main: Connection 1 Gatt Notify Service 1 return:0
    [00:00:55.109,130] <inf> main: Connection 1 Gatt Notify Service 2 return:0
    [00:00:55.116,058] <inf> main: Connection 1 Gatt Notify Service 1 return:0
    [00:00:55.116,149] <inf> main: Connection 1 Gatt Notify Service 2 return:0
    [00:00:55.123,107] <inf> main: Connection 1 Gatt Notify Service 1 return:0
    [00:00:55.123,199] <inf> main: Connection 1 Gatt Notify Service 2 return:0
    [00:00:55.130,096] <inf> main: Connection 1 Gatt Notify Service 1 return:0
    [00:00:55.130,218] <inf> main: Connection 1 Gatt Notify Service 2 return:0
    [00:00:55.137,115] <inf> main: Connection 1 Gatt Notify Service 1 return:0
    [00:00:55.137,207] <inf> main: Connection 1 Gatt Notify Service 2 return:0
    [00:00:55.144,226] <inf> main: Connection 1 Gatt Notify Service 1 return:0
    [00:00:55.144,317] <inf> main: Connection 1 Gatt Notify Service 2 return:0
    [00:00:55.151,123] <inf> main: Connection 1 Gatt Notify Service 1 return:0
    [00:00:55.151,184] <wrn> bt_att: Unable to allocate ATT TX meta
    [00:00:55.151,184] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.151,214] <inf> main: Connection 1 Gatt Notify Service 2 return:-12
    [00:00:55.157,348] <inf> main: connected
    [00:00:55.157,440] <inf> main: Connected to DD:09:1C:C5:87:68 (random)
    [00:00:55.158,416] <wrn> bt_att: Unable to allocate ATT TX meta
    [00:00:55.158,447] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.158,447] <inf> main: Connection 1 Gatt Notify Service 1 return:-12
    [00:00:55.158,477] <wrn> bt_att: Unable to allocate ATT TX meta
    [00:00:55.158,508] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.158,538] <inf> main: Connection 1 Gatt Notify Service 2 return:-12
    [00:00:55.158,538] <wrn> bt_att: No ATT channel for MTU 243
    [00:00:55.158,569] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.158,599] <inf> main: Connection 2 Gatt Notify Service 1 return:-12
    [00:00:55.158,630] <wrn> bt_att: No ATT channel for MTU 243
    [00:00:55.158,630] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.158,630] <inf> main: Connection 2 Gatt Notify Service 2 return:-12
    [00:00:55.165,100] <wrn> bt_att: Unable to allocate ATT TX meta
    [00:00:55.165,100] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.165,130] <inf> main: Connection 1 Gatt Notify Service 1 return:-12
    [00:00:55.165,161] <wrn> bt_att: Unable to allocate ATT TX meta
    [00:00:55.165,191] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.165,191] <inf> main: Connection 1 Gatt Notify Service 2 return:-12
    [00:00:55.165,222] <wrn> bt_att: No ATT channel for MTU 243
    [00:00:55.165,252] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.165,252] <inf> main: Connection 2 Gatt Notify Service 1 return:-12
    [00:00:55.165,283] <wrn> bt_att: No ATT channel for MTU 243
    [00:00:55.165,283] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.165,313] <inf> main: Connection 2 Gatt Notify Service 2 return:-12
    [00:00:55.172,119] <wrn> bt_att: Unable to allocate ATT TX meta
    [00:00:55.172,149] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.172,149] <inf> main: Connection 1 Gatt Notify Service 1 return:-12
    [00:00:55.172,180] <wrn> bt_att: Unable to allocate ATT TX meta
    [00:00:55.172,210] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.172,210] <inf> main: Connection 1 Gatt Notify Service 2 return:-12
    [00:00:55.172,241] <wrn> bt_att: No ATT channel for MTU 243
    [00:00:55.172,271] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.172,271] <inf> main: Connection 2 Gatt Notify Service 1 return:-12
    [00:00:55.172,302] <wrn> bt_att: No ATT channel for MTU 243
    [00:00:55.172,302] <wrn> bt_gatt: No buffer available to send notification
    [00:00:55.172,332] <inf> main: Connection 2 Gatt Notify Service 2 return:-12

    At this time, peripheral does not output any special message.

    Sorry I said it wrong here. When the second central connection was made, the peripheral had an "Unable to allocate ATT TX meta" error and could no longer successfully send any data.

    The central 1(The first connected device):

    [00:01:31.220,916] <inf> central_test: connected
    [00:01:31.221,008] <inf> central_test: Connected to C3:1B:EF:44:AA:E6 (random)
    [00:01:35.222,564] <inf> central_test: MTU exchange done
    
    [00:01:40.222,656] <inf> central_test: [ATTRIBUTE] Service 1 handle 16
    [00:01:40.222,839] <inf> central_test: Discover Service
    [0
    [00:00:09.227,386] <inf> central_test: Discover Service
    [00:00:11.227,233] <inf> central_test: [ATTRIBUTE] Service 2 handle 20
    [00:00:11.227,325] <inf> central_test: Discover Service
    [00:00:12.229,949] <inf> central_test: [ATTRIBUTE] Service 1 handle 17
    [00:00:12.230,041] <inf> central_test: Discover Character
    [00:00:15.228,424] <inf> central_test: [ATTRIBUTE] Service 2 handle 21
    [00:00:15.228,515] <inf> central_test: Discover Character
    [00:00:16.229,827] <inf> central_test: [ATTRIBUTE] Service 1 handle 19
    [00:00:16.229,919] <inf> central_test: [SUBSCRIBED]
    
    [00:00:17.228,057] <inf> central_test: [NOTIFICATION] Service 1 data ff ff length 240
    
    [00:00:17.229,766] <inf> central_test: [ATTRIBUTE] Service 2 handle 23
    [00:00:17.229,888] <inf> central_test: [SUBSCRIBED]
    
    [00:00:18.228,057] <inf> central_test: [NOTIFICATION] Service 1 data ff ff length 240
    
    [00:00:18.229,309] <inf> central_test: [NOTIFICATION] Service 2 data ff ff length 240
    
    [00:00:19.228,057] <inf> central_test: [NOTIFICATION] Service 1 data ff ff length 240
    
    [00:00:19.229,309] <inf> central_test: [NOTIFICATION] Service 2 data ff ff length 240
    
    [00:00:19.235,382] <inf> central_test: [NOTIFICATION] Service 1 data ff ff length 240
    
    [00:00:19.236,816] <inf> central_test: [NOTIFICATION] Service 2 data ff ff length 240
    
    [00:00:19.242,889] <inf> central_test: [NOTIFICATION] Service 1 data ff ff length 240
    
    [00:00:19.244,323] <inf> central_test: [NOTIFICATION] Service 2 data ff ff length 240

    It stopped outputting logs when the second central is connected to the peripheral.

    Now I think it stopped outputting logs because it didn't receive data rather than "crashes".

    The central 2(The second connected device):

    [00:00:30.148,956] <err> bt_att: ATT Timeout for device C3:1B:EF:44:AA:E6 (random)
    [00:00:30.149,017] <inf> central_test: MTU exchange failed (err 14)
    
    [00:00:30.149,017] <inf> central_test: Discover complete
    [00:00:30.149,047] <inf> central_test: Discover complete

    It seems that an exchange error occurred while connecting.

    The peripheral and central do the same thing when connected. The following is the code.

    void connected(struct bt_conn *conn, uint8_t err)
    {
    	LOG_INF("connected");
    	connected_count++;
    	if(connected_count == 1){
    		app_conn1 = conn;
    	}else if(connected_count == 2){
    		app_conn2 = conn;
    	}
    	char addr[BT_ADDR_LE_STR_LEN];
    	static struct bt_gatt_exchange_params exchange_params;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (err != 0) {
    		LOG_INF("Failed to connect to %s (%u)", addr, err);
            bt_conn_unref(conn_connecting);
    		conn_connecting = NULL;
            start_scan();
    		return;
    	}
    	LOG_INF("Connected to %s", addr);
    
    	exchange_params.func = exchange_func;
    	err = bt_gatt_exchange_mtu(conn, &exchange_params);
    	if (err) {
    		LOG_INF("MTU exchange failed (err %d)", err);
    	}
     
    	if(conn == conn_connecting){
    		memcpy(&uuid, &test_uuid.uuid, sizeof(uuid));
    		discover_params.uuid = &uuid.uuid;
        	discover_params.func = discover_func;
    		discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
    		discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
    		discover_params.type = BT_GATT_DISCOVER_PRIMARY;
        	err = bt_gatt_discover(conn,&discover_params);
    		if (err) {
    			LOG_ERR("Discover failed(err %d)\n", err);
    			return;
    		}
    #if CONFIG_TWO_GATT_SERVICE
    		memcpy(&uuid_2, &test_uuid_2.uuid, sizeof(uuid_2));
    		discover_params_2.uuid = &uuid_2.uuid;
        	discover_params_2.func = discover_func_2;
    		discover_params_2.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
    		discover_params_2.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
    		discover_params_2.type = BT_GATT_DISCOVER_PRIMARY;
        	err = bt_gatt_discover(conn,&discover_params_2);
    		if (err) {
    			LOG_ERR("Discover failed(err %d)\n", err);
    			return;
    		}
    #endif
    	}
    }

    static uint8_t notify_func(struct bt_conn *conn,
    		struct bt_gatt_subscribe_params *params,
    		const void *data, uint16_t length)
    {
    	uint8_t value[200];
    	memcpy(value,data,length);
    	if (!data) {
    		LOG_INF("[UNSUBSCRIBED]\n");
    		connected_flag = 0;
    		return BT_GATT_ITER_STOP;
    	}
    	LOG_INF("[NOTIFICATION] data %x %x length %u\n", value[0],value[1], length);
    	connected_flag = 1;
    	return BT_GATT_ITER_CONTINUE;
    }
    
    static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
    			     struct bt_gatt_discover_params *params)
    {
        int err;
        if (!attr) {
    		LOG_INF("Discover complete");
    		(void)memset(params, 0, sizeof(*params));
    		return BT_GATT_ITER_STOP;
    	}
        LOG_INF("[ATTRIBUTE] handle %u", attr->handle);
        if (!bt_uuid_cmp(discover_params.uuid, &test_uuid.uuid)) {
    		memcpy(&uuid, &test_chrc_uuid.uuid, sizeof(uuid));
    		discover_params.uuid = &uuid.uuid;
    		discover_params.start_handle = attr->handle + 1;
    		discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
    
    		err = bt_gatt_discover(conn, &discover_params);
    		LOG_INF("Discover Service");
    		if (err) {
    			LOG_INF("Discover failed (err %d)\n", err);
    		}
    	} else if (!bt_uuid_cmp(discover_params.uuid,&test_chrc_uuid.uuid)) {
    		memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
    		discover_params.uuid = &uuid.uuid;
    		discover_params.start_handle = attr->handle + 2;
    		discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
    		subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
    		err = bt_gatt_discover(conn, &discover_params);
    		LOG_INF("Discover Character");
    		if (err) {
    			LOG_INF("Discover failed (err %d)\n", err);
    		}
    	} else if (bt_uuid_cmp(discover_params.uuid, &test_chrc_uuid.uuid)){
    		subscribe_params.notify = notify_func;
    		subscribe_params.value = BT_GATT_CCC_NOTIFY;
    		subscribe_params.ccc_handle = attr->handle;
    		err = bt_gatt_subscribe(conn, &subscribe_params);
    		if (err && err != -EALREADY) {
    			LOG_INF("Subscribe failed (err %d)\n", err);
    		} else {
    			LOG_INF("[SUBSCRIBED]\n");
    		}
    	}
    	return BT_GATT_ITER_STOP;
    }
    
    #if CONFIG_TWO_GATT_SERVICE
    static uint8_t discover_func_2(struct bt_conn *conn, const struct bt_gatt_attr *attr,
    			     struct bt_gatt_discover_params *params)
    {
        int err;
        if (!attr) {
    		LOG_INF("Discover complete");
    		(void)memset(params, 0, sizeof(*params));
    		return BT_GATT_ITER_STOP;
    	}
        LOG_INF("[ATTRIBUTE] handle %u", attr->handle);
        if (!bt_uuid_cmp(discover_params_2.uuid, &test_uuid_2.uuid)) {
    		memcpy(&uuid_2, &test_chrc_uuid_2.uuid, sizeof(uuid_2));
    		discover_params_2.uuid = &uuid_2.uuid;
    		discover_params_2.start_handle = attr->handle + 1;
    		discover_params_2.type = BT_GATT_DISCOVER_CHARACTERISTIC;
    
    		err = bt_gatt_discover(conn, &discover_params_2);
    		LOG_INF("Discover Service");
    		if (err) {
    			LOG_INF("Discover failed (err %d)\n", err);
    		}
    	} else if (!bt_uuid_cmp(discover_params_2.uuid,&test_chrc_uuid_2.uuid)) {
    		memcpy(&uuid_2, BT_UUID_GATT_CCC, sizeof(uuid_2));
    		discover_params_2.uuid = &uuid_2.uuid;
    		discover_params_2.start_handle = attr->handle + 2;
    		discover_params_2.type = BT_GATT_DISCOVER_DESCRIPTOR;
    		subscribe_params_2.value_handle = bt_gatt_attr_value_handle(attr);
    
    		err = bt_gatt_discover(conn, &discover_params_2);
    		LOG_INF("Discover Character");
    		if (err) {
    			LOG_INF("Discover failed (err %d)\n", err);
    		}
    	} else if (bt_uuid_cmp(discover_params_2.uuid, &test_chrc_uuid_2.uuid)){
    		subscribe_params_2.notify = notify_func;
    		subscribe_params_2.value = BT_GATT_CCC_NOTIFY;
    		subscribe_params_2.ccc_handle = attr->handle;
    		err = bt_gatt_subscribe(conn, &subscribe_params_2);
    		if (err && err != -EALREADY) {
    			LOG_INF("Subscribe failed (err %d)\n", err);
    		} else {
    			LOG_INF("[SUBSCRIBED]\n");
    			connected_flag = 1;
    		}
    	}
    	return BT_GATT_ITER_STOP;
    }
    #endif

    Is it because two services are registered at the same time and connected to two central devices at the same time, causing the connection to be unstable?

Related