十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于 esp-iot-solution 实现 BLE Current Time Service(CTS):GATT 时间同步服务从配置到源码解析

基于 esp-iot-solution 实现 BLE Current Time Service(CTS):GATT 时间同步服务从配置到源码解析 物联网嵌入式驱动开发硬件开发【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址https://gitcode.com/GitHub_Trending/es/esp-iot-solution点击查看免费下载本文是基于 esp-iot-solution 仓库中 ble_cts 示例 编写的一篇实战技术指南。该示例将 ESP32 系列芯片配置为 BLE GATT Server通过 Current Time ServiceCTS向客户端暴露标准时间信息并结合 BLE Connection Manager 完成连接管理与广播流程。读完本文你将掌握如何在 ESP-IDF 工程中启用并配置 CTS 服务、理解其三个核心特征值的数据结构以及掌握通过事件回调驱动时间同步的完整开发链路。示例概览与适用场景Current Time ServiceCTS是蓝牙 SIG 定义的标准 GATT 服务Service UUID0x1805用于向远程客户端提供当前时间、本地时间偏移以及参考时间等信息。在 esp-iot-solution 中ble_cts 示例 展示了以下能力创建一个GATT Server并启动广播等待 GATT Client 连接通过Current Time Service暴露设备时间信息基于BLE Connection Managerble_conn_mgr完成 BLE 连接管理与事件分发帮助开发者理解 BLE Current Time Service 与 BLE 连接管理 API 的配合方式。该示例基于蓝牙控制器Bluetooth controller实现默认使用 NimBLE 协议栈见 sdkconfig.defaults 中的CONFIG_BT_NIMBLE_ENABLEDy。测试时任何支持 BLE 的扫码工具BLE scanner app都可作为 GATT Client 连接并读取时间特征值。示例支持的目标芯片如下支持目标ESP32ESP32-C3ESP32-C2ESP32-S3ESP32-H2硬件与软件准备硬件要求一块搭载 ESP32 / ESP32-C3 / ESP32-C2 / ESP32-S3 SoC 的开发板一根 USB 数据线用于供电与程序烧录。软件环境示例通过组件管理器依赖两个本地组件见 idf_component.ymlble_conn_mgr~1.*BLE 连接管理组件位于 components/bluetooth/ble_conn_mgrble_services~1.*标准 BLE 服务集合CTS 即位于其中对应源码在 components/bluetooth/ble_services/cts。示例工程要求 IDF 版本不低于 4.3idf: 4.3。构建与运行步骤1. 设置目标芯片在工程配置与编译之前先设置正确的芯片目标idf.py set-target chip_name其中chip_name替换为上表所列芯片型号例如esp32s3。2. 配置工程打开工程配置菜单idf.py menuconfig需要关注两个菜单项Example Configuration 菜单Example Configuration -- Advertisement name设置设备的广播名称默认值为BLE_CTS。该选项对应 Kconfig.projbuild 中的EXAMPLE_BLE_ADV_NAME同菜单下还有Subsequent advertisement dataEXAMPLE_BLE_SUB_ADV默认值为SUB_ADV用于设置后续广播数据内容。BLE Standard Services 菜单GATT Current Time Service即BLE_CTS开关选择是否启用 CTS 服务默认关闭disable。启用后下方还有三个子选项详见 Kconfig.in配置项说明默认值BLE_CTS_CURRENT_TIME_WRITE_ENABLE是否允许客户端写入 Current Time 特征值yBLE_CTS_LOCAL_TIME_CHAR_ENABLE是否包含 Local Time Information 特征值yBLE_CTS_LOCAL_TIME_WRITE_ENABLE是否允许写入 Local Time 特征值依赖上一项yBLE_CTS_REF_TIME_CHAR_ENABLE是否包含 Reference Time Information 特征值y从源码看ble_services组件的 CTS 服务在顶层BLE_CTS开关关闭时整体不编译因此示例在 sdkconfig.defaults 中显式写入CONFIG_BLE_CTSy以确保默认启用。3. 编译烧录并监视输出idf.py -p PORT flash monitor将PORT替换为开发板对应的串口设备如/dev/ttyUSB0。退出串口监视器可输入Ctrl-]。4. 预期串口输出当设备启动、NimBLE 完成初始化并开始广播时串口会输出类似如下日志节选自原文档I (330) BLE_INIT: BT controller compile version [9359a4d] I (340) system_api: Base MAC address is not set I (340) system_api: read default base MAC address from EFUSE I (350) BLE_INIT: Bluetooth MAC: 58:cf:79:1e:9e:de I (350) phy_init: phy_version 1150,7c3c08f,Jan 24 2024,17:32:21 I (410) blecm_nimble: BLE Host Task Started I (410) blecm_nimble: No characteristic(0x2a00) found I (410) blecm_nimble: No characteristic(0x2a01) found I (410) blecm_nimble: No characteristic(0x2a05) found I (420) NimBLE: GAP procedure initiated: stop advertising. I (430) NimBLE: GAP procedure initiated: advertise; I (430) NimBLE: disc_mode2 I (440) NimBLE: adv_channel_map0 own_addr_type0 adv_filter_policy0 adv_itvl_min256 adv_itvl_max256 I (450) NimBLE: I (450) main_task: Returned from app_main()其中No characteristic(0x2a00) found等日志表明连接管理器在启动时对若干标准特征值进行例行探测本服务未注册这些特征值属正常现象。连接建立后客户端读取特征值即可通过 GATT 响应获取对应时间数据。CTS 服务结构与核心特征值CTS 服务在 esp_cts.h 中定义了服务与特征值 UUID以及三个核心数据结构/* 16 Bit Current Time Service UUID */ #define BLE_CTS_UUID16 0x1805 /* 16 Bit Current Time Characteristics UUID */ #define BLE_CTS_CHR_UUID16_CURRENT_TIME 0x2A2B #define BLE_CTS_CHR_UUID16_LOCAL_TIME 0x2A0F #define BLE_CTS_CHR_UUID16_REFERENCE_TIME 0x2A14Current Time 特征值0x2A2Besp_ble_cts_cur_time_t由时间戳与附加字段组成字段均以__attribute__((packed))紧凑布局typedef struct { struct { uint16_t year; /*! 公历年份有效范围 1582 - 9999 */ uint8_t month; /*! 月份1一月到 12十二月 */ uint8_t day; /*! 日期1 - 31 */ uint8_t hours; /*! 午夜后小时数0 - 23 */ uint8_t minutes; /*! 小时内的分钟数0 - 59 */ uint8_t seconds; /*! 分钟内的秒数0 - 59 */ } __attribute__((packed)) timestamp; uint8_t day_of_week; /*! 星期1周一到 7周日0 表示未知 */ uint8_t fractions_256; /*! 秒的 1/256 分数0 - 255 */ uint8_t adjust_reason; /*! 时间调整原因掩码 */ } __attribute__((packed)) esp_ble_cts_cur_time_t;adjust_reason字段使用如下位掩码表示时间调整原因#define BLE_CTS_MANUAL_TIME_UPDATE_MASK (1 0) /* 手动校时 */ #define BLE_CTS_EXTERNAL_REFERENCE_TIME_UPDATE_MASK (1 1) /* 外部参考时间更新 */ #define BLE_CTS_CHANGE_OF_TIME_ZONE_MASK (1 2) /* 时区变化 */ #define BLE_CTS_CHANGE_OF_DST_MASK (1 3) /* 夏令时变化 */Local Time 特征值0x2A0Fesp_ble_cts_local_time_t描述相对 UTC 的本地时间偏移typedef struct { int8_t timezone; /*! 以 15 分钟为单位相对 UTC 的偏移范围 -48 到 56-128 表示时区未知 */ uint8_t dst_offset; /*! 夏令时偏移允许值0、2、4、8、255 */ } __attribute__((packed)) esp_ble_cts_local_time_t;需要说明的是该时区偏移恒定不变不随夏令时生效与否而变化夏令时影响由dst_offset单独表达。Reference Time 特征值0x2A14esp_ble_cts_ref_time_t描述参考时间源与时间信息的精度/漂移typedef struct { uint8_t time_source; /*! 时间源有效范围 0 - 253255 表示未知 */ uint8_t time_accuracy; /*! 以 1/8 秒125ms为步进的时间精度0 - 2530s - 31.625s254 表示漂移大于 31.625s255 表示未知 */ uint8_t days_since_update; /*! 距上次更新的天数0 - 254255 表示超过 254 天 */ uint8_t hours_since_update; /*! 距上次更新的小时数0 - 23255 表示大于等于 255 天 */ } __attribute__((packed)) esp_ble_cts_ref_time_t;源码级原理剖析服务注册一个特征值查找表完成一切CTS 服务的核心实现非常简洁全部位于 esp_cts.c约 280 行。它并不直接操作 NimBLE/Bluedroid 的 GATT API而是通过esp_ble_conn_mgr提供的抽象接口把服务“登记”到连接管理器static const esp_ble_conn_svc_t svc { .type BLE_CONN_UUID_TYPE_16, .uuid { .uuid16 BLE_CTS_UUID16 }, .nu_lookup_count sizeof(nu_lookup_table) / sizeof(nu_lookup_table[0]), .nu_lookup (esp_ble_conn_character_t *)nu_lookup_table }; esp_err_t esp_ble_cts_init(void) { return esp_ble_conn_add_svc(svc); }三个特征值以nu_lookup_table静态表的形式声明每个条目指定特征名称、UUID 类型、读写/通知属性标志以及对应的处理回调static const esp_ble_conn_character_t nu_lookup_table[] { { Current Time, BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_READ | BLE_CONN_GATT_CHR_NOTIFY #ifdef CONFIG_BLE_CTS_CURRENT_TIME_WRITE_ENABLE | BLE_CONN_GATT_CHR_WRITE #endif , { BLE_CTS_CHR_UUID16_CURRENT_TIME }, cts_cur_time_cb }, /* ... Local Time、Reference Time 类似 ... */ };可以看到特征值属性与 Kconfig 配置项严格联动例如只有启用CONFIG_BLE_CTS_CURRENT_TIME_WRITE_ENABLE时Current Time 特征值才会挂上WRITE属性Local Time、Reference Time 特征值是否出现在服务中则由CONFIG_BLE_CTS_LOCAL_TIME_CHAR_ENABLE与CONFIG_BLE_CTS_REF_TIME_CHAR_ENABLE决定。读写回调读前更新 写后事件通知以 Current Time 为例其回调cts_cur_time_cb同时处理读与写两条路径写路径当CONFIG_BLE_CTS_CURRENT_TIME_WRITE_ENABLE启用且inbuf非空时将客户端写入数据拷贝到静态变量s_cur_time随后通过esp_event_post向BLE_CTS_EVENTS事件基发布BLE_CTS_CHR_UUID16_CURRENT_TIME事件应用层可据此感知时间被远程更新读路径当客户端发起读操作时先调用已注册的读回调s_cur_time_read_cb可通过esp_ble_cts_set_current_time_read_cb()注册传入NULL取消允许应用在响应发出前刷新时间值然后拷贝s_cur_time作为 GATT 读响应返回。Local Time 与 Reference Time 的回调结构与此一致只是 Local Time 的读回调注册函数为esp_ble_cts_set_local_time_read_cb()Reference Time 的为esp_ble_cts_set_reference_time_read_cb()。主动通知连接建立即推送当前时间esp_ble_cts_set_current_time()在更新内部时间值的同时可通过need_send参数选择是否立即向已连接客户端发送 NOTIFY内部通过esp_ble_conn_notify()完成。这正是示例 app_main.c 中“连接即校时”的机制来源。示例应用流程拆解初始化与连接事件处理app_main()的启动流程如下初始化 NVSnvs_flash_init()必要时先擦除再初始化创建默认事件循环并向BLE_CONN_MGR_EVENTS注册连接管理事件处理器构造esp_ble_conn_config_t配置广播名取CONFIG_EXAMPLE_BLE_ADV_NAME默认BLE_CTS广播数据取CONFIG_EXAMPLE_BLE_SUB_ADV调用esp_ble_conn_init()初始化连接管理器调用app_ble_cts_init()完成 CTS 服务注册esp_ble_cts_init() 事件处理器注册调用esp_ble_conn_start()启动广播若启动失败则依次执行esp_ble_conn_stop()、esp_ble_conn_deinit()并注销事件处理器完成清理。连接即校时事件驱动的典型写法示例在app_ble_conn_event_handler中监听连接管理事件收到ESP_BLE_CONN_EVENT_CONNECTED时打印日志并调用esp_ble_cts_set_current_time(cur_time, true)将本地构造的时间值示例代码中固定为 2024-10-01 09:10:25adjust_reason为BLE_CTS_MANUAL_TIME_UPDATE_MASK写入 CTS 并立即通知客户端收到ESP_BLE_CONN_EVENT_DISCONNECTED时打印断开日志。app_ble_cts_event_handler则监听BLE_CTS_EVENTS基下的服务事件当客户端写入 Current Time、Local Time 或 Reference Time 特征值时分别打印对应的年份/月份、时区或时间精度直观验证“写后事件通知”机制是否生效。组件架构与可移植性说明从结构上看本示例是“薄应用 厚组件”的典型范式应用层app_main.c只负责初始化、事件注册和业务逻辑ble_conn_mgr 组件统一封装 BLE 初始化、广播、GATT 服务注册与连接事件分发屏蔽了 NimBLE 与 Bluedroid 的差异CTS 服务components/bluetooth/ble_services/cts以特征值查找表方式声明服务应用只需注册BLE_CTS_EVENTS事件即可获得读写通知。因此开发者可以将 esp_cts.h 中的esp_ble_cts_init()、esp_ble_cts_set_current_time()等 API 直接复用到自己的工程中实现“连接建立即下发时间”的时间同步方案若要接入真实时钟源如 NTP 或 RTC只需替换示例中固定时间戳的构造逻辑并在读回调中返回实时时间即可。常见问题排查串口无任何 BLE 相关日志确认已执行idf.py set-target且芯片型号正确同时检查sdkconfig.defaults中的CONFIG_BT_ENABLEDy与CONFIG_BT_NIMBLE_ENABLEDy是否生效扫码工具搜不到设备确认广播名称Example Configuration -- Advertisement name未被修改为空并检查开发板天线/射频环境客户端读不到三个特征值检查BLE Standard Services -- GATT Current Time Service是否开启以及BLE_CTS_LOCAL_TIME_CHAR_ENABLE、BLE_CTS_REF_TIME_CHAR_ENABLE是否被误关闭希望客户端能写入时间确认BLE_CTS_CURRENT_TIME_WRITE_ENABLE/BLE_CTS_LOCAL_TIME_WRITE_ENABLE保持开启否则对应特征值不具备 WRITE 属性。扩展阅读BLE 标准服务示例集合含 ANCS、BAS、BCS、DIS、HRS、HTS、OTS、TPS、UDS、WSS 等同类示例可作为服务接入的横向参考ble_conn_mgr 组件连接管理器 API 与事件定义ble_services 组件CTS 等标准服务的 Kconfig 与实现CTS 服务头文件全部数据结构与 API 定义。赞分享物联网嵌入式驱动开发硬件开发【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址https://gitcode.com/GitHub_Trending/es/esp-iot-solution点击查看免费下载相关推荐ESP IoT Solution 实战基于 esp-iot-solution 的 BLE 健康温度计服务HTSGATT 服务端示例详解ESP IoT Solution 实战基于 esp iot solution 的 BLE 健康温度计服务HTSGATT 服务端示例详解 导读 本指南围绕物联网嵌入式驱动开发硬件开发ESP-IoT-Solution BLE Alert Notification ServiceANS开发指南基于 esp_ble_conn_mgr 的 GATT 告警服务实现与实战ESP IoT Solution BLE Alert Notification ServiceANS开发指南基于 esp_ble_conn_mgr 的 G物联网嵌入式驱动开发硬件开发esp-iot-solution 的 BLE 电池服务BAS从 GATT 特征到源码实现完整指南esp iot solution 的 BLE 电池服务BAS从 GATT 特征到源码实现完整指南 本文基于 esp iot solution 仓库中 do物联网嵌入式驱动开发硬件开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表