蓝牙----蓝牙连接建立_连接建立

news2024/11/17 6:18:44

蓝牙----蓝牙连接建立_连接建立

  • 蓝牙连接建立过程图
  • 1.主机扫描到广播包
    • 1.1判断是否是自己关心的广播包
    • 1.2广播地址添加到扫描列表
  • 2.主机扫描结束,建立连接
  • 3.主从连接成功后,执行连接建立后事件
    • 3.1.主机将连接句柄和设备地址添加到连接列表
    • 3.2.主机进行GATT服务的发现
    • 3.3.从机获取连接句柄,并发起连接参数更新
  • 4.从机发起连接参数更新
    • 4.1主机收到连接参数更新请求
    • 4.2从机进行连接参数更新


蓝牙连接建立过程图

在这里插入图片描述

1.主机扫描到广播包

执行注册的回调函数,触发APP层SC_EVT_ADV_REPORT事件

      //判断广播包是否是自己关心的
      if (SimpleCentral_findSvcUuid(SIMPLEPROFILE_SERV_UUID,
                                    pAdvRpt->pData, pAdvRpt->dataLen))
      {
        //将广播设备的地址和地址类型添加到扫描列表中
        SimpleCentral_addScanInfo(pAdvRpt->addr, pAdvRpt->addrType);
        Display_printf(dispHandle, SC_ROW_NON_CONN, 0, "Discovered: %s",
                       Util_convertBdAddr2Str(pAdvRpt->addr));
      }

1.1判断是否是自己关心的广播包

SimpleCentral_findSvcUuid是查看广播包是否包含自己设置的UUID(SIMPLEPROFILE_SERV_UUID)。
广播包的判断有多种也可以对广播数据判断。

从机的广播数据
	static uint8_t advertData[] =
	{
	  0x02,   // length of this data
	  GAP_ADTYPE_FLAGS,
	  DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
	  // service UUID, to notify central devices what services are included
 	 // in this peripheral
 	 0x03,   // length of this data
 	 GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
 	 LO_UINT16(SIMPLEPROFILE_SERV_UUID),
	  HI_UINT16(SIMPLEPROFILE_SERV_UUID)
};
主机扫描UUID判断
        if ((adType == GAP_ADTYPE_16BIT_MORE) ||   (adType == GAP_ADTYPE_16BIT_COMPLETE))
        {
          pData++;
          adLen--;
          // For each UUID in list
          while (adLen >= 2 && pData < pEnd)
          {
            // Check for match
            if ((pData[0] == LO_UINT16(uuid)) && (pData[1] == HI_UINT16(uuid)))
            {
              // Match found
              return TRUE;
            }
            // Go to next
            pData += 2;
            adLen -= 2;
          }
        }
 

1.2广播地址添加到扫描列表

SimpleCentral_addScanInfo(pAdvRpt->addr, pAdvRpt->addrType);

//添加一个设备到扫描列表
static void SimpleCentral_addScanInfo(uint8_t *pAddr, uint8_t addrType)
{
  uint8_t i;
  // If result count not at max
  // DEFAULT_MAX_SCAN_RES扫描结果的最大数目
  if (numScanRes < DEFAULT_MAX_SCAN_RES)
  {
    // Check if device is already in scan results
    for (i = 0; i < numScanRes; i++)
    {
      if (memcmp(pAddr, scanList[i].addr , B_ADDR_LEN) == 0)
      {
        return;
      }
    }
    // Add addr to scan result list
    memcpy(scanList[numScanRes].addr, pAddr, B_ADDR_LEN);
    scanList[numScanRes].addrType = addrType;
    // Increment scan result count
    numScanRes++;
  }
}

当到达最大扫描数目时,执行GapScan_disable(),并执行回调函数,触发SC_EVT_SCAN_DISABLED事件

2.主机扫描结束,建立连接

处理SC_EVT_SCAN_DISABLED事件,进行GAP连接

 GapInit_connect(tempMember->addrType & MASK_ADDRTYPE_ID,tempMember->addr, DEFAULT_INIT_PHY, CONNECTION_TIMEOUT);

3.主从连接成功后,执行连接建立后事件

GapInit_connect成功返回GAP层事件GAP_LINK_Estableished,主机及从机进行事件处理

3.1.主机将连接句柄和设备地址添加到连接列表

SimpleCentral_addConnInfo(connHandle, pAddr);

//添加一个设备到 连接列表
static uint8_t SimpleCentral_addConnInfo(uint16_t connHandle, uint8_t *pAddr)
{
  uint8_t i;

  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
  {
    if (connList[i].connHandle == CONNHANDLE_INVALID)
    {
      // Found available entry to put a new connection info in
      connList[i].connHandle = connHandle;
      memcpy(connList[i].addr, pAddr, B_ADDR_LEN);
      numConn++;

      break;
    }
  }

  return i;
}

其中connList[]元素结构体定义如下

//连接设备信息
typedef struct
{
  uint16_t connHandle;        // Connection Handle          连接句柄
  uint8_t  addr[B_ADDR_LEN];  // Peer Device Address        连接对端设备地址
  uint8_t  charHandle;        // Characteristic Handle      特征值句柄
  Clock_Struct *pRssiClock;   // pointer to clock struct
} connRec_t;

3.2.主机进行GATT服务的发现

蓝牙----蓝牙消息传输_GATT服务发现

3.3.从机获取连接句柄,并发起连接参数更新

SimplePeripheral_addConn(pPkt->connectionHandle);
从机获取连接句柄,并判断是否到达连接数目,选择继续/停止广播
连接参数更新在自定义的SP_SEND_PARAM_UPDATE_DELAY(6S)后,从机发起

//从机获取连接句柄,进行连接参数更新
static uint8_t SimplePeripheral_addConn(uint16_t connHandle)
{
  uint8_t i;
  uint8_t status = bleNoResources;

  // Try to find an available entry
  for (i = 0; i < MAX_NUM_BLE_CONNS; i++)
  {
    if (connList[i].connHandle == CONNHANDLE_INVALID)
    {
      // Found available entry to put a new connection info in
      connList[i].connHandle = connHandle;

      // Allocate data to send through clock handler
      connList[i].pParamUpdateEventData = ICall_malloc(sizeof(spClockEventData_t) +
                                                       sizeof (uint16_t));
      if(connList[i].pParamUpdateEventData)
      {
        connList[i].pParamUpdateEventData->event = SP_SEND_PARAM_UPDATE_EVT;
        *((uint16_t *)connList[i].pParamUpdateEventData->data) = connHandle;

        // Create a clock object and start
        connList[i].pUpdateClock
          = (Clock_Struct*) ICall_malloc(sizeof(Clock_Struct));
        //启动连接参数更新
        if (connList[i].pUpdateClock)
        {
          Util_constructClock(connList[i].pUpdateClock,
                              SimplePeripheral_clockHandler,
                              SP_SEND_PARAM_UPDATE_DELAY, 0, true,
                              (UArg) (connList[i].pParamUpdateEventData));
        }
        else
        {
            ICall_free(connList[i].pParamUpdateEventData);
        }
      }
      else
      {
        status = bleMemAllocError;
      }

      // Set default PHY to 1M
      connList[i].currPhy = HCI_PHY_1_MBPS;

      break;
    }
  }

  return status;
}

4.从机发起连接参数更新

从机发送连接参数更新GAP_UpdateLinkParamReq

4.1主机收到连接参数更新请求

主机GAP收到GAP_UPDATE_LINK_PARAM_REQ_EVENT连接请求事件,获取新的连接参数,执行连接请求回应GAP_UpdateLinkParamReqReply。

 case GAP_UPDATE_LINK_PARAM_REQ_EVENT:
    {
      gapUpdateLinkParamReqReply_t rsp;
      gapUpdateLinkParamReq_t *pReq;

      pReq = &((gapUpdateLinkParamReqEvent_t *)pMsg)->req;

      rsp.connectionHandle = pReq->connectionHandle;
      rsp.signalIdentifier = pReq->signalIdentifier;
      //允许连接参数更新
      if (acceptParamUpdateReq)
      {
          //收到的 新的连接请求参数
        rsp.intervalMin = pReq->intervalMin;
        rsp.intervalMax = pReq->intervalMax;
        rsp.connLatency = pReq->connLatency;
        rsp.connTimeout = pReq->connTimeout;
        rsp.accepted = TRUE;
      }
      else
      {
        // Reject the request.
        rsp.accepted = FALSE;
      }
      // Send Reply
      // 连接请求回应
      VOID GAP_UpdateLinkParamReqReply(&rsp);
      break;
    }

连接请求回应GAP_UpdateLinkParamReqReply,触发主机的GAP_LINK_PARAM_UPDATE_EVENT事件,对连接参数更新成功与失败情况进行判决。

4.2从机进行连接参数更新

主机向从机连接请求回应GAP_UpdateLinkParamReqReply后,对连接参数更新成功与失败情况进行判决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1418166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ad18学习笔记十六:v割

所谓“V割”是印刷电路板&#xff08;PCB&#xff09;厂商依据客户的图纸要求&#xff0c;事先在PCB的特定位置用转盘刀具切割好的一条条分割线&#xff0c;其目的是为了方便后续SMT电路板组装完成后的分板之用&#xff0c;因为其切割后的外型看起来就像个英文的“V”字型&…

msfconsole实战使用(结合靶场演示)

msfconsole实战使用 前言 MSFconsole&#xff08;Metasploit Framework Console&#xff09;是Metasploit框架的一部分&#xff0c;是一个功能强大的渗透测试工具。Metasploit框架是一个开源的安全工具&#xff0c;旨在开发、测试和执行针对计算机系统的攻击。MSFconsole是Me…

SpringMvc切换Json转换工具

SpringBoot切换使用goolge的Gson作为SpringMvc的Json转换工具 <!-- gson依赖 --> <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId> </dependency>Configuration public class JsonWebConfig {B…

ThreadLocal学习笔记

ThreadLocal类图 ThreadLocal/InheritableThreadLocal/ \TransmittableThreadLocal(阿里巴巴) TransmissibleThreadLocal(阿里巴巴)ThreadLocal 这是Thread类的局部变量&#xff0c;每个线程私有。 它主要用于解决多线程中的数据共享问题&#xff0c;保…

把数组中的key都取出来然后去重

今日接到一个小需求&#xff0c;一张表有类似这样的数据&#xff1a;&#xff08;下面是一行&#xff09; 但是每行的数据&#xff0c;主要是key不一样&#xff0c;我们想把所有的key取出来&#xff0c;并且做个去重。 首先我先在mysql中&#xff0c; SELECT GROUP_CONCAT(RE…

在租户内启用SharePoint Embedded

要开启 SharePoint Embedded&#xff0c;你得是管理员&#xff0c;然后按照这些步骤操作&#xff1a; 登录到你的 SharePoint 管理中心。在左边的菜单里找到“设置”选项&#xff0c;点进去。 3. 在设置页面里找到“SharePoint Embedded 应用”。 4.如果这个功能还没开启&…

高阶测试开发必备技能: k8s入门!

现在稍微有点规模公司都是基于docker容器化部署技巧&#xff0c;K8s现在主流&#xff0c;应用最广的容器集群管理技术。 k8s全称kubernetes&#xff08;首字母为 k、首字母与尾字母之间有 8 个字符、尾字母为 s&#xff0c;所以简称 k8s&#xff09;&#xff0c;基于Docker容器…

Top-level await is not available in the configured target environment

当在使用 Vite 进行项目构建时&#xff0c;可能会遇到如下错误提示&#xff1a;ERROR: Top-level await is not available in the configured target environment。 问题原因 这个错误通常是由于项目配置中的目标浏览器环境不支持 JavaScript 的 top-level-await 特性。top-le…

探索Viper-适用于GoLang的完整配置解决方案

前言 对于现代应用程序&#xff0c;尤其大中型的项目来说&#xff0c;在程序启动和运行时&#xff0c;往往需要传入许多参数来控制程序的行为&#xff0c;我们可以通过命令行参数&#xff0c;环境变量&#xff0c;配置文件等方式来将参数传递给程序。而Viper库为Golang语言开发…

Mac安装配置maven

Mac安装配置maven 官网下载地址&#xff1a;https://maven.apache.org/download.cgi 下载好以后解压配置 maven 环境变量 打开终端&#xff0c;输入命令打开配置文件./bash_profile open ~/.bash_profile输入i进入编辑模式,进行maven配置; MAVEN_HOME为maven的本地路径 ex…

VR全景技术对党建宣传有什么好处,如何应用在党建宣传

引言&#xff1a; 近年来&#xff0c;随着VR&#xff08;虚拟现实&#xff09;全景技术的不断发展&#xff0c;其在各个领域的应用也愈加广泛。在党建宣传方面&#xff0c;VR全景技术正逐渐成为一种创新而强大的工具&#xff0c;为组织的思想宣传提供了全新的方式。 一&#x…

SpringBoot 实现自定义指标监控

一、添加业务监控指标 在 spring-web-prometheus-demo 项目的基础上&#xff0c;我们添加一个 PrometheusCustomMonitor 类。在这里面我们定义了三个业务指标&#xff1a; order_request_count&#xff1a;下单总次数order_amount_sum&#xff1a;下单总金额 Component publ…

全球医疗器械产品查询-30个官网查询系统合集!

国内外上市医疗器械产品数据及注册备案信息是医疗器械行业中极其重要的情报之一。大多数医械人都知道国内医疗器械产品信息可在NPMA及各省市药监局官网查询&#xff0c;但对于国际的医疗器械产品数据披露平台&#xff0c;由于语言壁垒及网页设计习惯差异&#xff0c;查询却不太…

深入了解Redis:选择适用于你的场景的持久化方案

自然语言处理的发展 文章目录 自然语言处理的发展强烈推荐前言&#xff1a;Redis提供了几种主要的持久化方案&#xff1a;RDB快照持久化&#xff1a;工作原理&#xff1a; AOF日志文件持久化&#xff1a;混合持久化&#xff1a; 总结强烈推荐专栏集锦写在最后 强烈推荐 前些天…

厨房用品国际市场拓展:如何利用海外网红营销助力品牌成长

随着全球化的加速和互联网的普及&#xff0c;越来越多的中国厨房用品品牌开始寻求海外市场的拓展。而在这一过程中&#xff0c;海外网红营销正崭露头角&#xff0c;为品牌的跨足国际市场提供了强有力的助力。本文Nox聚星将和大家探讨如何通过海外网红营销助力厨房用品品牌在海外…

第四篇【传奇开心果系列】beeware的Toga开发移动应用示例:健身追踪应用

传奇开心果博文系列 系列博文目录beeware的Toga开发移动应用示例系列博文目录前言一、记录存储运动活动数据二、添加添加统计显示功能三、添加图表显示数据分析功能四、增加健身计划管理五、增加备份数据恢复数据功能六、初步整合代码示例七、增加登录验证功能八、完成最终整合…

什么是数据库设计?基本步骤有哪些?

数据库设计结构图 实线代表输入&#xff0c;虚线代表输出&#xff0c;每个节点的输出作为下一个节点的输入。 基本步骤 1.需求分析阶段 数据需求分析是在项目确定之后&#xff0c;用户和设计人员对数据库应用系统所要涉及的内容&#xff08;数据&#xff09;和功能&#xff0…

vmware虚拟机centos8共享文件夹挂载

1.设置虚拟机共享文件夹 2. 上述设置完毕之后&#xff0c;重启进入虚拟机&#xff0c;查看出现的共享文件夹名称 vmware-hgfsclient 3.查看是否有挂载目录&#xff0c;挂在目录默认为 /mnt/hgfs。没有时可以使用以下命令创建 mkdir /mnt/hgfs 4. 手动挂载目录--只能实现一次 注…

【python】argparse解析参数的过程

python基础知识 python文件解析if \_\_name\_\_ \_\_main\_\_的作用import到底导入了什么&#xff1f;argparse解析命令行参数的过程Debug—案例分析 python文件解析 Python和C语言的编译、执行过程有很大区别。我们先回顾一下c语言的执行过程&#xff0c;首先代码文件要编译…

GitLab 中国发行版如何设置镜像拉取策略?

最近在用极狐GitLab&#xff08;极狐GitLab 可以理解为 GitLab 在中国的发行版&#xff09; CI/CD 的时候遇到一个问题&#xff1a;CI/CD 中有一个 stage 需要拉取 dockerhub 上的镜像&#xff0c;但是由于 dockerhub 在国内的访问不是很顺畅&#xff0c;经常发生 timeout 的情…