1. Nordic SDK BLE服务指针机制概述
在Nordic的BLE协议栈开发中,服务指针机制是整个架构设计的核心枢纽。不同于传统的直接调用方式,Nordic SDK采用了一种基于观察者模式的多层指针传递机制。这种设计使得服务实例能够动态注册到协议栈中,同时保持各层之间的松耦合关系。
以Battery Service为例,当我们创建一个电池服务实例时,实际上是在内存中分配了一个结构体,这个结构体包含了服务所需的所有属性和方法指针。关键点在于,这个实例并不是直接硬编码到协议栈中的,而是通过一系列指针传递和回调注册完成的。
这种机制带来了几个显著优势:
- 服务实例可以动态创建和销毁
- 同一服务类型支持多个实例
- 协议栈和服务实现之间解耦
- 便于单元测试和模块替换
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Battery Service的具体实现解析
2.1 服务实例的创建过程
在Nordic SDK中创建一个Battery Service实例,通常需要调用ble_bas_init()函数。这个函数的典型实现如下:
c复制ret_code_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init)
{
// 参数校验
if (p_bas == NULL || p_bas_init == NULL) {
return NRF_ERROR_NULL;
}
// 初始化服务结构体
memset(p_bas, 0, sizeof(ble_bas_t));
// 设置特征值属性
p_bas->battery_level_last = p_bas_init->initial_batt_level;
p_bas->evt_handler = p_bas_init->evt_handler;
p_bas->conn_handle = BLE_CONN_HANDLE_INVALID;
// 添加服务到GATT表
return bas_service_add(p_bas, p_bas_init);
}
这个初始化过程的关键在于:
- 分配并清零服务结构体内存
- 设置初始电池电量值
- 注册事件处理回调函数
- 通过
bas_service_add()将服务添加到GATT表
2.2 特征值的动态注册机制
Battery Service的核心是电池电量特征值(Characteristic),在SDK中它的注册过程体现了指针机制的精妙之处:
c复制static uint32_t bas_char_add(ble_bas_t * p_bas)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
// 配置特征值元数据
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.notify = (p_bas->is_notification_supported) ? 1 : 0;
