I have an external device. After connecting it to the central device, I found that the Bluetooth service of my external device couldn't be enabled properly. When I checked the log of the central device, I discovered an ATT timeout error. The log is approximately as follows:
[02:30:52.146,911] <inf> ble_server: detect device. [02:30:52.146,911] <inf> ble_server: stop scan. [02:30:52.147,308] <inf> ble_server: [7D]: Agree to connect. [02:30:52.147,338] <inf> ble_server: [7D]: ready connect. [02:30:52.148,101] <inf> ble_server: Remove device to wait connect list. [02:30:52.254,913] <inf> ble_server: [7D]: Device connected. [02:30:59.401,245] <inf> ble_server: Remove device to timeout list. [02:31:22.255,401] <err> bt_att: ATT Timeout for device FB:2A:BB:70:58:87 (random). Disconnecting... [02:31:22.259,857] <err> ble_server: [ble_server_smf_get_mtu_run]: MTU change error. [02:31:22.259,887] <err> ble_server: SMF ERROR CHECK. [02:31:22.270,080] <inf> ble_server: start scan. [02:31:22.355,834] <inf> ble_server: [disconnected] Disconnect [7D] success. [02:31:22.357,788] <inf> ble_server: [7D]: device has disconnected [02:31:22.357,849] <wrn> ble_server: [7D]: Device is not in connecting or connected. [02:31:23.188,323] <inf> ble_server: Add device to wait connect list.
#include "lib/ble/ble_client.h"
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/services/nus.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/hci_vs.h>
static uint8_t device_id[8];
#if defined(CONFIG_CUSTOM_MANUFACTURER_DATA)
static const uint8_t manu_data[] = {
CONFIG_MANUFACTURER_DATA_0,
CONFIG_MANUFACTURER_DATA_1,
CONFIG_MANUFACTURER_DATA_2,
CONFIG_MANUFACTURER_DATA_3,
CONFIG_MANUFACTURER_DATA_4,
CONFIG_MANUFACTURER_DATA_5,
CONFIG_MANUFACTURER_DATA_6,
};
#else
static const uint8_t manu_data[] = {
CONFIG_CLIENT_MANUFACTURER_DATA_0,
CONFIG_CLIENT_MANUFACTURER_DATA_1,
CONFIG_CLIENT_MANUFACTURER_DATA_2,
CONFIG_CLIENT_MANUFACTURER_DATA_3,
CONFIG_CLIENT_MANUFACTURER_DATA_4,
CONFIG_CLIENT_MANUFACTURER_DATA_5,
CONFIG_CLIENT_MANUFACTURER_DATA_6,
};
#endif
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA(BT_DATA_MANUFACTURER_DATA, &manu_data, sizeof(manu_data)),
BT_DATA(BT_DATA_DEVICE_ID, &device_id, sizeof(device_id)),
BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_SRV_VAL),
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};
enum _LIB_NAME_(state)
{
_LIB_NAME_CAP_(STATE_BLE_NUS_INIT),
};
static struct __maybe_unused _LIB_NAME_(instance)
{
atomic_t state;
struct bt_le_ext_adv *adv;
struct bt_conn *conn;
struct _LIB_NAME_(config) * config;
} _LIB_NAME_(inst);
static void connected(struct bt_conn *conn, uint8_t conn_err)
{
int err;
if (conn_err)
{
printk("Connection failed, err 0x%02x \n", conn_err);
_LIB_NAME_(inst).conn = NULL;
return;
}
#if defined(CONFIG_BT_CTLR_PHY_CODED)
const struct bt_conn_le_phy_param preferred_phy = {
.options = BT_CONN_LE_PHY_OPT_CODED_S8,
.pref_rx_phy = BT_GAP_LE_PHY_CODED,
.pref_tx_phy = BT_GAP_LE_PHY_CODED,
};
err = bt_conn_le_phy_update(conn, &preferred_phy);
if (err)
{
printk("bt_conn_le_phy_update() returned %d", err);
}
#endif
_LIB_NAME_(inst).conn = conn;
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
if(_LIB_NAME_(inst).conn != conn)
{
return;
}
_LIB_NAME_(inst).conn = NULL;
if (_LIB_NAME_(inst).config != NULL && _LIB_NAME_(inst).config->callback.connected != NULL)
{
_LIB_NAME_(inst).config->callback.connected(false);
}
}
static void le_phy_updated(struct bt_conn *conn, struct bt_conn_le_phy_info *param)
{
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.le_phy_updated = le_phy_updated,
};
static void notif_enabled(bool enabled, void *ctx)
{
ARG_UNUSED(ctx);
if (_LIB_NAME_(inst).config != NULL && _LIB_NAME_(inst).config->callback.connected != NULL)
{
_LIB_NAME_(inst).config->callback.connected(enabled);
}
}
static void received(struct bt_conn *conn, const void *data, uint16_t len, void *ctx)
{
ARG_UNUSED(conn);
ARG_UNUSED(ctx);
if (_LIB_NAME_(inst).config != NULL && _LIB_NAME_(inst).config->callback.receive != NULL)
{
_LIB_NAME_(inst).config->callback.receive(data, len);
}
}
struct bt_nus_cb nus_listener = {
.notif_enabled = notif_enabled,
.received = received,
};
_API_(int) _LIB_NAME_(set_device_config)(struct _LIB_NAME_(config) * config)
{
int err;
if (config != NULL)
{
_LIB_NAME_(inst).config = config;
}
device_id[0] = (uint8_t)((NRF_FICR->DEVICEID[1] >> 24) & 0xFF);
device_id[1] = (uint8_t)((NRF_FICR->DEVICEID[1] >> 16) & 0xFF);
device_id[2] = (uint8_t)((NRF_FICR->DEVICEID[1] >> 8) & 0xFF);
device_id[3] = (uint8_t)((NRF_FICR->DEVICEID[1] >> 00) & 0xFF);
device_id[4] = (uint8_t)((NRF_FICR->DEVICEID[0] >> 24) & 0xFF);
device_id[5] = (uint8_t)((NRF_FICR->DEVICEID[0] >> 16) & 0xFF);
device_id[6] = (uint8_t)((NRF_FICR->DEVICEID[0] >> 8) & 0xFF);
device_id[7] = (uint8_t)((NRF_FICR->DEVICEID[0] >> 00) & 0xFF);
if (atomic_test_and_set_bit(&_LIB_NAME_(inst).state, _LIB_NAME_CAP_(STATE_BLE_NUS_INIT)))
{
return -EALREADY;
}
err = bt_nus_cb_register(&nus_listener, NULL);
if (err)
{
printk("Failed to register NUS callback: %d\n", err);
atomic_clear_bit(&_LIB_NAME_(inst).state, _LIB_NAME_CAP_(STATE_BLE_NUS_INIT));
return err;
}
return 0;
}
_API_(int) _LIB_NAME_(send_data)(const uint8_t *data, uint16_t len)
{
return bt_nus_send(_LIB_NAME_(inst).conn, data, len);
}
_API_(int) _LIB_NAME_(init)()
{
int err;
err = bt_enable(NULL);
if (err)
{
return err;
}
#if defined(CONFIG_BT_CTLR_PHY_CODED)
struct bt_le_adv_param param =
BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE |
BT_LE_ADV_OPT_EXT_ADV |
BT_LE_ADV_OPT_CODED,
BT_GAP_ADV_FAST_INT_MIN_2,
BT_GAP_ADV_FAST_INT_MAX_2,
NULL);
#elif defined(CONFIG_BT_EXT_ADV)
struct bt_le_adv_param param =
BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_CONNECTABLE |
BT_LE_ADV_OPT_EXT_ADV,
BT_GAP_ADV_FAST_INT_MIN_1,
BT_GAP_ADV_FAST_INT_MAX_1,
NULL);
#endif
err = bt_le_ext_adv_create(¶m, NULL, &_LIB_NAME_(inst).adv);
if (err)
{
printk("Failed to create Coded PHY extended advertising set (err %d)\n", err);
return err;
}
err = bt_le_ext_adv_set_data(_LIB_NAME_(inst).adv, ad, ARRAY_SIZE(ad), NULL, 0);
if (err)
{
printk("Failed to set extended advertising data (err %d)\n", err);
return err;
}
return 0;
}
_API_(int) _LIB_NAME_(uninit)()
{
_LIB_NAME_(disconnect)();
return bt_disable();
}
_API_(int) _LIB_NAME_(adv_start)()
{
int err = bt_le_ext_adv_start(_LIB_NAME_(inst).adv, BT_LE_EXT_ADV_START_DEFAULT);
if (err)
{
printk("Failed to start advertising set (err %d)\n", err);
return err;
}
return 0;
}
_API_(int) _LIB_NAME_(adv_stop)()
{
int err = bt_le_ext_adv_stop(_LIB_NAME_(inst).adv);
if (err)
{
printk("Failed to stop advertising set (err %d)\n", err);
return err;
}
return 0;
}
_API_(void) _LIB_NAME_(disconnect)(void)
{
if (_LIB_NAME_(inst).conn != NULL)
bt_conn_disconnect(_LIB_NAME_(inst).conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
bt_le_ext_adv_stop(_LIB_NAME_(inst).adv);
}
Among them, ble_client.c is the code related to BLE for my peripheral device. Since my peripheral device doesn't have a Debug interface yet, I would like to ask you what the reason is.
Under normal circumstances, my peripheral devices have a timer that maintains the BLE communication time. If there is no connection established or the communication times out, the BLE connection will be automatically closed and wait for the next time period to re-enable the BLE. However, when there is an ATT timeout, the BLE does not work properly. It is worth noting that this situation occurs more severely when my BLE interference is particularly significant (such as when there are too many peripheral devices attempting to establish connections with the central device simultaneously). This situation becomes less frequent only when the number of peripheral devices is reduced to an appropriate value.