您当前的位置: 首页 > 

仙剑情缘

暂无认证

  • 3浏览

    0关注

    333博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

NRF52832 SDK15.3 BLE bond

仙剑情缘 发布时间:2019-11-16 21:46:57 ,浏览量:3

  • 基于NRF52832 SDK15.3 uart工程实现BLE的三种绑定功能
  1.    无密码方式绑定 
  2.    动态密码方式绑定 
  3.    静态密码方式绑定

为了解决手机绑定后,设备如果再次复位造成双方保存的信息不一致,导致绑定的设备无法连接,使用内部flash将绑定成功能信息保存起来,上电复位后从flash中恢复配置信息

如何实现上述三种方式绑定呢?看下Nordic API定义的IO能力,如果实现无密码绑定,则要将IO能力选择为BLE_GAP_IO_CAPS_NONE              


/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities
 * @{ */
#define BLE_GAP_IO_CAPS_DISPLAY_ONLY      0x00   /**< Display Only. */
#define BLE_GAP_IO_CAPS_DISPLAY_YESNO     0x01   /**< Display and Yes/No entry. */
#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY     0x02   /**< Keyboard Only. */
#define BLE_GAP_IO_CAPS_NONE              0x03   /**< No I/O capabilities. */
#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY  0x04   /**< Keyboard and Display. */
/**@} */
绑定安全参数定义

/**@brief GAP security parameters. */
typedef struct
{
  uint8_t               bond      : 1;             /**< Perform bonding. */
  uint8_t               mitm      : 1;             /**< Enable Man In The Middle protection. */
  uint8_t               lesc      : 1;             /**< Enable LE Secure Connection pairing. */
  uint8_t               keypress  : 1;             /**< Enable generation of keypress notifications. */
  uint8_t               io_caps   : 3;             /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
  uint8_t               oob       : 1;             /**< The OOB data flag.
                                                        - In LE legacy pairing, this flag is set if a device has out of band authentication data.
                                                          The OOB method is used if both of the devices have out of band authentication data.
                                                        - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band authentication data.
                                                          The OOB method is used if at least one device has the peer device's OOB data available. */
  uint8_t               min_key_size;              /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
  uint8_t               max_key_size;              /**< Maximum encryption key size in octets between min_key_size and 16. */
  ble_gap_sec_kdist_t   kdist_own;                 /**< Key distribution bitmap: keys that the local device will distribute. */
  ble_gap_sec_kdist_t   kdist_peer;                /**< Key distribution bitmap: keys that the remote device will distribute. */
} ble_gap_sec_params_t;
先定义几个变量来保存相关的绑定信息

static ble_gap_sec_params_t m_sec_params;
static ble_gap_sec_keyset_t m_sec_keyset;
static ble_gap_enc_key_t m_own_enc_key;
static ble_gap_enc_key_t m_peer_enc_key;
static ble_gap_sec_params_t sec_params_auth;
static uint8_t PasswordOk;
绑定安全参数初时化
static void sec_params_init()
{

    memset(&m_sec_params, 0, sizeof(ble_gap_sec_params_t));
	  

    m_sec_params.bond = SEC_PARAM_BOND; 

    m_sec_params.mitm = SEC_PARAM_MITM;

    m_sec_params.io_caps = BLE_GAP_IO_CAPS_NONE;
	
    m_sec_params.oob =  SEC_PARAM_OOB;
    m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;

    m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;

		m_sec_params.kdist_own.enc = 1;

		m_sec_params.kdist_own.id = 0;

		m_sec_params.kdist_own.sign = 0;

		m_sec_params.kdist_peer.enc = 1;

		m_sec_params.kdist_peer.id = 0;

		m_sec_params.kdist_peer.sign = 0;  

		m_sec_keyset.keys_own.p_enc_key = &m_own_enc_key;

		m_sec_keyset.keys_own.p_id_key = NULL;

		m_sec_keyset.keys_own.p_pk = NULL;

		m_sec_keyset.keys_own.p_sign_key = NULL;   

		m_sec_keyset.keys_peer.p_enc_key = &m_peer_enc_key;

		m_sec_keyset.keys_peer.p_id_key = NULL;

		m_sec_keyset.keys_peer.p_pk = NULL;

		m_sec_keyset.keys_peer.p_sign_key = NULL;

}			
 请求绑定函数实现

static void requestBondToCenterBle(void)
{
   sec_params_auth.bond = 0; 

   sec_params_auth.mitm = 0;     
	 
   sd_ble_gap_authenticate(m_conn_handle, &sec_params_auth);//向中心设备发送配对请求
}
  1. 在ble_evt_handler回调函数的BLE_GAP_EVT_CONNECTED蓝牙连接事件中触发绑定请求
  2. 在BLE_GAP_EVT_SEC_PARAMS_REQUEST事件中交换绑定参数信息
  3.  绑定成功或失败都会触发BLE_GAP_EVT_AUTH_STATUS事件
  4.  绑定成功后,手机再次连接设备会触发BLE_GAP_EVT_SEC_INFO_REQUEST事件
  5.  如果有密码请求,会触发BLE_GAP_EVT_PASSKEY_DISPLAY事件,此事件中能够产生密码信息
  6.  将绑定成功中的ble_gap_enc_key_t信息存入内部flash
对于无密码绑定,在ble_evt_handler函数中实现添加以下代码 step 1:

    BLE_GAP_EVT_CONNECTED事件中调用requestBondToCenterBle函数

 

step 2:

     BLE_GAP_EVT_PHY_UPDATE_REQUEST事件中,调用绑定初时化函数,及参数回复主机函数

case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
             sec_params_init();                      
             err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &m_sec_params, &m_sec_keyset);            
             APP_ERROR_CHECK(err_code);
            break;

  参数回复函数原型说明


/**@brief Reply with GAP security parameters.
 *
 * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE.
 * @note    If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected parameters.
 *
 * @events
 * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref sd_ble_gap_authenticate.}
 * @endevents
 *
 * @mscs
 * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC}
 * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC}
 * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC}
 * @endmscs
 *
 * @param[in] conn_handle Connection handle.
 * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS.
 * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be set to NULL, as the parameters have
 *                         already been provided during a previous call to @ref sd_ble_gap_authenticate.
 * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or distributed as a result of the ongoing security procedure
 *                         will be stored into the memory referenced by the pointers inside this structure. The keys will be stored and available to the application
 *                         upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event.
 *                         Note that the SoftDevice expects the application to provide memory for storing the
 *                         peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The pointers to the local key
 *                         can, however, be NULL, in which case, the local key data will not be available to the application upon reception of the
 *                         @ref BLE_GAP_EVT_AUTH_STATUS event.
 *
 * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application.
 * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
 * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry.
 * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
 * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested.
 * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
 * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported.
 */
SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, ble_gap_sec_keyset_t const *p_sec_keyset));
step 3:

    BLE_GAP_EVT_SEC_INFO_REQUEST事件中回复配对info信息

case BLE_GAP_EVT_SEC_INFO_REQUEST:
   if(memcmp(p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.rand, m_own_enc_key.master_id.rand,8) != 0)  //配对信息不一致
   {
									
      err_code = sd_ble_gap_sec_info_reply(m_conn_handle,NULL, NULL, NULL);
      APP_ERROR_CHECK(err_code);
   }
  else   // 第一次配对成功
  {
      err_code = sd_ble_gap_sec_info_reply(m_conn_handle, &(m_own_enc_key.enc_info), NULL,NULL);                       
      APP_ERROR_CHECK(err_code);
  }	
break;
step 4:

      BLE_GAP_EVT_AUTH_STATUS事件中获取配对的结果

 case BLE_GAP_EVT_AUTH_STATUS:                        
                 
		if(p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)                        
                {                            

                    NRF_LOG_INFO("pair success\n");                            

                    PasswordOk = 1;
									
                }                      
                else                        
                {                            

                    NRF_LOG_INFO("pair error\n");    

                    err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                    APP_ERROR_CHECK(err_code);
                   PasswordOk = 0; 
                } 

 上述完整代码如下


/**@brief Function for handling BLE events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 * @param[in]   p_context   Unused.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    uint32_t err_code;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("Connected");
           
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
            APP_ERROR_CHECK(err_code);
					NRF_LOG_INFO("MAC ADDRESS = %02x:%02x:%02x:%02x:%02x:%02x",p_ble_evt->evt.gap_evt.params.connected.peer_addr.addr[0],\
				  p_ble_evt->evt.gap_evt.params.connected.peer_addr.addr[1],\
				p_ble_evt->evt.gap_evt.params.connected.peer_addr.addr[2],\
				p_ble_evt->evt.gap_evt.params.connected.peer_addr.addr[3],\
				p_ble_evt->evt.gap_evt.params.connected.peer_addr.addr[4],\
				p_ble_evt->evt.gap_evt.params.connected.peer_addr.addr[5]);
						requestBondToCenterBle();
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected");
            // LED indication will be changed when advertising starts.
            m_conn_handle = BLE_CONN_HANDLE_INVALID;
            break;

        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
        {
            NRF_LOG_DEBUG("PHY update request.");
            ble_gap_phys_t const phys =
            {
                .rx_phys = BLE_GAP_PHY_AUTO,
                .tx_phys = BLE_GAP_PHY_AUTO,
            };
            err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
            APP_ERROR_CHECK(err_code);
        } break;

				case BLE_GAP_EVT_SEC_INFO_REQUEST:
					          
                     NRF_LOG_INFO("enc need: %d  id need:%d   sign need:%d\r\n",
                                          p_ble_evt->evt.gap_evt.params.sec_info_request.enc_info,
                                          p_ble_evt->evt.gap_evt.params.sec_info_request.id_info, 
                                            p_ble_evt->evt.gap_evt.params.sec_info_request.sign_info);             
                     NRF_LOG_INFO("RSP:  LTK :");
                     for(int i = 0; i < m_own_enc_key.enc_info.ltk_len; i++){
                            NRF_LOG_INFO("%x",m_own_enc_key.enc_info.ltk[i]);
                     }
										 
										 
										 
                     NRF_LOG_INFO("\r\nEDIV :%x  RANDOM:",
                            p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.ediv);
                    
                     for(int i = 0; i< 8; i++){
                            NRF_LOG_INFO("%x",
                     m_own_enc_key.master_id.rand[i]);
                     }
				    NRF_LOG_INFO("key");
				for(int i = 0; i< 8; i++){
                            NRF_LOG_INFO("%x",
                     p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.rand[i]);
                     }
				   if(memcmp(p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.rand,m_own_enc_key.master_id.rand,8) != 0)
					 {
									
						 err_code = sd_ble_gap_sec_info_reply(m_conn_handle,NULL, NULL, NULL);
             APP_ERROR_CHECK(err_code);
					 }
					 else
					 {
            err_code = sd_ble_gap_sec_info_reply(m_conn_handle, &(m_own_enc_key.enc_info), NULL, NULL);
            APP_ERROR_CHECK(err_code);
					 }	
            break;
        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
             sec_params_init();                      
             err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &m_sec_params, &m_sec_keyset);            
             APP_ERROR_CHECK(err_code);
            break;
			case BLE_GAP_EVT_PASSKEY_DISPLAY:                      

                NRF_LOG_INFO("passkey: %s\n",p_ble_evt->evt.gap_evt.params.passkey_display.passkey);                        

                break;   
			 case BLE_GAP_EVT_AUTH_STATUS:                        
                 
			               NRF_LOG_INFO("LTK :");
                     for(int i = 0; i < m_own_enc_key.enc_info.ltk_len; i++){
                            NRF_LOG_INFO("%x",m_own_enc_key.enc_info.ltk[i]);
                     }
                    
                     NRF_LOG_INFO("   AUTH: %d ",m_own_enc_key.enc_info.auth);
                     NRF_LOG_INFO("   LTK length: %d \r\n",m_own_enc_key.enc_info.ltk_len);
                     NRF_LOG_INFO("EDIV: %x ",m_own_enc_key.master_id.ediv);
                     NRF_LOG_INFO("rand:");
                     for(int i = 0; i < 8; i++){
                            NRF_LOG_INFO("%x",m_own_enc_key.master_id.rand[i]);
                     }
                   
						 
                if(p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)                        

                {                            

                    NRF_LOG_INFO("pair success\n");                            

                    PasswordOk = 1;
									
                }                        

                else                        

                {                            

                    NRF_LOG_INFO("pair error\n");    

                    err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,

                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);

                    APP_ERROR_CHECK(err_code);

                   PasswordOk = 0; 

                } 
        case BLE_GATTS_EVT_SYS_ATTR_MISSING:
            // No system attributes have been stored.
            err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);

								APP_ERROR_CHECK(err_code);

								NRF_LOG_INFO("23333333333333\n"); 
                break;

        case BLE_GATTC_EVT_TIMEOUT:
            // Disconnect on GATT Client timeout event.
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
				    PasswordOk = 0; 
						NRF_LOG_INFO("BLE_GATTC_EVT_TIMEOUT");
            break;

        case BLE_GATTS_EVT_TIMEOUT:
            // Disconnect on GATT Server timeout event.
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
				    PasswordOk = 0; 
				    NRF_LOG_INFO("BLE_GATTS_EVT_TIMEOUT");
            break;

        default:
            // No implementation needed.
            break;
    }
}

 

step 5:

   保存配对信息

if(PasswordOk)
{
	PasswordOk = 0;
	App_RunNote_SaveData(&s_note);
}
 step 6: 

    恢复配置信息

  BSP_InnerFlash_Init();
  App_RunNote_ReadData(&s_note);
在上述的基础上只需修改两个地方即可实现,首先修m_sec_params.io_caps = BLE_GAP_IO_CAPS_NONE;   
static void sec_params_init()
{

    memset(&m_sec_params, 0, sizeof(ble_gap_sec_params_t));
	  

    m_sec_params.bond = SEC_PARAM_BOND; 

    m_sec_params.mitm = SEC_PARAM_MITM;

    m_sec_params.io_caps = BLE_GAP_IO_CAPS_NONE;
	
    m_sec_params.oob =  SEC_PARAM_OOB;
    m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;

    m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;

		m_sec_params.kdist_own.enc = 1;

		m_sec_params.kdist_own.id = 0;

		m_sec_params.kdist_own.sign = 0;

		m_sec_params.kdist_peer.enc = 1;

		m_sec_params.kdist_peer.id = 0;

		m_sec_params.kdist_peer.sign = 0;  

		m_sec_keyset.keys_own.p_enc_key = &m_own_enc_key;

		m_sec_keyset.keys_own.p_id_key = NULL;

		m_sec_keyset.keys_own.p_pk = NULL;

		m_sec_keyset.keys_own.p_sign_key = NULL;   

		m_sec_keyset.keys_peer.p_enc_key = &m_peer_enc_key;

		m_sec_keyset.keys_peer.p_id_key = NULL;

		m_sec_keyset.keys_peer.p_pk = NULL;

		m_sec_keyset.keys_peer.p_sign_key = NULL;

}			

其次在BLE_GAP_EVT_PASSKEY_DISPLAY事件中获取配对密码,由于uart例程没有显示功能,只能通过RTT打印密码

case BLE_GAP_EVT_PASSKEY_DISPLAY:                      

      NRF_LOG_INFO("passkey: %s\n",p_ble_evt->evt.gap_evt.params.passkey_display.passkey);                        

 break;   

静态密码在动态密码的基础上,增加如下代码,此代码在gap_params_init中添加

/**@brief Function for initializing the Connection Parameters module.
 */
static void conn_params_init(void)
{
    uint32_t               err_code;
    ble_conn_params_init_t cp_init;

    memset(&cp_init, 0, sizeof(cp_init));

    cp_init.p_conn_params                  = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
    cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
    cp_init.disconnect_on_fail             = false;
    cp_init.evt_handler                    = on_conn_params_evt;
    cp_init.error_handler                  = conn_params_error_handler;

    err_code = ble_conn_params_init(&cp_init);
    APP_ERROR_CHECK(err_code);
	//-----静态配对代码如下---------------------------
    ble_opt_t passkey_opt;
    uint8_t passkey[] = "123456";	
    passkey_opt.gap_opt.passkey.p_passkey = passkey;	
    err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &passkey_opt);		
    APP_ERROR_CHECK(err_code);

}

三种方式配对DEMO下载链接:https://download.csdn.net/download/mygod2008ok/11980301

 

 

 

 
关注
打赏
1658017818
查看更多评论
立即登录/注册

微信扫码登录

0.0757s