蓝牙设备端只能与指定APP连接

Date2015.2.1 Author:杨  QQ1209758756 <[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);

    }

//立即报警使用传值的方式,而这里使用传指针

你可能感兴趣的:(蓝牙,服务,特性,低功耗)