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);
}
} //立即報警使用傳值的方式,而這裏使用傳指針