SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 5796|回复: 4
打印 上一主题 下一主题

[Discuss] 蓝牙(Ble)

[复制链接]

187

主题

346

帖子

2450

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2450
跳转到指定楼层
楼主
发表于 2016-5-10 20:45:46 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
回调函数时机
did_discover_peripheral扫描到新外设
did_release_peripheral释放了一外设。意外断开时会强制执行释放注1
did_connect_peripheral连接了一外设
did_disconnect_peripheral断开外设。包括1)应用要求断开;2)意外断开。如果一个正要被释放的设备正连接着,它会先调用这个断开
did_discover_services获得外设的所有服务
did_discover_characteristics获得一服务的所有特征
did_read_characteristic读了一个特征
did_write_characteristic写了一个特征
did_notify_characteristic通知模式的特征触发了新通知
did_discover_descriptors获得一特征的所有描述符

注1:Discover后,SDL会为该设备创建系统相关结构及内存块,释放指的就是释放系统相关结构及内存块。
回复

使用道具 举报

187

主题

346

帖子

2450

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2450
沙发
 楼主| 发表于 2016-5-10 20:46:21 | 只看该作者

刷新在线BLE设备

本帖最后由 ancientcc 于 2020-7-30 16:04 编辑

先看个问题:启动扫描后,已扫描periperhial A,那此次扫描过程还会出现periperhial A吗?——不同操作系统不同实现,app应该兼容重复和不重复。Android是重复的。BluetoothLeScanner.startScan后,ScanCallback.onScanResult就会不断报出搜到的设备,这些设备会重复,而且重复间隔非常短,像不到120毫秒(这个间隔或许和GAP广播包间隔有关)。iOS提供了CBCentralManagerScanOptionAllowDuplicatesKey,由它来决定是否要重复。

刷新设备列表的任务包括两个:检测到新设备后增加、设备离线后移除。这两个任务中检测新设备不难,难在如何判断设备是否离线。

1:iOS平台不能使用判断广播包间隔机制
广播包间隔机制基于的是设备会不断发送广告包,app把这广告包当心跳,根据心跳间隔来判断是否离线。iOS平台可以把CBCentralManagerScanOptionAllowDuplicatesKey设为YES来关掉筛选器,从而使让产生心跳,但实测下来,关掉这个筛选器至少会产生两个问题。
1)耗更多电。这个苹果官方文档有写。
2)无法确定“有效”的广播间隔门限值。硬件应该是以固定间隔发送广播包,但经过iOS BLE后,它给app的间隔变成不确定,而且是很不确定,快的有时一秒就十多个,慢的十秒都不出现一个。

由于存在第二个问题,使得iOS下根据广播包间隔来判断设备这否离线变得不可能。

在iOS平台如何判断是否已离线?我想到的办法是使用固定间隔重扫描。它基于的是在iOS,即使打开筛选器,调用scanForPeripheralsWithServices就会重新获得在线设备。要注意的,即使当前正处在扫描中,不调用停止扫描,只调用该函数就会产生重新获得在线设备效果。

在一次扫描过程中,同一个设备只能被发现(Discover)一次。也就是说,一设备被发现了,然后把这设备断电,接下再上电,扫描过程发现不了此次上电。

广播包中的mac地址
peripheral在广播,有center来连它,连接成功,一段时间后断了。还是这一个center,立即重新连,此次peripheral发的广播包中,得到的peripheral的mac地址可能会变。也就是说,同一个peripheral,在重新广播时会出现不同的mac地址。

——peripheral可以自编程广播包中是什么数据,标准没有规定广播包中mac地址一定是芯硬件内部的那个。有些硬件厂家为让上面识别,可能会在广播包固定使用硬件内部的那个mac地址。但有些为隐私,会使用随机生成的mac地址,就和硬件内部的那个mac地址没关系。具体到Android下把ble编程成peripheral这个场景,采用第二种方案,即广播包中的mac地址是随机生成。想要不改变,必须从framework层禁止,应用层修改不了的。

回复 支持 反对

使用道具 举报

187

主题

346

帖子

2450

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2450
板凳
 楼主| 发表于 2016-5-10 20:46:43 | 只看该作者
本帖最后由 ancientcc 于 2016-5-10 20:48 编辑

GAP、GATT设置
一、至少要设一个Service UUID。原因:iOS在后台的断开后重连需要uuid值。
二、不要让一个特征同时具有notify、indicate属性。原因:iOS设置notify、indicate用的是一个函数,当属性只有这们中一个时,它会正确设置,如果同时存在,它只会设置indicate。indicate和notify的主要区别:indicate时,center发数据给peripheral,peripheral收到数据后,需再发应答给center;notify时,center发数据给peripheral,peripheral不必给center任何应答。在Android系统,设置indicate、notify是不同常量,ENABLE_NOTIFICATION_VALUE/ENABLE_INDICATION_VALUE,gatt.writeDescriptor必需按要求设置,否则会导致出随机错误,像断开连接。Windows类似Android,用的也是不同值。
回复 支持 反对

使用道具 举报

187

主题

346

帖子

2450

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2450
地板
 楼主| 发表于 2016-5-10 20:47:03 | 只看该作者
本帖最后由 ancientcc 于 2016-5-10 20:52 编辑

SDL_BleScanPeripherals
  • 功能是扫描正在广播的设备。
  • 在扫描状态下再调用SDL_BleScanPeripherals,会从全新状态开始扫描。
  • 在一次扫描过程中,同一个设备只能被发现(Discover)一次。也就是说,一设备被发现了,然后把这设备断电,接下再上电,扫描过程发现不了此次上电。但依据2,再次SDL_BleScanPeripherals会发现该设备。
回复 支持 反对

使用道具 举报

187

主题

346

帖子

2450

积分

版主

Rank: 7Rank: 7Rank: 7

积分
2450
5#
 楼主| 发表于 2016-5-10 20:50:05 | 只看该作者

自动重连

本帖最后由 ancientcc 于 2016-8-7 10:43 编辑

自动重连的条件
  1. void tble::did_discover_peripheral(SDL_BlePeripheral& peripheral)
  2. {
  3.         if (!connecting_peripheral_ && !peripheral_ && connector_->match(peripheral)) {
  4.                 connect_peripheral(peripheral);
  5.         }
  6.         app_discover_peripheral(peripheral);
  7. }
复制代码

1、当前没有正在连接(!connecting_peripheral_)或已连接(!peripheral_)。
2、匹配当前的连接适配器(connector_->match(peripheral))。

tble::disable_reconnect_
当前想禁止自动重连时,把它设为true,一旦可允许重连,设为false,并随后要调用start_scan,以允许重连。

考虑这么个场景:一个连续测温度的app,它想处理文件中的温度数据,但由于蓝牙会定时把读到的温度写入文件,为避免文件不同步它需要断掉蓝牙。这意味着它必须暂时关掉蓝牙,等处理完后再打开,接下就让深入这过程,为方便描述以下把处理文件中数据称为B任务。断开连接过程中会触发tble::did_disconnect_peripheral,一旦disable_reconnect_是false,它要调用start_scan,这时会出现1)有平台(Windows)是会同步调起tble::did_discover_peripheral,2)执行B任务过程中有可能调用SDL_PumpEvent,如果旁边有设备恰好发来广播包,这时会调起tble::did_discover_peripheral(start_scan发现了蓝牙设备)。不管哪一种都会导致调用tble::did_discover_peripheral,该函数将引起自动重连,而这时B任务还未开始执行或没执行,结果是程序混乱。

为消除这混乱引入disable_reconnect_,当它是true时,tble::did_disconnect_peripheral不会调用start_scan。

disable_reconnect_和start_scan密切相关,当它是true时不要让执行start_scan!于是tpersist_scan_lock的析构函数就要判断这变量。

App如何设置disable_reconnect_?当前想禁止重连时,把它设为true,一旦可允许重连,设为false,并随后要调用start_scan。为方便,建议App使用封装了这过程的tdisable_reconnect_lock。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2024-5-20 04:17 , Processed in 0.066734 second(s), 22 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表