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

Android蓝牙协议栈fluoride(五) - 设备管理(bt application)中描述了设备管理中的API、状态机以及事件处理,接下来将描述设备管理中的功耗管理和上报到上层的事件。

功耗管理

连接策略

蓝牙设备有很大比例都是带电池的产品,那么功耗的高低直接决定了使用时间的长短,蓝牙在工作时有时候需要连续传输数据或者实时的传输数据(如播放音乐/通话等),有时仅仅建立了连接并没有业务处理(如音乐暂停但连接并未断开),那么就希望有业务时能实时的传输数据,没有业务时保持连接的同时有较低的功耗,因此就产生以下模式(策略):
在这里插入图片描述

  • active模式
    有业务时实时(宏观上)传输数据。
    在这里插入图片描述
  • sniff模式
    没有业务时定期发送心跳保持连接,待有业务时切换到active模式。
    在这里插入图片描述
  • hold模式
    该模式下,不支持ACL通道上的数据传输(SCO通道可以传输数据),因此设备可以利用这个时间段完成其他业务,如scan、page、inquiry等。

所以在在蓝牙设备使用过程中,在有业务时将链接策略设置为active模式,在没有业务的时候设置为sniff模式或者hold模式节省功耗。

在代码中,系统管理器提供了以下几个接口设置链接策略:

// 设置/清除策略
void bta_sys_set_policy(uint8_t id, uint8_t policy, const RawAddress& peer_addr);
void bta_sys_clear_policy(uint8_t id, uint8_t policy, const RawAddress& peer_addr);
// 设置/清除默认设置
void bta_sys_set_default_policy(uint8_t id, uint8_t policy);
void bta_sys_clear_default_policy(uint8_t id, uint8_t policy);

以上接口都是调用设备管理中的bta_dm_policy_cback回调,该回调通过 bta_sys_policy_register注册。这个回调中分别调用BTM_SetLinkPolicyBTM_SetDefaultLinkPolicy实现。

参数设置

各个的profile在不同状态下设置不同参数,在设备管理器中按照生成以下几个表,每个表之间建立映射关系,设置参数时查表设置。

typedef struct {
  uint8_t id;  //模块ID
  uint8_t app_id; //App ID
  uint8_t spec_idx; // tBTA_DM_PM_SPEC表中的index
} tBTA_DM_PM_CFG;

typedef struct {
  tBTA_DM_PM_ACTION power_mode; // 连接策略
  uint16_t timeout; // 当前策略的超时时间
} tBTA_DM_PM_ACTN;

typedef struct {
  uint8_t allow_mask; //运行的策略的mask
  uint8_t ssr; 
  tBTA_DM_PM_ACTN actn_tbl[BTA_DM_PM_NUM_EVTS][2];  // 各个profile不同状态下的策略和超时时间,策略的参数在tBTM_PM_PWR_MD中
} tBTA_DM_PM_SPEC;

typedef struct {
  uint16_t max;
  uint16_t min;
  uint16_t attempt;
  uint16_t timeout;
  tBTM_PM_MODE mode;
} tBTM_PM_PWR_MD;

在这里插入图片描述

注: Core 5.3删除了park模式,本系列文章不再介绍,有文章中有出现请忽略

代码中这三个表格实现如下:

tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = {
   {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY, 0}, /* reserved: specifies length of this table. */
   {BTA_ID_AG, BTA_ALL_APP_ID, 0},               /* ag uses first spec table for app id 0 */
   {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */
   {BTA_ID_CG, BTA_ALL_APP_ID, 1},   /* cg resue ct spec table */
   ...
};
tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
    /* AG : 0 */
    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
     (BTA_DM_PM_SSR2), /* the SSR entry */
     {
         {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff  */
         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
         {{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000},
          {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
         {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
          {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff  */
         {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
         {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}},    /* busy */
         {{BTA_DM_PM_RETRY, 7000},
          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
     }},

    /* CT, CG : 1 */
    {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
     (BTA_DM_PM_SSR2), /* the SSR entry */
     {
         {{BTA_DM_PM_PARK, 5000},
          {BTA_DM_PM_NO_ACTION, 0}}, /* conn open  park */
         {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}},   /* conn close  */
         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
         {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
          {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */
         {{BTA_DM_PM_PARK, 5000},
          {BTA_DM_PM_NO_ACTION, 0}}, /* sco close  park */
         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
         {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
         {{BTA_DM_PM_RETRY, 5000},
          {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
     }},
     ...
};
tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] = {
    /* sniff modes: max interval, min interval, attempt, timeout */
    {BTA_DM_PM_SNIFF_MAX, BTA_DM_PM_SNIFF_MIN, BTA_DM_PM_SNIFF_ATTEMPT,
     BTA_DM_PM_SNIFF_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF - A2DP */
    {BTA_DM_PM_SNIFF1_MAX, BTA_DM_PM_SNIFF1_MIN, BTA_DM_PM_SNIFF1_ATTEMPT,
     BTA_DM_PM_SNIFF1_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF1 */
    {BTA_DM_PM_SNIFF2_MAX, BTA_DM_PM_SNIFF2_MIN, BTA_DM_PM_SNIFF2_ATTEMPT,
     BTA_DM_PM_SNIFF2_TIMEOUT,
     BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF2- HD idle */
     ...
};


const tBTA_DM_PM_CFG* p_bta_dm_pm_cfg = &bta_dm_pm_cfg[0];
const tBTA_DM_PM_SPEC* p_bta_dm_pm_spec = &bta_dm_pm_spec[0];
const tBTM_PM_PWR_MD* p_bta_dm_pm_md = &bta_dm_pm_md[0];

触发修改参数的动作有3个:

  • bta_sys
    初始化时会调用bta_sys_pm_register(bta_dm_pm_cback)向系统管理注册回调,系统管理中对应的API以及状态如下:
extern void bta_sys_conn_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_conn_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_app_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_app_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_sco_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_sco_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_sco_use(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_sco_unuse(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_idle(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);
extern void bta_sys_busy(uint8_t id, uint8_t app_id, const RawAddress& peer_addr);

#define BTA_SYS_CONN_OPEN 0x00
#define BTA_SYS_CONN_CLOSE 0x01
#define BTA_SYS_APP_OPEN 0x02
#define BTA_SYS_APP_CLOSE 0x03
#define BTA_SYS_SCO_OPEN 0x04
#define BTA_SYS_SCO_CLOSE 0x05
#define BTA_SYS_CONN_IDLE 0x06
#define BTA_SYS_CONN_BUSY 0x07

设备管理器中的处理函数是bta_dm_pm_cback,首先根据id和app id在bta_dm_pm_cfg中查找到bta_dm_pm_spec的index,根据index从bta_dm_pm_spec获取到当前状态的策略,如果是BTA_DM_PM_NO_ACTION则直接返回,否则根据id、app id、对端地址查找连接信息;根据index从bta_dm_pm_spec获取当前状态的策略,如果是BTA_DM_PM_NO_PREF则删除连接信息,否则判断是否找到连接信息,如果找到则更新状态,否则添加新的连接信息;最后调用bta_dm_pm_set_mode更新连接策略。
在这里插入图片描述
功耗管理是按设备划分的,不是按照连接的profile划分,即一个设备可能连接多个profile(通过id区分),只要有一个profile是active则整个通信都是active,所以当某个profile的power_mode为BTA_DM_PM_NO_PREF时会删除这个profile记录的信息,即这个profile不再决定通信的策略。

  • btm
    初始化时会调用BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id,bta_dm_pm_btm_cback)向BTM注册回调,当策略发生变化时通过bta_dm_pm_btm_cback回调通知设备管理器。根据当前状态判断是否需要调用bta_dm_pm_set_mode更新策略。
    在这里插入图片描述

  • 定时器
    bta_dm_pm_set_mode中会启动一些定时器,当定时器超时后会触发调用bta_dm_pm_timer_cback,回调中首先会清除不使用的定时器,然后根据定时器记录的策略调用bta_dm_pm_set_mode

bta_dm_pm_set_mode是链接策略更新的核心函数,首先找到所有连接的profile中策略优先级最高的策略(ACTIVE > SNIFF > NO_PREF > NO_ACTIVE),如果需要启动定时器且定时器的超时时间大于0,则启动一个定时器(超时时间在bta_dm_pm_spec中获取)。如果设置的策略优先级低于当前的策略则直接返回,否则根据设置相应的策略。
在这里插入图片描述
设置Park策略和Sniff策略时获取bta_dm_pm_md表中的策略参数。

上报事件

在fluoride中上报事件大多是通过回调上报,启动蓝牙时(BTA_EnableBluetooth)注册了tBTA_DM_SEC_CBACK原型的回调,bta中设备管理的大多数事件都是通过这个回调向上层上报事件,此外BTA_DmSearchBTA_DmDiscover时也注册了tBTA_DM_SEARCH_CBACK原型的回调,用于上报发现设备/服务的事件。

// 原型
typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data);
/* 上报的事件 */
#define BTA_DM_ENABLE_EVT 0    /* Enable Event */
#define BTA_DM_DISABLE_EVT 1   /* Disable Event */
#define BTA_DM_PIN_REQ_EVT 2   /* PIN request. */
#define BTA_DM_AUTH_CMPL_EVT 3 /* Authentication complete indication. */
#define BTA_DM_AUTHORIZE_EVT 4 /* Authorization request. */
#define BTA_DM_LINK_UP_EVT 5   /* Connection UP event */
#define BTA_DM_LINK_DOWN_EVT 6 /* Connection DOWN event */
#define BTA_DM_SIG_STRENGTH_EVT 7 /* Signal strength for bluetooth connection */
#define BTA_DM_BUSY_LEVEL_EVT 8 /* System busy level */
#define BTA_DM_BOND_CANCEL_CMPL_EVT 9 /* Bond cancel complete indication */
#define BTA_DM_SP_CFM_REQ_EVT 10 /* Simple Pairing User Confirmation request. */
#define BTA_DM_SP_KEY_NOTIF_EVT 11 /* Simple Pairing Passkey Notification */
#define BTA_DM_SP_RMT_OOB_EVT 12   /* Simple Pairing Remote OOB Data request. */
#define BTA_DM_SP_KEYPRESS_EVT 13  /* Key press notification event. */
#define BTA_DM_ROLE_CHG_EVT 14     /* Role Change event. */
#define BTA_DM_BLE_KEY_EVT 15      /* BLE SMP key event for peer device keys */
#define BTA_DM_BLE_SEC_REQ_EVT 16  /* BLE SMP security request */
#define BTA_DM_BLE_PASSKEY_NOTIF_EVT 17 /* SMP passkey notification event */
#define BTA_DM_BLE_PASSKEY_REQ_EVT 18   /* SMP passkey request event */
#define BTA_DM_BLE_OOB_REQ_EVT 19       /* SMP OOB request event */
#define BTA_DM_BLE_LOCAL_IR_EVT 20      /* BLE local IR event */
#define BTA_DM_BLE_LOCAL_ER_EVT 21      /* BLE local ER event */
#define BTA_DM_BLE_NC_REQ_EVT 22 /* SMP Numeric Comparison request event */
#define BTA_DM_SP_RMT_OOB_EXT_EVT 23 /* Simple Pairing Remote OOB Extended Data request. */
#define BTA_DM_BLE_AUTH_CMPL_EVT 24 /* BLE Auth complete */
#define BTA_DM_DEV_UNPAIRED_EVT 25
#define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */
#define BTA_DM_LE_FEATURES_READ 27 /* Cotroller specific LE features are read */
#define BTA_DM_ENER_INFO_READ 28 /* Energy info read */
#define BTA_DM_BLE_SC_OOB_REQ_EVT 29 /* SMP SC OOB request event */
#define BTA_DM_BLE_CONSENT_REQ_EVT 30 /* SMP consent request event */

// 原型
typedef void(tBTA_DM_SEARCH_CBACK)(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data);
/* 上报的事件 */
#define BTA_DM_INQ_RES_EVT 0  /* Inquiry result for a peer device. */
#define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */
#define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */
#define BTA_DM_DISC_BLE_RES_EVT 3 /* Discovery result for BLE GATT based servoce on a peer device. */
#define BTA_DM_DISC_CMPL_EVT 4          /* Discovery complete. */
#define BTA_DM_DI_DISC_CMPL_EVT 5       /* Discovery complete. */
#define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */
  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
代码下载:完整代码,可直接运行 ;运行版本:2022a或2019b或2014a;若运行有问题,可私信博主; **仿真咨询 1 各类智能优化算法改进及应用** 生产调度、经济调度、装配线调度、充电优化、车间调度、发车优化、水库调度、三维装箱、物流选址、货位优化、公交排班优化、充电桩布局优化、车间布局优化、集装箱船配载优化、水泵组合优化、解医疗资源分配优化、设施布局优化、可视域基站和无人机选址优化 **2 机器学习和深度学习方面** 卷积神经网络(CNN)、LSTM、支持向量机(SVM)、最小二乘支持向量机(LSSVM)、极限学习机(ELM)、核极限学习机(KELM)、BP、RBF、宽度学习、DBN、RF、RBF、DELM、XGBOOST、TCN实现风电预测、光伏预测、电池寿命预测、辐射源识别、交通流预测、负荷预测、股价预测、PM2.5浓度预测、电池健康状态预测、水体光学参数反演、NLOS信号识别、地铁停车精准预测、变压器故障诊断 **3 图像处理方面** 图像识别、图像分割、图像检测、图像隐藏、图像配准、图像拼接、图像融合、图像增强、图像压缩感知 **4 路径规划方面** 旅行商问题(TSP)、车辆路径问题(VRP、MVRP、CVRP、VRPTW等)、无人机三维路径规划、无人机协同、无人机编队、机器人路径规划、栅格地图路径规划、多式联运运输问题、车辆协同无人机路径规划、天线线性阵列分布优化、车间布局优化 **5 无人机应用方面** 无人机路径规划、无人机控制、无人机编队、无人机协同、无人机任务分配 **6 无线传感器定位及布局方面** 传感器部署优化、通信协议优化、路由优化、目标定位优化、Dv-Hop定位优化、Leach协议优化、WSN覆盖优化、组播优化、RSSI定位优化 **7 信号处理方面** 信号识别、信号加密、信号去噪、信号增强、雷达信号处理、信号水印嵌入提取、肌电信号、脑电信号、信号配时优化 **8 电力系统方面** 微电网优化、无功优化、配电网重构、储能配置 **9 元胞自动机方面** 交通流 人群疏散 病毒扩散 晶体生长 **10 雷达方面** 卡尔曼滤波跟踪、航迹关联、航迹融合
代码下载:完整代码,可直接运行 ;运行版本:2022a或2019b或2014a;若运行有问题,可私信博主; **仿真咨询 1 各类智能优化算法改进及应用** 生产调度、经济调度、装配线调度、充电优化、车间调度、发车优化、水库调度、三维装箱、物流选址、货位优化、公交排班优化、充电桩布局优化、车间布局优化、集装箱船配载优化、水泵组合优化、解医疗资源分配优化、设施布局优化、可视域基站和无人机选址优化 **2 机器学习和深度学习方面** 卷积神经网络(CNN)、LSTM、支持向量机(SVM)、最小二乘支持向量机(LSSVM)、极限学习机(ELM)、核极限学习机(KELM)、BP、RBF、宽度学习、DBN、RF、RBF、DELM、XGBOOST、TCN实现风电预测、光伏预测、电池寿命预测、辐射源识别、交通流预测、负荷预测、股价预测、PM2.5浓度预测、电池健康状态预测、水体光学参数反演、NLOS信号识别、地铁停车精准预测、变压器故障诊断 **3 图像处理方面** 图像识别、图像分割、图像检测、图像隐藏、图像配准、图像拼接、图像融合、图像增强、图像压缩感知 **4 路径规划方面** 旅行商问题(TSP)、车辆路径问题(VRP、MVRP、CVRP、VRPTW等)、无人机三维路径规划、无人机协同、无人机编队、机器人路径规划、栅格地图路径规划、多式联运运输问题、车辆协同无人机路径规划、天线线性阵列分布优化、车间布局优化 **5 无人机应用方面** 无人机路径规划、无人机控制、无人机编队、无人机协同、无人机任务分配 **6 无线传感器定位及布局方面** 传感器部署优化、通信协议优化、路由优化、目标定位优化、Dv-Hop定位优化、Leach协议优化、WSN覆盖优化、组播优化、RSSI定位优化 **7 信号处理方面** 信号识别、信号加密、信号去噪、信号增强、雷达信号处理、信号水印嵌入提取、肌电信号、脑电信号、信号配时优化 **8 电力系统方面** 微电网优化、无功优化、配电网重构、储能配置 **9 元胞自动机方面** 交通流 人群疏散 病毒扩散 晶体生长 **10 雷达方面** 卡尔曼滤波跟踪、航迹关联、航迹融合
### 回答1: Linux 系统中有几种常见的蓝牙协议栈: 1. BlueZ:这是 Linux 系统中默认的蓝牙协议栈,它由 Linux 基金会开发并维护。BlueZ 提供了蓝牙的高级功能,并且可以让用户通过命令行或脚本来控制蓝牙设备。 2. Bluedroid:这是 Android 系统中的蓝牙协议栈,也可以在其他基于 Linux 的系统中使用。Bluedroid 提供了丰富的蓝牙功能,包括蓝牙协议栈、配对、连接、传输数据等。 3. BlueZ for Android:这是一个基于 BlueZ 的蓝牙协议栈,专门为 Android 系统开发。它兼容 BlueZ 命令行工具,可以让用户在 Android 系统中使用 BlueZ 命令行来控制蓝牙设备。 4. hciattach:这是 Linux 中用于驱动蓝牙硬件的工具,它可以将蓝牙硬件附加到蓝牙协议栈中,使蓝牙硬件可以与其他蓝牙设备通信。 总的来说,Linux 系统中的蓝牙协议栈主要有 BlueZ 和 Bluedroid 两种,其中 BlueZ 是 Linux 系统中的默认蓝牙协议栈,Bluedroid 则是 Android 系统中的蓝牙协议栈。 ### 回答2: Linux操作系统中有两种蓝牙协议栈可供选择。 1. BlueZ协议栈:BlueZ是Linux操作系统上最常用的蓝牙协议栈。它提供API和工具,用于在Linux设备上实现蓝牙功能。BlueZ支持几乎所有的蓝牙协议,包括传统的蓝牙核心规范(Bluetooth Core Specification)和最新的蓝牙低功耗(Bluetooth Low Energy)规范。BlueZ协议栈被广泛应用于各种Linux设备,包括智能手机、平板电脑、智能手表等。 2. Affix协议栈:Affix是一个开源的Linux蓝牙协议栈。它提供了蓝牙通信的基本功能,并可以在嵌入式系统上运行。Affix协议栈支持蓝牙核心规范,但对于蓝牙低功耗规范的支持相对有限。它适用于资源受限的嵌入式设备,如物联网设备、传感器等。 总结起来,Linux操作系统上有两种常用的蓝牙协议栈:BlueZ协议栈和Affix协议栈。其中,BlueZ协议栈是最常用和功能最全面的蓝牙协议栈,被广泛应用于各种Linux设备。而Affix协议栈则适用于资源受限的嵌入式设备。 ### 回答3: Linux操作系统支持多种蓝牙协议栈,以下是其中一些常见的蓝牙协议栈: 1. BlueZ:BlueZ是Linux操作系统上最为广泛使用的开源蓝牙协议栈。它提供了一套完整的蓝牙协议栈实现,包括蓝牙核心协议、蓝牙硬件驱动和一系列用户空间的工具和库。BlueZ支持众多的蓝牙协议和功能,如蓝牙文件传输、蓝牙耳机、蓝牙键盘等。 2. Affix:Affix是一种轻量级的蓝牙协议栈,旨在提供更小的内存占用和更低的功耗。它适用于嵌入式设备和资源受限的系统。Affix支持核心蓝牙协议,但不支持所有BlueZ的高级功能。 3. Bluedroid:Bluedroid最初是由Android平台使用的蓝牙协议栈,后来也被移植到了Linux操作系统中。Bluedroid基于BlueZ协议栈,但做了一些定制化的修改和优化,以适应移动设备的需求。 4. FluorideFluoride是谷歌开发的蓝牙协议栈,最初用于Android平台,后来也支持了Linux操作系统。Fluoride提供了一套用于开发蓝牙应用的API和工具,并且与BlueZ相比有一些特有的优化和功能。 这些蓝牙协议栈都有各自的特点和适用场景,开发者可以根据不同的需求选择合适的协议栈来进行蓝牙应用程序的开发和调试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值