教程原地址: https://devzone.nordicsemi.com/tutorials/15/
如何使用nrf51开发工具包的设备管理器库来绑定和连接对端蓝牙设备。
下面来讲讲如何使用设备管理器(devicce manager)来存储和删除绑定信息。
配对是每个BLE设备的安全功能的初始交互,创建一个临时加密。
设备配对后,可以选择和继续绑定。绑定就是交换一个长期安全秘钥,它被存储起来以便之后重连和加密。
设备管理器做到这一点,是利用存储模块pstorage,将绑定信息存储进flash,这样即使重新启动信息也依然存在。假如你绑定的设备数量达到了你自己设定的最大绑定数量,那么设备管理器将弹出事件,然后你编程可以自行处理。处理此问题的一个例子:the github-example ble-peripheral-bond-handling.
本教程使用的模板:ble_app_template
下面进入正题:
1、添加设备管理库文件(device manage library)
在main.c中包含头文件 #include "device_manage.h"
将.c文件添加到项目中(device_manager_central.c 或者 device_manager_peripheral.c) 。文件在"..\sdk_0.9\components\ble\device_manager" 下面我们用从机(peripheral)来做作示例:
在c/c++选项中包含相应.h文件的路径。如下图:
注意有两个路径,第二个路径中有一个文件 device_manage_cnfg.h,该文件包含设备管理器的配置,可以在这里设置最大绑定数,连接,等等。
接下里我们还需要将一个设备管理器依赖的模块加入工程。
#include "pstorage.h"
..\..\..\..\..\..\components\drivers_nrf\pstorage
and
..\..\..\..\..\..\components\drivers_nrf\pstorage\config
在这里你可以找到 pstorage_platform.h 文件,该文件包含pstorage模块的配置信息。
2、代码初始化
我们要将 pstorage 加入系统事件调度器(system event dispatch)。调度器其实就是一个事件处理程序,它决定了发送事件到哪个处理函数和发送的顺序。改动 sys_evt_dispatch 的内容如下:
static void sys_evt_dispatch(uint32_t sys_evt)
{
ble_advertising_on_sys_evt(sys_evt);
}
to:
static void sys_evt_dispatch(uint32_t sys_evt)
{
pstorage_sys_event_handler(sys_evt); //Add this line
ble_advertising_on_sys_evt(sys_evt);
}
接下来初始化设备管理器,将下列代码加入main.c中:
static dm_application_instance_t m_app_handle; /**< Application identifier allocated by device manager */
/**@brief Function for handling the Device Manager events.
*
* @param[in] p_evt Data associated to the device manager event.
*/
static uint32_t device_manager_evt_handler(dm_handle_t const * p_handle,
dm_event_t const * p_event,
ret_code_t event_result)
{
APP_ERROR_CHECK(event_result);
return NRF_SUCCESS;
}
/**@brief Function for the Device Manager initialization.
*
* @param[in] erase_bonds Indicates whether bonding information should be cleared from
* persistent storage during initialization of the Device Manager.
*/
static void device_manager_init(bool erase_bonds)
{
uint32_t err_code;
dm_init_param_t init_param = {.clear_persistent_data = erase_bonds};
dm_application_param_t register_param;
// Initialize persistent storage module.
err_code = pstorage_init();
APP_ERROR_CHECK(err_code);
err_code = dm_init(&init_param);
APP_ERROR_CHECK(err_code);
memset(®ister_param.sec_param, 0, sizeof(ble_gap_sec_params_t));
register_param.sec_param.bond = SEC_PARAM_BOND;
register_param.sec_param.mitm = SEC_PARAM_MITM;
register_param.sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
register_param.sec_param.oob = SEC_PARAM_OOB;
register_param.sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
register_param.sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
register_param.evt_handler = device_manager_evt_handler;
register_param.service_type = DM_PROTOCOL_CNTXT_GATT_SRVR_ID;
err_code = dm_register(&m_app_handle, ®ister_param);
APP_ERROR_CHECK(err_code);
}
可以看到,设备管理器初始化函数中设置了连接参数。在上面的配对例程中,我们使用了下面的参数
#define SEC_PARAM_BOND 1 /**< Perform bonding. */
#define SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */
#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */
#define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */
#define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */
#define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */
DM_PROTOCOL_CNTXT_GATT_SRVR_ID : 作为服务器
接下来在main()函数中完成初始化。我们还需要初始化局部变量 erase_bonds,这种操作能够支持我们通过按下一个按钮或者类似的东西来擦除所有的绑定。如下:
bool erase_bonds; device_manager_init(erase_bonds);//
放在协议栈初始化之后 我们还需要在BLE调度器(BLE dispatcher)中注册设备管理事件处理程序:
ble_evt_dispatch()函数
修改部分
具体
如下:from:
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
on_ble_evt(p_ble_evt);
ble_conn_params_on_ble_evt(p_ble_evt);
ble_advertising_on_ble_evt(p_ble_evt);
/*
YOUR_JOB: Add service ble_evt handlers calls here, like, for example:
ble_bas_on_ble_evt(&m_bas, p_ble_evt);
*/
}
to:
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
on_ble_evt(p_ble_evt);
ble_conn_params_on_ble_evt(p_ble_evt);
ble_advertising_on_ble_evt(p_ble_evt);
/*
YOUR_JOB: Add service ble_evt handlers calls here, like, for example:
ble_bas_on_ble_evt(&m_bas, p_ble_evt);
*/
dm_ble_evt_handler(p_ble_evt); //Add this line
}打开主控制面板(Master Control Panel)MCP并检查我们的新设备管理连接的功能。在编译和下载我们的工程之后,我们可以看到LED1在闪烁,这表明设备正在广播。我们也可以使用MCP连接它,这时观察到LED1的闪烁变为常亮。但是,当我们试图和它进行配对和绑定,这会让我们遇到麻烦,它会拒绝绑定然后重新返回到广播状态由于原始代码已经实现了手动配对,因此我们做了两次相同的事情,一次手动,一次使用设备管理器,这就是导致错误的原因。我们希望配对和绑定由设备管理器处理,我们可以将 on_ble_evt 处理程序更改为:
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
uint32_t err_code;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
APP_ERROR_CHECK(err_code);
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
break;
default:
// No implementation needed.
break;
}
}
虽然教程上是这么写的,不过我们实际使用的时候一般会加多一条断开连接处理,经过验证这种写法是不会影响连接和绑定的,如下:
static void on_ble_evt(ble_evt_t * p_ble_evt) { uint32_t err_code; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: err_code = bsp_indication_set(BSP_INDICATE_CONNECTED); APP_ERROR_CHECK(err_code); m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; break; case BLE_GAP_EVT_DISCONNECTED: //
让设备断开连接后继续广播
m_conn_handle = BLE_CONN_HANDLE_INVALID; AdvertisingStart(); break;
default:
// No implementation needed.
break;
}
}
现在我们可以使用MCP或者BLE手机与设备自由连接和绑定。请注意,在未连接时设备处于广播状态,LED1闪烁,在连接时LED1常亮。请注意,如果您对开发工具包(development kit)进行配对绑定,断开后重新连接时不需要再次进行绑定就能够获得加密的连接。这就是设备管理器的好处。