Date:2015.2.1 Author:杨正 QQ:1209758756 <[email protected]>
设备端与指定APP相连,即设备只能与自己开发的APP相连,而不能与别人所开发的APP相连。那么,这个功能有什么意义,它又是如何实现的呢?
原理:在应用层做一个连接密钥,这个密钥可以是数字或者是字母或者是两者结合,比如:1234等。在设备与APP连接上时,在设备端开启一个定时器,如果在定时器超时之前,收到APP发来双方约定好的连接密钥,那么终止定时器,继续保持连接状态,否则断开连接。
步骤:
1、 在main函数的timer_init()接口中,创建一个定时器,作为连接密钥的限定时间。
2、 在处理事件接口on_ble_evt()的case BLE_GAP_EVT_CONNECTED分支中启动定时器。
3、 在创建定时器时,在创建的超时处理函数中调用sd_ble_gap_disconnect断开连接。如果在设定时间内没有收到双方约定的连接密钥,则调用超时函数断开连接。
4、 为连接密钥添加一个服务,这个服务用来向设备端写入连接密钥。
实现过程:
一、创建定时器。
1、 参照电池定时器,创建连接密钥定时器。
#ifdefDEF_PASSWD_PAIR_TIMER
//Create passwd pairtimer
err_code = app_timer_create(&m_passwd_pair_timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
passwd_pair_meas_timeout_handler);
APP_ERROR_CHECK(err_code);
#endif
2、 在处理事件接口on_ble_evt()的case BLE_GAP_EVT_CONNECTED分支中启动定时器。
static voidon_ble_evt(ble_evt_t * p_ble_evt)
{
uint32_t err_code= NRF_SUCCESS;
switch (p_ble_evt->header.evt_id)
{
caseBLE_GAP_EVT_CONNECTED:
#ifdefDEF_PASSWD_PAIR_TIMER
err_code = app_timer_start(m_passwd_pair_timer_id,PASSWD_PAIR_MEAS_INTERVAL,NULL);
APP_ERROR_CHECK(err_code);
#endif
……
3、 添加定时器超时函数。
static voidpasswd_pair_meas_timeout_handler(void * p_context)
{
uint32_t err_code;
UNUSED_PARAMETER(p_context);
if(m_conn_handle != BLE_CONN_HANDLE_INVALID)
{
err_code=sd_ble_gap_disconnect(m_conn_handle, \
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
}
}
二、创建服务
1、 以立即报警服务为模板,创建连接密钥服务。
static voidpwd_init(void)
{
uint32_t err_code;
ble_pwd_init_tpwd_init_obj;
memset(&pwd_init_obj,0,sizeof(pwd_init_obj));
pwd_init_obj.pwd_evt_handler= on_pwd_evt;
err_code =ble_pwd_init(&m_pwd, &pwd_init_obj);
APP_ERROR_CHECK(err_code);
}
static void services_init(void)
{
……
#ifdef DEF_PASSWD_PAIR
pwd_init();
#endif
}
在nrf51822\Source\ble\ble_services中复制ble_ias.c,并命名为ble_pwd.c;
在nrf51822\Include\ble\ble_services中复制ble_ias.h,并命名为ble_pwd.h;
在ble_app_proximity工程中添加刚才复制的两个文件。
2、 修改各个文件及结构。
在ble_pwd.h和ble_pwd.c中,把所有ias替换成pwd;添加服务和特性可以模仿ble_ias.c和ble_ias.h。重点讲一下如何添加服务和特性的uuid。
3、 添加服务、特性UUID
首先在nRFstudio中生成128位的uuid:打开nRFgo Studio—>在nRF8001 Setup菜单中,选择Edit 128-bit UUIDs选项,点击Add new。这就产生了一个随机的UUID,可以用于定制服务中,新产生的基本UUID必须以数组的形式包含在源代码中。16位的uuid可以是任意值。
为了代码可读性,把数组定义成宏:
#define BLE_PWD_UUID_BASE {0xDF,0xFE, 0xBE, 0x01, 0x54, 0xE7, 0x17, 0x17, 0x7B,0x44, 0x12, 0x95, 0x00,0x00, 0x49, 0x56}
#define BLE_UUID_PASSWD_PAIR_SERVICE 0x1152 //随便定义,但是不能与已使用的UID雷同
#define BLE_UUID_PASSWD_PAIR_CHAR 0x1153 //随便定义,但是不能与已使用的UID雷同
uint32_tble_pwd_init(ble_pwd_t * p_pwd, const ble_pwd_init_t *p_pwd_init)
{
uint32_t err_code;
ble_uuid_t ble_uuid;
ble_uuid128_t base_uuid = BLE_PWD_UUID_BASE;
err_code= sd_ble_uuid_vs_add(&base_uuid,&p_pwd->uuid_type);
if(err_code != NRF_SUCCESS)
{
return err_code;
}
4、 在ble_evt_dispatch()中添加ble_ _pwd_on_ble_evt(&m_pwd,p_ble_evt)。
void ble_pwd_on_ble_evt(ble_pwd_t * p_pwd, ble_evt_t * p_ble_evt)
{
switch(p_ble_evt->header.evt_id)
{
caseBLE_GATTS_EVT_WRITE;
on_write(p_pwd,p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
当有写入事件发生时,就调用这里的on_write,然后触发pwd_init()中的事件处理函数,如果写入的值与预定义的值相同,则终止定时器,如果不同,则等待定时器超时。
5、验证密钥
static void on_pwd_evt(ble_pwd_t * p_pwd, ble_pwd_evt_t * p_evt)
{
switch(p_evt->evt_type)
{
caseBLE_PWD_EVT_PASSWD_PAIR_UPDATED:
//buzzer_set(1000);
pwd_signal(p_evt->params.passwd_pair_data);
break;
default:
break;
}
}
static void pwd_signal(uint8_t *passwd_pair_data)
{
if ( (*passwd_pair_data == (uint8_t)0x12) && \
(*(passwd_pair_data + 1) == (uint8_t)0x34) && \
(*(passwd_pair_data + 2) == (uint8_t)0x56) && \
(*(passwd_pair_data+ 3) == (uint8_t)0x78) )
{
uint32_terr_code;
// Stop timer ifrunning
err_code = app_timer_stop(m_passwd_pair_timer_id);
if ((err_code !=NRF_SUCCESS))
{
return;
}
}
}
注:因为这个服务是模仿立即报警服务添加的,所以如果密钥的长度大于一个字节,那个还需要做如下修改:
typedef struct
{
uint16_t handle; /**< Attribute Handle. */
uint8_t op; /**< Type of writeoperation, see @ref BLE_GATTS_OPS. */
ble_gatts_attr_context_t context; /**<Attribute Context. */
uint16_t offset; /**< Offset for the writeoperation. */
uint16_t len; /**< Length of the incomingdata. */
uint8_t data[4]; /**< Incomingdata, variable length. */ //根据密钥长度来修改
} ble_gatts_evt_write_t;
typedef struct
{
ble_pwd_evt_type_tevt_type; /**<Type of event. */
union
{
uint8_t *passwd_pair_data; /**< passwd pairvalue. */
} params;
} ble_pwd_evt_t; //这个结构体是模仿立即报警服务自己添加的,但二者有区别
static void on_write(ble_pwd_t * p_pwd, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_write_t *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
if((p_evt_write->handle == p_pwd->passwd_pair_handles.value_handle)&& (p_evt_write->len !=0))
{
// Alert levelwritten, call application event handler
ble_pwd_evt_t evt;
evt.evt_type = BLE_PWD_EVT_PASSWD_PAIR_UPDATED;
evt.params.passwd_pair_data= p_evt_write->data;
p_pwd->pwd_evt_handler(p_pwd, &evt);
}
} //立即报警使用传值的方式,而这里使用传指针