NRF52832学习笔记(23)——GAP主机端连接

一、背景

链路层(LL) 控制设备的射频状态,有五个设备状态:待机、广播、扫描、初始化和连接。

广播 为广播数据包,而 扫描 则是监听广播。

GAP通信中角色,中心设备(Central - 主机) 用来扫描和连接 外围设备(Peripheral - 从机)

二、配置连接参数

定义连接的参数,这个参数将在sd_ble_gap_connect()函数中被调用。

// 定义连接参数
static ble_gap_conn_params_t m_conn_params = 
{
    .min_conn_interval  = MSEC_TO_UNITS(NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL, UNIT_1_25_MS),  // 最小连接间隔7.5ms
    .max_conn_interval  = MSEC_TO_UNITS(NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL, UNIT_1_25_MS),  // 最大连接间隔30ms  
    .slave_latency      = NRF_BLE_SCAN_SLAVE_LATENCY,                                         // 隐藏周期0 
    .conn_sup_timeout   = MSEC_TO_UNITS(NRF_BLE_SCAN_SUPERVISION_TIMEOUT, UNIT_10_MS),        // 超时时间4000ms 
};

三、连接相关函数

3.1 nrf_ble_scan_stop

配置好准备连接的设备的MAC信息,在发起连接之前,我们一定要先调用nrf_ble_scan_stop()函数去停止扫描,不然会出错。

停止扫描之后,我们调用sd_ble_gap_connect()函数,发起对从机设备的连接。

3.2 sd_ble_gap_connect

3.3 sd_ble_gap_disconnect

调用该方法就可以主动断开蓝牙的连接
sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);

四、发起连接

在扫描回调事件处理的函数中,前面一部分就是获取扫描到的从机设备的信息。

我们对扫描到的从机设备的RSSI进行了判断,我们人为定义,当设备的RSSI大于-30dBm的时候,也就是信号强度非常好,我们就默认连接该设备。

首先,我们先定义准备连接的从机设备的地址和信息,配置m_addr.addr_type为BLE_GAP_ADDR_TYPE_RANDOM_STATIC,配置m_addr.addr为扫描到的设备地址p_scan_evt->params.p_not_found->peer_addr.addr。

配置好准备连接的设备的MAC信息,在发起连接之前,我们一定要先调用nrf_ble_scan_stop()函数去停止扫描,不然会出错。

停止扫描之后,我们调用sd_ble_gap_connect()函数,发起对从机设备的连接。

//******************************************************************
// fn : scan_evt_handler
//
// brief : 处理扫描回调事件
//
// param : scan_evt_t  扫描事件结构体
//
// return : none
static void scan_evt_handler(scan_evt_t const * p_scan_evt)
{
    switch(p_scan_evt->scan_evt_id)
    {
        // 未过滤的扫描数据
        case NRF_BLE_SCAN_EVT_NOT_FOUND:
        {
          // 判断是否为扫描回调数据
          if(p_scan_evt->params.p_not_found->type.scan_response)
          {
            if(p_scan_evt->params.p_not_found->data.len)    // 存在扫描回调数据
            {
              NRF_LOG_INFO("scan data:  %s",
                            Util_convertHex2Str(
                            p_scan_evt->params.p_not_found->data.p_data,
                            p_scan_evt->params.p_not_found->data.len));
            }
            else
            {
              NRF_LOG_INFO("scan data:  %s","NONE");
            }
            NRF_LOG_INFO("rssi:  %ddBm",p_scan_evt->params.p_not_found->rssi);
          }
          else  // 否则为广播数据
          {
            // 打印扫描的设备MAC
            NRF_LOG_INFO("Device MAC:  %s",
                         Util_convertBdAddr2Str((uint8_t*)p_scan_evt->params.p_not_found->peer_addr.addr));
            
            if(p_scan_evt->params.p_not_found->data.len)    // 存在广播数据
            {
              NRF_LOG_INFO("adv data:  %s",
                            Util_convertHex2Str(
                            p_scan_evt->params.p_not_found->data.p_data,
                            p_scan_evt->params.p_not_found->data.len));
            }
            else
            {
              NRF_LOG_INFO("adv data:  %s","NONE");
            }
          }
          
          
          // 如果扫描到的设备信号强度大于-30dBm
          if(p_scan_evt->params.p_not_found->rssi > (-30))
          {
            ret_code_t          err_code;
            
            // 配置准备连接的设备MAC
            ble_gap_addr_t m_addr;
            m_addr.addr_id_peer = 1;
            m_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC;
            memcpy(m_addr.addr,p_scan_evt->params.p_not_found->peer_addr.addr,BLE_GAP_ADDR_LEN);
            
            // 停止扫描
            nrf_ble_scan_stop();
            // 发起连接
            err_code = sd_ble_gap_connect(&m_addr,&m_scan_params,&m_conn_params,APP_BLE_CONN_CFG_TAG);
            APP_ERROR_CHECK(err_code);
          }
          
        } break;

        default:
           break;
    }
}

五、连接事件处理

当我们的主机设备进行连接,或者断开连接的时候,BLE的事件回调中,都会给我们状态事件提示。

连接成功的状态 BLE_GAP_EVT_CONNECTED,我们可以在这边获取到连接的设备的MAC、连接参数等等。

断开连接的状态 BLE_GAP_EVT_DISCONNECTED,我们可以获取到断开的连接的原因等等。

BLE_GAP_EVT_TIMEOUT GAP连接超时事件。当主从机连接一直不成功,超过了连接事件最大的时间,则协议栈触发GAP连接超时事件。这个连接最大的事件就是GAP中的监督超时时间(连接超时时间)。

BLE_GATT_EVT_TIMEOUT 主机GATT连接超时事件。本质上不属于连接时发生的事情,而是连接中发生的事情。当正在连接的主从机由于某种原因发生断开,主机设备发起多次连接请求没有回应就会发生GATT连接超时事件。协议栈将禁用所有ATT流量并将ATT连接标记为down,但是由应用程序必须主动的使用sd_ble_gap_disconnect()完成最后的断开连接。

//******************************************************************
// fn : ble_evt_handler
//
// brief : BLE事件回调
// details : 包含以下几种事件类型:COMMON、GAP、GATT Client、GATT Server、L2CAP
//
// param : ble_evt_t  事件类型
//         p_context  未使用
//
// return : none
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    ble_gap_evt_connected_t const * p_connected_evt = &p_gap_evt->params.connected;
    switch (p_ble_evt->header.evt_id)
    {
        // 连接
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("Connected. conn_DevAddr: %s\nConnected. conn_handle: 0x%04x\nConnected. conn_Param: %d,%d,%d,%d",
                         Util_convertBdAddr2Str((uint8_t*)p_connected_evt->peer_addr.addr),
                         p_gap_evt->conn_handle,
                         p_connected_evt->conn_params.min_conn_interval,
                         p_connected_evt->conn_params.max_conn_interval,
                         p_connected_evt->conn_params.slave_latency,
                         p_connected_evt->conn_params.conn_sup_timeout
                         );
            break;
        // 断开连接
        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%04x",
                         p_gap_evt->conn_handle,
                         p_gap_evt->params.disconnected.reason);
            // 如果需要异常断开重连,可以打开下面的注释
            // scan_start();  // 重新开始扫描
            break;

        case BLE_GAP_EVT_TIMEOUT:
        {		            
            // We have not specified a timeout for scanning, so only connection attemps can timeout.
            if(p_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
            {
                NRF_LOG_DEBUG("Connection request timed out.");
            }
            
            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            // Start scanning
            scan_start();
        } break;

        case BLE_GATTC_EVT_TIMEOUT:
        {
            NRF_LOG_INFO("{0x%x BLE_GATTC_EVT_TIMEOUT}", p_gap_evt->conn_handle);
            
            // 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);
            
            scan_start();
        } break;

        default:
            break;
    }
}

• 由 Leung 写于 2020 年 8 月 10 日

• 参考:青风电子社区
    NRF52832DK协议栈实验——17 通用连接实验

猜你喜欢

转载自blog.csdn.net/qq_36347513/article/details/107911309