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()函数,发起对从机设备的连接。

char *Util_convertBdAddr2Str(uint8_t *pAddr)
{
  uint8_t     charCnt;
  char        hex[] = "0123456789ABCDEF";
  static char str[(2*B_ADDR_LEN)+3];
  char        *pStr = str;
 
  *pStr++ = '0';
  *pStr++ = 'x';
 
  // Start from end of addr
  pAddr += B_ADDR_LEN;
 
  for (charCnt = B_ADDR_LEN; charCnt > 0; charCnt--)
  {
    *pStr++ = hex[*--pAddr >> 4];
    *pStr++ = hex[*pAddr & 0x0F];
  }
  *pStr = NULL;
 
  return str;
}

//******************************************************************
// 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()完成最后的断开连接。

char *Util_convertBdAddr2Str(uint8_t *pAddr)
{
  uint8_t     charCnt;
  char        hex[] = "0123456789ABCDEF";
  static char str[(2*B_ADDR_LEN)+3];
  char        *pStr = str;
 
  *pStr++ = '0';
  *pStr++ = 'x';
 
  // Start from end of addr
  pAddr += B_ADDR_LEN;
 
  for (charCnt = B_ADDR_LEN; charCnt > 0; charCnt--)
  {
    *pStr++ = hex[*--pAddr >> 4];
    *pStr++ = hex[*pAddr & 0x0F];
  }
  *pStr = NULL;
 
  return str;
}

//******************************************************************
// 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 通用连接实验

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343