Skip to main content

Seeed Studio XIAO nRF54L15 Sense BLE 使用指南

以下示例代码专为 PlatformIO 设计,但也兼容 nRF Connect SDK。

tip

基于 VS Code,如果您想在 nRF Connect SDK 上使用以下案例,请参考提供的连接,添加 app.overlay 文件并修改 prj.conf 中的内容

XIAO nRF54L15 添加 overlay 文件并修改 conf 文件

BLE 观察者

一个演示蓝牙低功耗观察者角色功能的简单应用程序。该应用程序将定期扫描附近的设备。如果发现任何设备,将设备地址、RSSI 值、广播类型和广播数据长度打印到控制台。

如果使用的蓝牙低功耗控制器支持扩展扫描,您可以在项目配置文件 prj.conf 中启用 CONFIG_BT_EXT_ADV。有关更多详细信息,请参考项目配置文件。

XIAO nRF54L15 Observer

扫描结果

添加 XIAO nRF54L15 开发板

要将 XIAO nRF54L15(Sense) 开发板添加到 NCS (nRF Connect SDK),您可以参考 Seeed Studio Wiki 上的"入门指南"。该指南将提供详细的操作说明。

BLE 观察者代码

Main.c

#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/bluetooth.h>

int observer_start(void);

int main(void)
{
int err;

printk("Starting Observer Demo\n");

err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return 0;
}

(void)observer_start();

printk("Exiting %s thread.\n", __func__);
return 0;
}
note
  • main.c: 初始化蓝牙子系统并启动观察者演示。

  • bt_enable(NULL): 初始化蓝牙子系统。

  • observer_start(): 调用启动观察者的函数。

  • printk("Exiting %s thread.\n", __func__): 在主函数退出时打印消息。

observer.c

#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>

#define NAME_LEN 30

static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
struct net_buf_simple *ad)
{
char addr_str[BT_ADDR_LE_STR_LEN];

bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
printk("Device found: %s (RSSI %d), type %u, AD data len %u\n",
addr_str, rssi, type, ad->len);
}

#if defined(CONFIG_BT_EXT_ADV)
static bool data_cb(struct bt_data *data, void *user_data)
{
char *name = user_data;
uint8_t len;

switch (data->type) {
case BT_DATA_NAME_SHORTENED:
case BT_DATA_NAME_COMPLETE:
len = MIN(data->data_len, NAME_LEN - 1);
(void)memcpy(name, data->data, len);
name[len] = '\0';
return false;
default:
return true;
}
}

static const char *phy2str(uint8_t phy)
{
switch (phy) {
case BT_GAP_LE_PHY_NONE: return "No packets";
case BT_GAP_LE_PHY_1M: return "LE 1M";
case BT_GAP_LE_PHY_2M: return "LE 2M";
case BT_GAP_LE_PHY_CODED: return "LE Coded";
default: return "Unknown";
}
}

static void scan_recv(const struct bt_le_scan_recv_info *info,
struct net_buf_simple *buf)
{
char le_addr[BT_ADDR_LE_STR_LEN];
char name[NAME_LEN];
uint8_t data_status;
uint16_t data_len;

(void)memset(name, 0, sizeof(name));

data_len = buf->len;
bt_data_parse(buf, data_cb, name);

data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(info->adv_props);

bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i "
"Data status: %u, AD data len: %u Name: %s "
"C:%u S:%u D:%u SR:%u E:%u Pri PHY: %s, Sec PHY: %s, "
"Interval: 0x%04x (%u ms), SID: %u\n",
le_addr, info->adv_type, info->tx_power, info->rssi,
data_status, data_len, name,
(info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
(info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
(info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
(info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
(info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0,
phy2str(info->primary_phy), phy2str(info->secondary_phy),
info->interval, info->interval * 5 / 4, info->sid);
}

static struct bt_le_scan_cb scan_callbacks = {
.recv = scan_recv,
};
#endif /* CONFIG_BT_EXT_ADV */

int observer_start(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_LE_SCAN_TYPE_PASSIVE,
.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW,
};
int err;

#if defined(CONFIG_BT_EXT_ADV)
bt_le_scan_cb_register(&scan_callbacks);
printk("Registered scan callbacks\n");
#endif /* CONFIG_BT_EXT_ADV */

err = bt_le_scan_start(&scan_param, device_found);
if (err) {
printk("Start scanning failed (err %d)\n", err);
return err;
}
printk("Started scanning...\n");

return 0;
}
note
  • device_found:在扫描过程中发现设备时调用的回调函数。它打印设备的地址、RSSI、类型和AD数据长度。

  • scan_recv: 用于扩展广播的回调函数,打印接收到的广播数据包的详细信息,包括设备地址、发射功率、RSSI和广播数据。

  • data_cb:由bt_data_parse使用的回调函数,用于从广播数据中提取设备名称。它处理缩短名称和完整名称。

  • phy2str: 将PHY(物理层)值转换为人类可读字符串(例如"LE 1M"、"LE 2M"等)的辅助函数。

  • observer_start:启动观察者的主函数。它定义扫描参数并启动扫描过程。

  • bt_le_scan_start: 使用指定参数和发现设备时的回调函数启动BLE扫描的函数。

BLE广播

这个蓝牙广播教程基于官方示例代码,经过修改以在Nordic Connect SDK上运行。结合我们的开发板和官方文档,您可以深入了解更多蓝牙应用

当手机未连接到XIAO nRF54L15时,板载指示灯将保持常亮。一旦手机成功连接,指示灯将开始闪烁,表示已建立连接。

XIAO nRF54L15 Ultra-low Power Consumption in System Off Mode

手机连接XIAO nRF54L15

BLE广播软件安装

对于这个示例,您需要在手机上下载官方蓝牙测试应用nRF Connect。

将程序烧录到XIAO nRF54L15 Sense开发板后,您可以打开nRF Connect应用的主页面与其交互。

  • 步骤1. 在nRF Connect应用中,点击右上角的扫描按钮开始扫描蓝牙设备。

  • 步骤2. 接下来,在"Name"字段中输入您的XIAO nRF54L15 Sense设备名称。这将帮助您过滤并快速定位您的设备。

  • 步骤3. 在扫描结果区域,找到您的XIAO nRF54L15 Sense设备并点击旁边的"Connect"按钮。

成功连接后,您将进入设备详情页面。在此页面上,您可以观察不同时间段内的蓝牙信号强度(RSSI)分布,这有助于您了解设备连接的稳定性。

添加 XIAO nRF54L15 开发板

要将 XIAO nRF54L15(Sense) 开发板添加到 NCS (nRF Connect SDK) 中,您可以参考 Seeed Studio Wiki 上的"入门指南"。该指南将提供详细的操作步骤说明。

BLE 广播代码

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/gap.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/dt-bindings/gpio/nordic-nrf-gpio.h>

LOG_MODULE_REGISTER(BLE_LowPower, LOG_LEVEL_INF);

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)

static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);

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_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};

static unsigned char url_data[] = {
0x17,
'/', '/', 'a', 'c', 'a', 'd', 'e', 'm', 'y', '.',
'n', 'o', 'r', 'd', 'i', 'c', 's', 'e', 'm', 'i', '.',
'c', 'o', 'm'
};

static const struct bt_data sd[] = {
BT_DATA(BT_DATA_URI, url_data, sizeof(url_data)),
};

static bool device_connected = false;

static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
LOG_ERR("Connection failed (err 0x%02x)\n", err);
} else {
LOG_INF("Device connected\n");
device_connected = true;
}
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
LOG_INF("Device disconnected (reason 0x%02x)\n", reason);
device_connected = false;

int err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
if (err) {
LOG_ERR("Failed to restart advertising (err %d)\n", err);
} else {
LOG_INF("Advertising successfully restarted (connectable)\n");
}
}

BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};

int main(void)
{
int err;

if (!gpio_is_ready_dt(&led0)) {
LOG_ERR("Error: LED device %s is not ready\n", led0.port->name);
return -1;
}

err = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_INACTIVE);
if (err) {
LOG_ERR("Error: Failed to configure LED pin %d (err %d)\n", led0.pin, err);
return -1;
}

LOG_INF("LED configured, initially off.");

err = bt_enable(NULL);
if (err) {
LOG_ERR("Bluetooth initialization failed (err %d)\n", err);
return -1;
}
LOG_INF("Bluetooth initialized\n");

err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
if (err) {
LOG_ERR("Advertising failed to start (err %d)\n", err);
return -1;
}
LOG_INF("Advertising successfully started (connectable)\n");

while (1) {
if (device_connected) {
gpio_pin_toggle_dt(&led0);
k_sleep(K_MSEC(500));
} else {
gpio_pin_set_dt(&led0, 0);
k_sleep(K_MSEC(1000));
}
}

return 0;
}
note
  • ad: 定义广播数据,包括通用可发现和不支持 BR/EDR 的标志,以及完整的设备名称。

  • sd: 定义扫描响应数据,其中包含一个 URI(统一资源标识符)。

  • connected: 当蓝牙设备成功连接时执行此回调函数。它将 device_connected 标志设置为 true。

  • disconnected: 当蓝牙设备断开连接时执行此回调函数。它将 device_connected 标志设置为 false 并重新启动广播以允许新连接。

  • conn_callbacks: 定义连接回调的结构,将 connected 和 disconnected 函数分配给各自的事件。

  • main: 程序的主函数。

  • gpio_is_ready_dt: 检查 LED GPIO 设备是否就绪。

  • gpio_pin_configure_dt: 将 LED 引脚配置为输出,初始设置为非活动状态。

  • bt_enable(NULL): 初始化蓝牙子系统。

  • bt_le_adv_start: 启动蓝牙广播。此代码使用 ad 和 sd 数据启动可连接广播。

  • while (1): 根据连接状态控制 LED 行为的无限循环。

  • gpio_pin_toggle_dt: 切换 LED 的开关状态。

  • k_sleep: 让线程休眠指定的时间。

  • device_connected: 跟踪连接状态的布尔标志。当设备连接时,LED 以 500ms 间隔闪烁。当设备未连接时,LED 关闭,程序休眠 1000ms。

  • LOG_INF, LOG_ERR: 用于记录信息和错误的函数。

BLE Central/GATT Write

这些代码文件共同实现了一个蓝牙低功耗(BLE)中央设备。中央设备持续扫描附近的蓝牙外围设备,当找到特定设备(RSSI 大于 -50)时自动建立连接。一旦建立连接,它会执行 GATT(通用属性配置文件)MTU(最大传输单元)交换以优化数据传输效率。

程序的核心功能是持续向连接的外围设备发送 GATT Write Without Response 命令。这通常用于性能测试,例如测量蓝牙连接的数据吞吐量或写入速率。

XIAO nRF54L15 gatt

gatt 结果

添加 XIAO nRF54L15 开发板

要将 XIAO nRF54L15(Sense) 开发板添加到 NCS(nRF Connect SDK),您可以参考 Seeed Studio Wiki 上的"入门指南"。该指南将提供详细的操作说明。

BLE Central/GATT 代码

Main.c

#include <stdint.h>

extern uint32_t central_gatt_write(uint32_t count);

int main(void)
{
(void)central_gatt_write(0U);
return 0;
}

note
  • main: 程序的入口点。它调用 central_gatt_write 函数,计数为 0U,这意味着写入命令将无限期发送。

central_gatt_write.c

/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>

extern int mtu_exchange(struct bt_conn *conn);
extern int write_cmd(struct bt_conn *conn);
extern struct bt_conn *conn_connected;
extern uint32_t last_write_rate;
extern void (*start_scan_func)(void);

static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
struct net_buf_simple *ad)
{
char dev[BT_ADDR_LE_STR_LEN];
struct bt_conn *conn;
int err;

bt_addr_le_to_str(addr, dev, sizeof(dev));
printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n",
dev, type, ad->len, rssi);

/* We're only interested in connectable events */
if (type != BT_GAP_ADV_TYPE_ADV_IND &&
type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
return;
}

/* connect only to devices in close proximity */
if (rssi < -50) {
return;
}

err = bt_le_scan_stop();
if (err) {
printk("%s: Stop LE scan failed (err %d)\n", __func__, err);
return;
}

err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
BT_LE_CONN_PARAM_DEFAULT, &conn);
if (err) {
printk("%s: Create conn failed (err %d)\n", __func__, err);
start_scan_func();
} else {
bt_conn_unref(conn);
}
}

static void start_scan(void)
{
int err;

err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
if (err) {
printk("%s: Scanning failed to start (err %d)\n", __func__,
err);
return;
}

printk("%s: Scanning successfully started\n", __func__);
}

void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
{
printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx);
}

static struct bt_gatt_cb gatt_callbacks = {
.att_mtu_updated = mtu_updated
};

uint32_t central_gatt_write(uint32_t count)
{
int err;

err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return 0U;
}
printk("Bluetooth initialized\n");

bt_gatt_cb_register(&gatt_callbacks);

conn_connected = NULL;
last_write_rate = 0U;

start_scan_func = start_scan;
start_scan_func();

while (true) {
struct bt_conn *conn = NULL;

if (conn_connected) {
/* Get a connection reference to ensure that a
* reference is maintained in case disconnected
* callback is called while we perform GATT Write
* command.
*/
conn = bt_conn_ref(conn_connected);
}

if (conn) {
(void)write_cmd(conn);
bt_conn_unref(conn);

if (count) {
count--;
if (!count) {
break;
}
}

k_yield();
} else {
k_sleep(K_SECONDS(1));
}
}

return last_write_rate;
}

note
  • device_found: 在扫描过程中发现新设备时触发的回调函数。它打印找到的设备信息,并尝试连接既可连接又在近距离内的设备(RSSI 大于 -50)。在创建连接之前,它会停止扫描过程。

  • start_scan: 启动主动 BLE 扫描的函数,使用 device_found 作为发现设备的回调函数。

  • mtu_updated: GATT MTU 更新的回调函数,打印新的 TX 和 RX MTU 大小。

  • gatt_callbacks: 注册 mtu_updated 函数作为 GATT 事件回调的结构体。

  • central_gatt_write: 中心设备应用程序的主函数。它初始化蓝牙子系统,注册 GATT 回调,并开始扫描设备。然后进入循环,等待连接并重复调用 write_cmd 来执行 GATT 写入。该循环可以配置为运行特定次数或无限期运行。

gatt_write_common.c

/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>

static struct bt_gatt_exchange_params mtu_exchange_params;
static uint32_t write_count;
static uint32_t write_len;
static uint32_t write_rate;
struct bt_conn *conn_connected;
uint32_t last_write_rate;
void (*start_scan_func)(void);

static void write_cmd_cb(struct bt_conn *conn, void *user_data)
{
static uint32_t cycle_stamp;
uint64_t delta;

delta = k_cycle_get_32() - cycle_stamp;
delta = k_cyc_to_ns_floor64(delta);

if (delta == 0) {
/* Skip division by zero */
return;
}

/* if last data rx-ed was greater than 1 second in the past,
* reset the metrics.
*/
if (delta > (1U * NSEC_PER_SEC)) {
printk("%s: count= %u, len= %u, rate= %u bps.\n", __func__,
write_count, write_len, write_rate);

last_write_rate = write_rate;

write_count = 0U;
write_len = 0U;
write_rate = 0U;
cycle_stamp = k_cycle_get_32();
} else {
uint16_t len;

write_count++;

/* Extract the 16-bit data length stored in user_data */
len = (uint32_t)user_data & 0xFFFF;

write_len += len;
write_rate = ((uint64_t)write_len << 3) * (1U * NSEC_PER_SEC) /
delta;
}
}

static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
struct bt_gatt_exchange_params *params)
{
printk("%s: MTU exchange %s (%u)\n", __func__,
err == 0U ? "successful" : "failed",
bt_gatt_get_mtu(conn));
}

static int mtu_exchange(struct bt_conn *conn)
{
int err;

printk("%s: Current MTU = %u\n", __func__, bt_gatt_get_mtu(conn));

mtu_exchange_params.func = mtu_exchange_cb;

printk("%s: Exchange MTU...\n", __func__);
err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params);
if (err) {
printk("%s: MTU exchange failed (err %d)", __func__, err);
}

return err;
}

static void connected(struct bt_conn *conn, uint8_t conn_err)
{
struct bt_conn_info conn_info;
char addr[BT_ADDR_LE_STR_LEN];
int err;

bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

if (conn_err) {
printk("%s: Failed to connect to %s (%u)\n", __func__, addr,
conn_err);
return;
}

err = bt_conn_get_info(conn, &conn_info);
if (err) {
printk("Failed to get connection info (%d).\n", err);
return;
}

printk("%s: %s role %u\n", __func__, addr, conn_info.role);

conn_connected = bt_conn_ref(conn);

(void)mtu_exchange(conn);

#if defined(CONFIG_BT_SMP)
if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
err = bt_conn_set_security(conn, BT_SECURITY_L2);
if (err) {
printk("Failed to set security (%d).\n", err);
}
}
#endif
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
struct bt_conn_info conn_info;
char addr[BT_ADDR_LE_STR_LEN];
int err;

bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

err = bt_conn_get_info(conn, &conn_info);
if (err) {
printk("Failed to get connection info (%d).\n", err);
return;
}

printk("%s: %s role %u, reason %u %s\n", __func__, addr, conn_info.role,
reason, bt_hci_err_to_str(reason));

conn_connected = NULL;

bt_conn_unref(conn);

if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
start_scan_func();
}
}

static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
{
printk("%s: int (0x%04x, 0x%04x) lat %u to %u\n", __func__,
param->interval_min, param->interval_max, param->latency,
param->timeout);

return true;
}

static void le_param_updated(struct bt_conn *conn, uint16_t interval,
uint16_t latency, uint16_t timeout)
{
printk("%s: int 0x%04x lat %u to %u\n", __func__, interval,
latency, timeout);
}

#if defined(CONFIG_BT_SMP)
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err)
{
printk("%s: to level %u, err %s(%u)\n", __func__, level, bt_security_err_to_str(err), err);
}
#endif

BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.le_param_req = le_param_req,
.le_param_updated = le_param_updated,
#if defined(CONFIG_BT_SMP)
.security_changed = security_changed,
#endif
};

int write_cmd(struct bt_conn *conn)
{
static uint8_t data[BT_ATT_MAX_ATTRIBUTE_LEN] = {0, };
static uint16_t data_len;
uint16_t data_len_max;
int err;

data_len_max = bt_gatt_get_mtu(conn) - 3;
if (data_len_max > BT_ATT_MAX_ATTRIBUTE_LEN) {
data_len_max = BT_ATT_MAX_ATTRIBUTE_LEN;
}

#if TEST_FRAGMENTATION_WITH_VARIABLE_LENGTH_DATA
/* Use incremental length data for every write command */
/* TODO: Include test case in BabbleSim tests */
static bool decrement;

if (decrement) {
data_len--;
if (data_len <= 1) {
data_len = 1;
decrement = false;
}
} else {
data_len++;
if (data_len >= data_len_max) {
data_len = data_len_max;
decrement = true;
}
}
#else
/* Use fixed length data for every write command */
data_len = data_len_max;
#endif

/* Pass the 16-bit data length value (instead of reference) in
* user_data so that unique value is pass for each write callback.
* Using handle 0x0001, we do not care if it is writable, we just want
* to transmit the data across.
*/
err = bt_gatt_write_without_response_cb(conn, 0x0001, data, data_len,
false, write_cmd_cb,
(void *)((uint32_t)data_len));
if (err) {
printk("%s: Write cmd failed (%d).\n", __func__, err);
}

return err;
}
note
  • write_cmd_cb:一个用于 bt_gatt_write_without_response_cb 的回调函数。它计算并打印写入次数、长度和数据速率(以每秒比特数 bps 为单位)。如果自上次接收数据以来的时间超过一秒,它会重置这些指标。

  • mtu_exchange_cb:一个在 MTU(最大传输单元)交换过程后调用的回调函数。它打印交换是否成功或失败,并显示新的 MTU 大小。

  • mtu_exchange:启动 MTU 交换过程。它首先打印当前 MTU,然后尝试进行交换,使用 mtu_exchange_cb 作为回调。

  • connected:连接建立时执行的回调函数。它打印已连接设备的地址及其角色。然后存储连接的引用并启动 MTU 交换。如果启用了安全性,它会尝试设置安全级别。

  • disconnected:连接终止时执行的回调函数。它打印已断开连接设备的地址、其角色和断开连接的原因。它清除连接引用,如果设备是中心设备,则重新启动扫描。

  • le_param_req: 用于处理来自外围设备的 LE 连接参数更新请求的回调函数。它打印请求的参数(间隔、延迟和超时)。

  • le_param_updated: 连接参数成功更新时调用的回调函数。它打印新的间隔、延迟和超时值。

  • security_changed:连接的安全级别发生变化时调用的回调函数。

  • write_cmd: 准备并发送不需要响应的 GATT 写入命令的函数。它根据当前 MTU 确定最大数据长度,并将数据发送到句柄 0x0001。它使用 write_cmd_cb 作为回调。

技术支持与产品讨论

感谢您选择我们的产品!我们在这里为您提供不同的支持,以确保您使用我们产品的体验尽可能顺畅。我们提供多种沟通渠道,以满足不同的偏好和需求。

Loading Comments...