ESP-IoT-Solution BLE L2CAP CoC 面向连接通道开发实战:从 PSM 配置到双向流式传输
ESP-IoT-Solution BLE L2CAP CoC 面向连接通道开发实战从 PSM 配置到双向流式传输【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution本篇技术指南以 BLE L2CAP 面向连接的通道 (CoC) 文档为骨架结合 esp-iot-solution 仓库中 BLE 连接管理组件ble_conn_mgr的源码与ble_l2cap_coc中心/外围双端示例系统讲解在 ESP32 系列芯片上使用 L2CAP CoC 建立可靠的、面向流的数据通道的完整方法。读完本文你将掌握 L2CAP CoC 的核心概念、PSM/MTU 的配置规则、ble_conn_mgr 提供的 CoC API 调用链以及中心设备与外围设备之间建立通道并双向收发数据的实战方案。L2CAP CoC 是什么BLE 上类 TCP的可靠数据通道L2CAP 面向连接的通道Connection-Oriented ChannelCoC是 BLE 协议栈提供的一项数据传输能力。与基于属性协议ATT的 GATT 不同L2CAP CoC 在设备之间建立专用通道提供类似 TCP 的面向连接模型支持更大数据量的传输与流控制。L2CAP CoC 的核心特性面向连接在设备之间建立专用通道后再进行数据传输通道有明确的建立与拆除过程流控制通过控制传输速率防止数据丢失避免发送端淹没接收端更大的 MTU支持最大 512 字节的 MTU可通过 Kconfig 配置双向通信在已建立的通道上支持全双工通信多通道支持多个并发的 CoC 通道同时存在。L2CAP CoC 特别适用于以下应用场景大文件传输音频/视频流传输批量数据同步任何需要可靠的、面向流的通信的应用。在 esp-iot-solution 仓库中L2CAP CoC 的能力由 components/bluetooth/ble_conn_mgr 组件以简洁的 API 形式封装支持 ESP32、ESP32-C2、ESP32-C3、ESP32-S3 等芯片示例工程还额外列出了 ESP32-H2。PSM 值配置通道的协议端口号PSMProtocol/Service Multiplexer协议/服务复用器是 L2CAP CoC 通道的标识符作用类似于 TCP/UDP 中的端口号。通信双方必须使用相同的 PSM 值才能建立连接。PSM 值可通过 Kconfig 配置。在示例工程中进入Example Configuration → L2CAP CoC PSM菜单即可设置。有效范围为0x0001-0x00FF1-255具体分为两类PSM 范围含义0x0001-0x007F固定 Bluetooth SIG 定义的服务0x0080-0x00FF动态自定义服务自定义应用应使用 0x0080-0x00FF 区间的动态值。示例工程默认值为0x00EF (239)恰好落在动态自定义服务区间内。两个示例工程的 Kconfig.projbuild 中均有如下配置定义config EXAMPLE_L2CAP_COC_PSM hex L2CAP CoC PSM (Protocol/Service Multiplexer) range 0x0001 0x00FF default 0x00EF help Protocol/Service Multiplexer value for L2CAP Connection-Oriented Channel. Valid range: 0x0001-0x00FF (1-255) - 0x0001-0x007F: Fixed Bluetooth SIG-defined services - 0x0080-0x00FF: Dynamic custom services Both central and peripheral must use the same PSM value to establish a connection.在应用代码中PSM 通过宏CONFIG_EXAMPLE_L2CAP_COC_PSM读取MTU 则通过连接管理组件提供的CONFIG_BLE_CONN_MGR_L2CAP_COC_MTU读取默认 512可配置范围 23-512见 Kconfig// PSM 值通过 Kconfig 配置 (CONFIG_EXAMPLE_L2CAP_COC_PSM) // 默认值0x00EF (239) #define L2CAP_COC_PSM CONFIG_EXAMPLE_L2CAP_COC_PSM #define L2CAP_COC_MTU CONFIG_BLE_CONN_MGR_L2CAP_COC_MTU // 最大传输单元核心 APIble_conn_mgr 的 L2CAP CoC 接口L2CAP CoC 的全部 API 声明集中在 esp_ble_conn_mgr.h 中围绕内存池初始化 → 创建服务端/发起连接 → 事件回调 → 收发数据的流程组织。关键接口如下初始化与资源管理// 初始化 L2CAP CoC 内存池 ESP_ERROR_CHECK(esp_ble_conn_l2cap_coc_mem_init());esp_ble_conn_l2cap_coc_mem_init()初始化 L2CAP CoC SDU 内存池。该 API 是线程安全的但应在任务上下文中调用重复调用是安全的会返回ESP_OK。内存池大小由CONFIG_BLE_CONN_MGR_L2CAP_COC_MTU决定默认 512 字节的 SDU MTU。esp_ble_conn_l2cap_coc_mem_release()释放内存池。在 l2cap_coc_central 示例 中esp_ble_conn_start()失败时会对mem_release、esp_ble_conn_deinit等做完整的逆序清理。服务端外围设备侧// 创建 L2CAP CoC 服务端 // app_ble_conn_l2cap_coc_event_handler 是你的回调函数 esp_err_t rc esp_ble_conn_l2cap_coc_create_server( L2CAP_COC_PSM, L2CAP_COC_MTU, app_ble_conn_l2cap_coc_event_handler, NULL);esp_ble_conn_l2cap_coc_create_server(psm, mtu, cb, arg)注册一个 CoC 服务端等待对端发起连接请求。客户端中心设备侧esp_err_t esp_ble_conn_l2cap_coc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu, esp_ble_conn_l2cap_coc_event_cb_t cb, void *arg);在 BLE 连接建立并完成服务发现后中心设备调用该接口发起 CoC 通道连接。数据收发esp_err_t esp_ble_conn_l2cap_coc_send(esp_ble_conn_l2cap_coc_chan_t chan, const esp_ble_conn_l2cap_coc_sdu_t *sdu); esp_err_t esp_ble_conn_l2cap_coc_recv_ready(esp_ble_conn_l2cap_coc_chan_t chan, uint16_t mtu); esp_err_t esp_ble_conn_l2cap_coc_disconnect(esp_ble_conn_l2cap_coc_chan_t chan);send通过已建立的通道发送一个 SDUesp_ble_conn_l2cap_coc_sdu_t包含data指针和len长度recv_ready接收完一个 SDU 后调用表示本端已准备好接收下一个 SDU配合流控制机制使用disconnect主动关闭通道。通道信息查询esp_err_t esp_ble_conn_l2cap_coc_get_chan_info(esp_ble_conn_l2cap_coc_chan_t chan, esp_ble_conn_l2cap_coc_chan_info_t *chan_info);esp_ble_conn_l2cap_coc_chan_info_t结构体携带通道的关键信息见 esp_ble_conn_mgr.h字段含义scid源通道 IDSource Channel IDdcid目的通道 IDDestination Channel IDour_l2cap_mtu本地 L2CAP MTUpeer_l2cap_mtu对端 L2CAP MTUpsm协议/服务复用器值our_coc_mtu本地 CoC MTUpeer_coc_mtu对端 CoC MTU其中peer_coc_mtu是发送端确定单次 SDU 负载大小的依据——应使用对端声明的 MTU 发送数据示例中正是用s_peer_sdu_size chan_info.peer_coc_mtu来设定发送长度。事件机制7 种通道事件与回调约定通道的异步事件统一通过注册的回调函数派发。事件类型定义在 esp_ble_conn_mgr.h 的枚举中事件含义ESP_BLE_CONN_L2CAP_COC_EVENT_CONNECTED通道连接成功携带conn_handle、status0 表示成功与chanESP_BLE_CONN_L2CAP_COC_EVENT_DISCONNECTED通道断开ESP_BLE_CONN_L2CAP_COC_EVENT_ACCEPT服务端收到连接请求需在回调中显式 acceptESP_BLE_CONN_L2CAP_COC_EVENT_DATA_RECEIVED收到一个 SDUESP_BLE_CONN_L2CAP_COC_EVENT_TX_UNSTALLED发送解除阻塞流控恢复ESP_BLE_CONN_L2CAP_COC_EVENT_RECONFIG_COMPLETED本地重配置完成ESP_BLE_CONN_L2CAP_COC_EVENT_PEER_RECONFIGURED对端完成重配置回调函数签名与返回值约定见 esp_ble_conn_mgr.htypedef int (*esp_ble_conn_l2cap_coc_event_cb_t)(esp_ble_conn_l2cap_coc_event_t *event, void *arg);返回 0 表示事件处理成功非 0 表示应用错误栈行为因事件类型而异。必须牢记的内存生命周期约定对于ESP_BLE_CONN_L2CAP_COC_EVENT_DATA_RECEIVED事件event-receive.sdu.data缓冲区由组件内部管理回调返回后会立即释放。回调内绝不能保存该指针供后续使用如需异步处理必须在返回前拷贝数据。这一约定在两个示例的源码注释中均有明确说明也是使用 CoC 最容易踩的坑。实战示例一外围设备服务端外围设备示例位于 examples/bluetooth/ble_l2cap_coc/l2cap_coc_peripheral角色为仅广播的外围设备启动 BLE 广播等待中心连接连接建立后创建 L2CAP CoC 服务端并处理通道事件。初始化流程app_main.cesp_ble_conn_config_t config { .device_name CONFIG_EXAMPLE_BLE_ADV_NAME, // 默认 BLE_L2CAP_COC_PERIPH .broadcast_data CONFIG_EXAMPLE_BLE_SUB_ADV // 默认 SUB_ADV }; // 1. 初始化 NVS处理 ESP_ERR_NVS_NO_FREE_PAGES / ESP_ERR_NVS_NEW_VERSION_FOUND nvs_flash_init(); // 2. 创建默认事件循环并注册 BLE_CONN_MGR_EVENTS 事件 esp_event_loop_create_default(); esp_event_handler_register(BLE_CONN_MGR_EVENTS, ESP_EVENT_ANY_ID, app_ble_conn_event_handler, NULL); // 3. 初始化 BLE 连接管理 L2CAP CoC 内存池 esp_ble_conn_init(config); esp_ble_conn_l2cap_coc_mem_init(); // 4. 启动 esp_ble_conn_start();与 GATT 服务在连接前注册不同示例在ESP_BLE_CONN_EVENT_CONNECTED事件中才创建 CoC 服务端PSM 与 MTU 均取 Kconfig 配置case ESP_BLE_CONN_EVENT_CONNECTED: ... ESP_ERROR_CHECK(esp_ble_conn_l2cap_coc_create_server(L2CAP_COC_PSM, BLE_CONN_MGR_L2CAP_COC_MTU, app_ble_conn_l2cap_coc_event_handler, NULL)); break;外围设备侧的事件回调核心逻辑case ESP_BLE_CONN_L2CAP_COC_EVENT_ACCEPT: // 收到连接请求记录对端 SDU 大小并显式接受 s_peer_sdu_size event-accept.peer_sdu_size; rc esp_ble_conn_l2cap_coc_accept(event-accept.conn_handle, event-accept.peer_sdu_size, event-accept.chan); break; case ESP_BLE_CONN_L2CAP_COC_EVENT_DATA_RECEIVED: // 收到数据后必须调用 recv_ready 才能继续接收 rc esp_ble_conn_l2cap_coc_recv_ready(event-receive.chan, BLE_CONN_MGR_L2CAP_COC_MTU); break;连接建立后示例创建了一个发送任务l2cap_coc_send_task栈 4096、优先级 10每 2 秒向对端回发一个 SDU缓冲区大小为s_peer_sdu_size即对端 MTU填充(uint8_t)(i 0xFF)的递增字节序列然后调用esp_ble_conn_l2cap_coc_send发送成功后打印[--TX--]L2CAP CoC data sent (%u bytes)。实战示例二中心设备客户端中心设备示例位于 examples/bluetooth/ble_l2cap_coc/l2cap_coc_central角色为被动扫描 连接 周期发送。工作流程分三步扫描匹配对端注册扫描回调esp_ble_conn_register_scan_callback在回调中用esp_ble_conn_parse_adv_data解析广播数据中的完整/短设备名与CONFIG_EXAMPLE_PEER_NAME默认BLE_L2CAP_COC_PERIPH比对匹配成功后调用esp_ble_conn_scan_stop()停止扫描并返回true结束扫描。连接并创建 CoC 通道在ESP_BLE_CONN_EVENT_DISC_COMPLETE服务发现完成事件中发起通道连接case ESP_BLE_CONN_EVENT_DISC_COMPLETE: if (s_conn_handle) { esp_err_t rc esp_ble_conn_l2cap_coc_connect(s_conn_handle, L2CAP_COC_PSM, L2CAP_COC_MTU, L2CAP_COC_MTU, app_ble_conn_l2cap_coc_event_handler, NULL); ... } break;连接成功后周期发送在ESP_BLE_CONN_L2CAP_COC_EVENT_CONNECTED回调中通过esp_ble_conn_l2cap_coc_get_chan_info打印通道详情并获取peer_coc_mtu作为发送长度然后创建发送任务每 2 秒发送一次数据ESP_LOGI(TAG, L2CAP CoC chan info: psm0x%04x scid0x%04x dcid0x%04x our_mps%u our_mtu%u peer_mps%u peer_mtu%u, ...); s_peer_sdu_size chan_info.peer_coc_mtu; s_coc_chan event-connect.chan; xTaskCreate(app_ble_conn_l2cap_coc_send_task, l2cap_coc_send_task, 4096, NULL, 10, ...);断开处理收到ESP_BLE_CONN_L2CAP_COC_EVENT_DISCONNECTED时置空通道并删除发送任务BLE 层ESP_BLE_CONN_EVENT_DISCONNECTED时清空连接句柄并复位s_target_found为下一次重连做准备。编译前的必配项NimBLE 参数调整L2CAP CoC 依赖 NimBLE 协议栈的相关配置两个示例的 README.md 均明确要求在idf.py menuconfig的Component Config菜单中完成两项设置否则通道无法正常工作启用 CoC 通道数Component config → Bluetooth → NimBLE Options → L2CAP → Maximum number of connection oriented channels将其设置为大于 0的值按并发通道需求设定加大 MSYS 内存块Component config → Bluetooth → NimBLE Options → Memory Settings → MSYS_1 Block Size设置为512用于最大化单次数据传输的吞吐。构建与烧录流程idf.py set-target chip_name # 如 esp32s3、esp32c3 idf.py menuconfig # 配置 PSM、对端名称及上述 NimBLE 参数 idf.py -p PORT flash monitor # 编译、烧录并监视串口退出串口监视器按Ctrl-]。调试与验证建议日志关键字发送端打印[--TX--]接收端打印[--RX--]观察两侧字节数是否与对端 MTU 一致即可快速判断通道是否打通原始数据核对示例默认关闭原始数据日志ENABLE_L2CAP_COC_RAW_DATA_LOG默认为 0可在编译时将其定义为 1通过ESP_LOG_BUFFER_HEX打印 SDU 的十六进制内容验证双向数据完整性发送侧填充的是0x00,0x01,0x02,...递增序列便于肉眼比对通道信息连接建立后打印的psm/scid/dcid/our_mtu/peer_mtu可用于排查 MTU 协商结果是否符合预期流控机制接收端每收到一个 SDU 必须调用一次esp_ble_conn_l2cap_coc_recv_ready若漏调发送端会因流控阻塞并最终在流控恢复时收到ESP_BLE_CONN_L2CAP_COC_EVENT_TX_UNSTALLED事件——这是验证流控行为最直观的观测点。小结L2CAP CoC 为 BLE 提供了超越 GATT 的面向流、大 MTU、全双工传输能力适合大文件、音视频流、批量同步等场景。在 esp-iot-solution 仓库中ble_conn_mgr 组件将其封装为mem_init → create_server/connect → send/recv_ready → disconnect的简洁 API 体系配合中心/外围两个开箱即用的示例工程l2cap_coc_central、l2cap_coc_peripheral可以快速搭建起可靠的双向数据通道。使用中需重点把握三个关键点通信双方 PSM 必须一致、接收回调返回前必须拷贝数据缓冲区内部管理、以及接收后及时调用recv_ready维持流控运转。更完整的 API 参考见 BLE 连接管理文档。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考