Android蓝牙协议栈fluoride(五) - 设备管理(bt application)

在上一篇Android蓝牙协议栈fluoride(四) - 设备管理(bt interface) 中梳理了设备管理器对上层提供的接口,本文将介绍这些接口的具体实现。
各个模块中采用了API+状态机+数据收发的方式,介绍设备管理时也将采用这个顺序介绍。
在这里插入图片描述

核心数据结构

设备管理的核心数据结构如下:

typedef struct {
  bool is_bta_dm_active;
  tBTA_DM_ACTIVE_LINK device_list; // 已连接设备列表
  tBTA_DM_SEC_CBACK* p_sec_cback;  // bt interface 注册的事件回调,BTA_EnableBluetooth()调用时注册 
  uint16_t state; // 设备管理的状态

  // 功耗管理与链接策略相关
  uint8_t pm_id;  
  tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER];
  uint32_t role_policy_mask;
  uint16_t cur_policy;
  uint16_t rs_event; // 设备角色切换事件
  uint8_t cur_av_count; // 已连接的audio/vedio数量
  tBTA_DM_API_SEARCH search_msg;  // 搜索设备的消息内容

  // page scan和inquiry scan相关参数
  uint16_t page_scan_interval;
  uint16_t page_scan_window;
  uint16_t inquiry_scan_interval;
  uint16_t inquiry_scan_window;

  // 配对时的pincode相关
  RawAddress pin_bd_addr;
  DEV_CLASS pin_dev_class;
  tBTA_DM_SEC_EVT pin_evt;

  // 本机与对端设备的IO能力
  tBTA_IO_CAP loc_io_caps;
  tBTA_IO_CAP rmt_io_caps;

  // 本机和对端设备的身份认证请求
  tBTA_AUTH_REQ loc_auth_req;
  tBTA_AUTH_REQ rmt_auth_req;

  uint32_t num_val; // 简单安全配对时向UI展示的数值,just work模式不需要展示
  bool just_works; // 是否是just work模式
  uint32_t eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE]; // EIR中的UUID mask
  tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback; // 加密相关的回调, BTA_DmSetEncryption()调用时注册
} tBTA_DM_CB;

搜索设备的核心数据结构如下(只列出了关注的几个字段):

typedef struct {
  tBTA_DM_SEARCH_CBACK* p_search_cback;  // 设备搜索/服务发现的事件回调,在BTA_DmSearch()/BTA_DmDiscover()函数中注册
  tBTM_INQ_INFO* p_btm_inq_info; // inquiry信息
  tBTA_SERVICE_MASK services; // 服务的mask
  tBTA_SERVICE_MASK services_to_search; // 搜索服务的mask
  tBTA_SERVICE_MASK services_found; // 已发现服务的mask
  tSDP_DISCOVERY_DB* p_sdp_db; // sdp的数据库
  uint16_t state; // 搜索设备的状态
  RawAddress peer_bdaddr; // 对端设备的地址
} tBTA_DM_SEARCH_CB;

API

设备管理提供的API如下:

使能蓝牙

// 使能/打开蓝牙, 在btif_init_ok()中调用
tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK* p_cback)
 -> bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg) // 向系统管理器注册设备管理的事件处理函数
 -> bta_dm_enable(p_cback) // enable蓝牙
  -> bta_sys_hw_register(BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback) // 向系统管理器注册硬件状态变化回调
  -> bta_sys_sendmsg(BTA_SYS_API_ENABLE_EVT) // 向系统管理器发送事件
 
// 禁用/关闭蓝牙
tBTA_STATUS BTA_DisableBluetooth(void)

设备发现

// 设置本机的发现模式:connectable, discoverable, pairable, conn paired only
void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, uint8_t pairable_mode, uint8_t conn_filter);
 -> bta_dm_set_visibility()
  -> BTM_SetDiscoverability()
  -> BTM_SetConnectability()
  -> BTM_SetPairableMode()

// 搜索周围的蓝牙设备
void BTA_DmSearch(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK* p_cback);
 -> bta_sys_sendmsg(BTA_DM_API_SEARCH_EVT) //向设备管理的事件处理发送搜索设备的事件

// 服务发现
void BTA_DmDiscover(const RawAddress& bd_addr, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search); 
 -> bta_sys_sendmsg(BTA_DM_API_DISCOVER_EVT)
void BTA_DmDiscoverUUID(const RawAddress& bd_addr, const bluetooth::Uuid& uuid, tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
 -> bta_sys_sendmsg(BTA_DM_API_DISCOVER_EVT)

// 取消搜索
void BTA_DmSearchCancel(void);
 -> bta_sys_sendmsg(BTA_DM_API_SEARCH_CANCEL_EVT)

// 从EIR中获取service mask
void BTA_GetEirService(uint8_t* p_eir, size_t eir_len, tBTA_SERVICE_MASK* p_services);

配对相关

// 发起配对
void BTA_DmBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBTA_TRANSPORT transport);
 -> bta_dm_bond()
  -> BTM_SecBond()
// 取消配对
void BTA_DmBondCancel(const RawAddress& bd_addr);
 -> bta_dm_bond_cancel()
  -> BTM_SecBondCancel()

// 设置pincode 
void BTA_DmPinReply(const RawAddress& bd_addr, bool accept, uint8_t pin_len, uint8_t* p_pin);
 -> bta_dm_pin_reply()
  -> BTM_PINCodeReply()
// 获取本地的oob数据
void BTA_DmLocalOob(void);
 -> BTM_ReadLocalOobData() // 通过bta_dm_co_loc_oob()上报结果
// 接受/拒绝 简单安全配对请求
void BTA_DmConfirm(const RawAddress& bd_addr, bool accept);
 -> bta_dm_confirm()
  -> BTM_ConfirmReqReply()

// 将已配对对端设备添加到安全数据库中,一般在系统初始化阶段调用
void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, const LinkKey& link_key, tBTA_SERVICE_MASK trusted_mask, bool is_trusted, uint8_t key_type, tBTA_IO_CAP io_cap, uint8_t pin_length);
 -> bta_dm_add_device()
  -> BTM_SecAddDevice()
// 从安全数据库中删除一个对端设备,通常在解除配对时调用
tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr);

其他

// 设置本机的蓝牙名称
void BTA_DmSetDeviceName(char* p_name);
// 获取已缓存的对端设备的名称
tBTA_STATUS BTA_DmGetCachedRemoteName(const RawAddress& remote_device, uint8_t** pp_cached_name);
// 获取连接状态
uint16_t BTA_DmGetConnectionState(const RawAddress& bd_addr);
// 向SDP数据库添加本地设备标识的SDP记录
tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info, uint32_t* p_handle);
// 强制关闭ACL连接,并从安全数据库中删除该设备
void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev, tBTA_TRANSPORT transport);

BLE 相关的API暂未列举,在后续文章中介绍。

状态机

设备管理中有4个状态,其转换关系如下(图中未列出的事件,表示发生该事件时不切换状态):
在这里插入图片描述

search是当前还未发现这个设备,通过inquiry去搜索周围的设备,而discover是已经发现了这个设备,通过SDP去获取这个设备支持的服务或者制定服务。

事件处理

设备管理中的事件处理是通过bta_dm_search_sm_execute()函数,在BTA_EnableBluetooth()函数中调用bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg)注册。设备管理中有10个事件以及对应的19处理函数(以下只介绍几个重点关注的函数):

  • bta_dm_search_start()
    该函数在idle状态下处理BTA_DM_API_SEARCH_EVT事件,流程如下:
    在这里插入图片描述
    在idle状态下收到BTA_DM_API_SEARCH_EVT事件后,首先判断是否需要延迟扫描,如:在播放状态下需要将本机角色切换为master,只能在master下进行搜索设备,如是slave将调用BTM_SwitchRole进行角色切换,切换完成后会通过回调通知调用方。然后需要清除inquiry数据库,并发起inquiry,并将搜索到的结果和搜索完成通过回调通知调用方,调用方将搜索结果通过bta_dm_search_start()调用时注册的回调上报,搜索完成后发出BTA_DM_INQ_CMPL_EVT事件,如果搜索到设备,还会通过bta_dm_discover_device发现服务,否则直接发出BTA_DM_SEARCH_CMPL_EVT事件。

  • bta_dm_search_cancel()
    在search cancel状态下收到BTA_DM_API_SEARCH_CANCEL_EVT,如果正在inquiry(即inquiry active状态)则调用BTM_CancelInquiry取消inquiry并发出BTA_DM_SEARCH_CMPL_EVT事件,如果是discover active状态则调用BTM_CancelRemoteDeviceName取消discover并发出BTA_DM_SEARCH_CMPL_EVT事件,否则直接发出BTA_DM_INQUIRY_CMPL_EVT事件。
    在这里插入图片描述

  • bta_dm_discover()
    在idle状态下收到BTA_DM_API_DISCOVER_EVT事件时,发起服务发现动作,首先根据MAC地址获取inquiry信息(调用BTM_InqDbRead), 然后调用bta_dm_discover_device发现服务,根据参数判断是否需要获取对端设备的名称,如需要则发起获取名称的请求,获取到对端设备名称后在发起服务发现请求,如果已经获取到对端名称,则判断是否需要发现服务,需要时发起SDP请求,否则直接发出BTA_DM_DISCOVERY_RESULT_EVT事件,函数调用和程序流程如下:

bta_dm_discover()
 -> BTM_InqDbRead()
 -> bta_dm_discover_device()
  -> bta_dm_read_remote_device_name() // 获取对端设备名称
   -> BTM_ReadRemoteDeviceName()
  -> bta_dm_eir_search_services() // 判断EIR中包含了哪些服务
  -> bta_dm_find_services() // 未包含在EIR中的则发起服务发现
   -> SDP_InitDiscoveryDb()
   -> SDP_ServiceSearchAttributeRequest()
  -> bta_sys_sendmsg(BTA_DM_DISCOVERY_RESULT_EVT)

在这里插入图片描述

  • bta_dm_inq_cmpl()
    在search active状态下收到BTA_DM_INQUIRY_CMPL_EVT事件时调用该函数,在bta_dm_search_start函数中inquiry完成的回调中会收到该事件,此处不再重复描述。
  • bta_dm_rmt_name()
    在search active状态下收到BTA_DM_REMT_NAME_EVT事件时调用,在该函数中发起服务发现请求,服务发现参考bta_dm_discover函数, BTA_DM_REMT_NAME_EVT在收到BTM_ReadRemoteDeviceName中注册,收到对端设备名称时回调。
  • bta_dm_sdp_result()
    在search active和discover active状态下收到BTA_DM_SDP_RESULT_EVT事件时调用,解析SDP的结果后发出BTA_DM_DISCOVERY_RESULT_EVT事件,BTA_DM_SDP_RESULT_EVT事件在SDP_ServiceSearchAttributeRequest注册的回调中发出。
  • bta_dm_search_cmpl()
    在search active和search canceling状态下收到BTA_DM_SEARCH_CMPL_EVT事件时调用,该函数中上报BTA_DM_DI_DISC_CMPL_EVT或BTA_DM_DISC_CMPL_EVT事件。
  • bta_dm_disc_result()
    在discover active状态下收到BTA_DM_DISCOVERY_RESULT_EVT事件时调用,函数中发出BTA_DM_SEARCH_CMPL_EVT事件,同时在服务发现完成时上报BTA_DM_DISC_RES_EVT事件。
  • bta_dm_search_result()
    在search active状态下收到BTA_DM_DISCOVERY_RESULT_EVT事件时调用,上报BTA_DM_DISC_RES_EVT事件,如果需要,发起下一个设备的服务发现。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙HarmonyOS4.0 入门与实战

一、开发准备: 熟悉鸿蒙官网安装DevEco Studio熟悉鸿蒙官网 HarmonyOS应用开发官网 - 华为HarmonyOS打造全场景新服务 应用设计相关资源: 开发相关资源: 例如开发工具 DevEco Studio 的下载 应用发布: 开发文档:

论文阅读《High-frequency Stereo Matching Network》

论文地址:https://openaccess.thecvf.com/content/CVPR2023/papers/Zhao_High-Frequency_Stereo_Matching_Network_CVPR_2023_paper.pdf 源码地址: https://github.com/David-Zhao-1997/High-frequency-Stereo-Matching-Network 概述 在立体匹配研究领域…

OpenAI承认GPT-4变懒,即将发布修复方案提升性能

目录 1OpenAI承认GPT-4变懒,即将发布修复方案提升性能 2一文秒懂人工智能全球近况 1OpenAI承认GPT-4变懒,即将发布修复方案提升性能 **划重点:** 1. 🤯 用户反馈:GPT-4使用者抱怨OpenAI破坏了体验,称模型几乎“害怕”提供答案。…

UE4 透明物体不渲染显示??

问题描述:半透明特效在背景(半透明材质模型)前,当半透明特效开始移动的时候,随着速度的加快会逐渐不渲染! 解决办法: 1.设置透明度排序 2.如果还没效果,修改半透明背景模型以下材质…

安全开发:身份认证方案之 Google 身份验证器和基于时间的一次性密码 TOTP 算法

参考资料在文末注明,如本文有错漏欢迎评论区指出👏 目前很多应用都逐步采用了双因子认证或者说MFA认证方案,因此本文介绍一下背后的机制和TOTP算法原理。使用TOTP算法,只要满足两个条件:1)基于相同的密钥&…

HTML行内元素和块级元素的区别? 分别有哪些?

目录 一、行内元素和块级元素的区别二、行内元素和块级元素分别有哪些1、行内元素2、块级元素 一、行内元素和块级元素的区别 1、行内元素不会占据整行,在一条直线上排列,都是同一行,水平方向排列;    2、块级元素可以包含行内…

订单接入支付宝流程实战与优化

概述 了解支付宝支付能力接入方式。电商项目如何对支付流程进行设计及优化。基于 RocketMQ 事务消息实现的订单确认机制,来完成订单超时回退功能。 支付宝接入流程简介 国内目前有支付牌照的公司总共只有两百来家,比如支付宝、云闪付、和包支付、翼支…

《PySpark大数据分析实战》-02.了解Hadoop

📋 博主简介 💖 作者简介:大家好,我是wux_labs。😜 热衷于各种主流技术,热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员(PCTA)、TiDB数据库专家(PCTP…

Flutter:web项目跨域问题解决

前后端解决系列 文章目录 一、Flutter web客户端解决本地环境调试跨域问题二、Flutter web客户端解决线上环境跨域问题 一、Flutter web客户端解决本地环境调试跨域问题 就一句命令【--web-browser-flag "--disable-web-security"】,用来屏蔽浏览器域名请…

axios 基础的 一次封装 二次封装

一、平常axios的请求发送方式 修改起来麻烦的一批 代码一大串 二、axios的一次封装 我们会在src/utils创建一个request.js的文件来存放我们的基地址与拦截器 /* 封装axios用于发送请求 */ import axios from axios/* (1)request 相当于 Axios 的实例对象 (2)为什么要有reque…

件夹和文件比较软件VisualDiffer mac功能介绍

VisualDiffer mac是一款运行在MacOS上的文件夹和文件快速比较工具。VisualDiffer可以对不同文件夹中文件或文档做出比较或者比较两个文件的路径。还可以通过UNIS diff命令快速、标准和可靠的比较出各类不同的文件夹和文件结果,使用不同的颜色直观地显示。 VisualDif…

西南科技大学数字电子技术实验四(基本触发器逻辑功能测试及FPGA的实现)预习报告

一、计算/设计过程 说明:本实验是验证性实验,计算预测验证结果。是设计性实验一定要从系统指标计算出元件参数过程,越详细越好。用公式输入法完成相关公式内容,不得贴手写图片。(注意:从抽象公式直接得出结果,不得分,页数可根据内容调整) (1)D触发器 特征方程: Q…

事务的四个特性、四个隔离级别以及数据库的常用锁

事务的四个特性、四个隔离级别以及数据库的常用锁 四大特性 事务的四大特性,通常被称为ACID特性,是数据库管理系统(DBMS)确保事务处理的关键属性。这四大特性分别是: 原子性(Atomicity)&#x…

微服务-理论 分布式事务

一、分布式事务理论模型 分布式事务问题也叫分布式数据一致性问题,简单来说就是如何在分布式场景中保证多个节点数据的一致性。分布式事务产生的核心原因在于存储资源的分布性,比如多个数据库,或者MySQL和Redis两种不同存储设备的数据一致性…

安装ThingBox Eclipse Plugin

1. ChatGPT问 The latest version of the ThingBox Eclipse Plugin requires Eclipse IDE 2021-06 or later. 2. PTC官网下载 MED-61378-CD-092_F000_Eclipse-Plugin-9-0-1.zip文件, 和 MED-61098-CD-085_F000_ThingWorx-Extension-SDK-8-5-0(需要账号&#xff09…

04-Nacos中负载均衡规则的配置

负载均衡规则 同集群优先 默认的ZoneAvoidanceRule实现并不能根据同集群优先的规则来实现负载均衡,Nacos中提供了一个实现叫NacosRule可以优先从同集群中挑选服务实例 当服务消费者在本地集群找不到服务提供者时也会去其他集群中寻找,但此时会在服务消费者的控制台报警告 第…

day33-37-SpringBootV12(整合Spring,SpringMVC,Mybatis,日志,api测试等框架)

ssm spring --> applicationContext.xml配置文件 springmvc --> springmvc.xml配置文件 mybatis —> mybatis-config.xml配置文件 —> springboot优化了之前的框架配置,思想是约定大于配置 一、引言 1.1 初始化配置 为了使用SSM框架去开发,准备SSM…

mysql数据库学习笔记(1)

今天开始学mysql数据库,为什么要学这个呢,因为数据库可结构化存储大量的数据信息,方便用户进行有效的检索和访问。数据库可有效地保持数据信息的一致性、完整性、降低数据冗余。数据库可满足应用的共享和安全方面的要求,把数据放在…

WPF仿网易云搭建笔记(4):信息流控制之消息订阅

文章目录 专栏和Gitee仓库前言消息订阅最简单的案例简单用例父组件订阅子组件回调 结果 消息订阅机制消息token是A还是B?传递消息的载体。双重token重复订阅问题 结论 专栏和Gitee仓库 WPF仿网易云 Gitee仓库 WPF仿网易云 CSDN博客专栏 前言 上一篇文章中,我们简单…

【三维重建】对极几何

极几何描述了同一场景或者物体的两个视点图像间的几何关系 可以发现P在左右相机的投影点一定在各自的极线上,如果求出极线就能缩小求解对应点的范围。 本质矩阵对规范化摄像机拍摄的两个视点图像间的极几何关系进行代数描述 规范化相机指的是相机的内参…