pair不上藍牙設(shè)備
- 我有遇到一個情況,如果出現(xiàn)pair Julia 連續(xù)的多次的失敗(一般情況就一次,下次就會pair成功),就會一直pair 失敗下去,這個pair失敗是安卓底層Api返回的狀態(tài)---------> 殺死App也不能重新pair成功情臭,只有重新啟動平板省撑。你們有遇到這種情況么 ?
- 我好像可以復現(xiàn)這個問題了俯在,當多次 pair失敗的時候竟秫,可以不開關(guān)機,然后把平板的藍牙重啟一下跷乐,然后在重新去掃描和pair肥败,就可以了成功了--- Lap Chow 如果你們又遇到這種情況,請記得給我說下步驟哈愕提,剛才和 Popo Liang 討論馒稍,她沒有遇到過,就我在測試過程中遇到了
我開始以為是Gatt開多了浅侨,然后導致內(nèi)存中的Gatt少了纽谒,所以我要去關(guān)閉它,但是好像問題不是這個樣子的如输,我看的是鼓黔,Gatt在掃描的同時,然后去pair 不见,那么肯定會 pair failed-----
我們有個服務(wù)请祖,當藍牙斷開連接的時候,會主動的去連接它脖祈,然后導致開了很多的 gatt的句柄在哪里,一個gatt在不斷的生成刷晋,但是沒有銷毀掉 盖高!兩個時間的重疊 ---在返回的藍牙掃描的結(jié)果的同時,還去pair藍牙的設(shè)備眼虱,導致這個設(shè)備就被打入冷宮喻奥,永遠都pair 不上了
todo 思路有點亂 媽的 !D笮撞蚕!
要復現(xiàn)這個問題 -------- -
new we need also disable APCF!
我們還需要禁用APCF!
09:12:27.923 8909-8909/com.tgi.device.cp80 D/BluetoothAdapter: isLeEnabled(): ON
2020-06-04 09:12:27.927 8909-8909/com.tgi.device.cp80 I/Stan: com.tgi.lib.ble.client.states.BluetoothMachine.setState(); 62 - Lines:
BluetoothMachine setState StandByState
2020-06-04 09:12:27.935 11301-11331/? D/BtGatt.ScanManager: we need also disable APCF!
2020-06-04 09:00:25.231 11301-11331/? D/BtGatt.ScanManager: we need also disable APCF!
2020-06-04 09:12:27.935 11301-11331/? D/BtGatt.ScanManager: we need also disable APCF!
2020-06-04 09:13:56.715 11301-11331/? D/BtGatt.ScanManager: we need also disable APCF!
pair 失敗的 會出下面的日志
又出現(xiàn)一個日志
bta_gattc_cache_load: can't open GATT cache file /data/misc/bluetooth/gatt_cache_5f00811ec6f5 for reading, error: No such file or directory
bt_bta_gattc: bta_gattc_explore_srvc no more services found
2020-06-04 11:52:45.886 11301-11341/? W/bt_btif: bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0013
2020-06-04 11:52:45.886 11301-11341/? W/bt_btif: bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0013
2020-06-04 11:52:45.886 11301-11341/? W/bt_btif: bta_gattc_conn_cback() - cif=5 connected=0 conn_id=5 reason=0x0013
2020-06-04 11:52:45.886 11301-11341/? W/bt_btif: bta_gattc_conn_cback() - cif=6 connected=0 conn_id=6 reason=0x0013
2020-06-04 11:52:45.886 11301-11341/? W/bt_btif: bta_gattc_conn_cback() - cif=7 connected=0 conn_id=7 reason=0x0013
2020-06-04 11:52:45.886 11301-11341/? I/bt_btm_sec: btm_sec_disconnected clearing pending flag handle:513 reason:19
2020-06-04 11:52:45.886 11301-11341/? E/bt_stack: [ERROR:bta_gattc_utils.cc(509)] bta_gattc_mark_bg_conn unable to find the bg connection mask for: 84:0d:8e:cc:9c:86
2020-06-04 11:52:45.967 11301-11324/? W/bt_btif: btif_av_move_idle: ACL Disconnected state 0 bd_addr=84:0d:8e:cc:9c:86 peer_bda=00:00:00:00:00:00
https://github.com/espressif/esp-idf/issues/250
ESP32是一系列低成本过牙,低功耗的單片機微控制器甥厦,集成了Wi-Fi和雙模藍牙。 ESP32系列采用Tensilica Xtensa LX6微處理器寇钉,包括雙核心和單核變體刀疙,內(nèi)置天線開關(guān),RF變換器扫倡,功率放大器谦秧,低噪聲接收放大器,濾波器和電源管理模塊。
ESP32 由總部位于上海的中國公司樂鑫信息科技創(chuàng)建和開發(fā)疚鲤,由臺積電采用40納米技術(shù)制造[2]锥累。它是ESP8266微控制器的后繼產(chǎn)品。
基本概念和問題
1集歇、藍牙設(shè)計范式桶略?
當手機通過掃描低功耗藍牙設(shè)備并連接上后,手機與藍牙設(shè)備構(gòu)成了客戶端-服務(wù)端架構(gòu)鬼悠。手機通過連接藍牙設(shè)備删性,可以讀取藍牙設(shè)備上的信息。手機就是客戶端焕窝,藍牙設(shè)備是服務(wù)端蹬挺。
手機做為客戶端可以連接多個藍牙設(shè)備,所以手機又可以叫中心設(shè)備(Central)它掂,藍牙設(shè)備叫外圍設(shè)備(Peripheral)巴帮。
還有另外一個稱謂:手機叫主設(shè)備(Master),藍牙設(shè)備叫從設(shè)備(Slave)虐秋。
Android4.3 開始支持低功耗藍牙榕茧,此版本只支持單模式:同時只能工作在中心設(shè)備模式或者外圍設(shè)備模式
Android5.0 開始支持主從一體。換句話說客给,手機可以掃描并進行連接用押,連接著藍牙設(shè)備的同時,又可以作為廣播者靶剑,發(fā)送藍牙廣播蜻拨,等待別的支持藍牙掃描的設(shè)備連接自己。
2桩引、從設(shè)備連接數(shù)量的問題缎讼?
理論層面
從經(jīng)典藍牙時代開始,藍牙有個星型拓撲的概念坑匠,一個主設(shè)備(Central)外圍有七個從設(shè)備(Peripheral)血崭,藍牙核心文檔規(guī)定了:同一時間只允許七個從設(shè)備進行連接。
系統(tǒng)層面
Android系統(tǒng)藍牙協(xié)議棧源碼中也使用了這個數(shù)值厘灼,Android手機的藍牙芯片都是雙模藍牙芯片夹纫,即同時支持經(jīng)典藍牙和低功耗藍牙,分析過協(xié)議棧源碼手幢,建立連接的過程經(jīng)典藍牙和低功耗藍牙是公用的代碼捷凄,所以手機作為主設(shè)備(Central)時,從設(shè)備(Peripheral)同時連接的最大值就是7臺設(shè)備围来。
實際情況
開發(fā)Android客戶端以來跺涤,遇到的實際情況就是匈睁,部分手機(偏低端一些機型,比如采用聯(lián)發(fā)科的解決方案桶错,手機的GPS航唆、藍牙、Wi-Fi等都是共模的院刁,都集成在一個芯片上)不能達到7臺設(shè)備糯钙。
3、ATT是什么退腥?
ATT是屬性協(xié)議(Attribute Protocol)任岸,定義了客戶端與服務(wù)器如何相互發(fā)送符合標準的消息。
4狡刘、GATT是什么享潜?
GATT是通用屬性規(guī)范(Generic Attribute Profile),定義了如何發(fā)現(xiàn)與使用服務(wù)嗅蔬、特性與描述符的標準方法剑按。
GATT的規(guī)程基本分為:
發(fā)現(xiàn)規(guī)程:發(fā)現(xiàn)服務(wù)(Service)、發(fā)現(xiàn)特征(Characteristic)等
客戶端發(fā)起規(guī)程:讀取特征(readCharacteristic)澜术、寫入特征(writeCharacteristic)等
服務(wù)端發(fā)起規(guī)程:比如通知(Notification)和指示(Indicate)
5艺蝴、低功耗藍牙頻段和信道問題
藍牙工作在2.45G ISM頻段,波段范圍是:2400-2483.5 MHz
信道:低功耗藍牙使用用40個RF信道鸟废,這些RF信道中心頻率為:f=2402+k*2 MHz, k=0, ... ,39
因為調(diào)試指數(shù)放寬猜敢,低功耗藍牙的信道與經(jīng)典藍牙有所不同。每個信道的功率譜更寬盒延,因此锣枝,為了避免鄰近信道干擾,低功耗藍牙的信道寬度為2MHz兰英,而不是經(jīng)典藍牙的1MHz
低功耗藍牙使用的2.45GHz頻段已經(jīng)非常擁擠,僅僅考慮標準的技術(shù)就包括:經(jīng)典藍牙供鸠、低功耗藍牙畦贸、IEEE 802.11、IEEE802.11b楞捂、IEEE802.11g薄坏、IEEE802.11n以及IEEE 802.15.4。另外寨闹,許多私有的無線電同樣使用這個頻段胶坠,包括X10視頻中繼器、無線報警繁堡、鍵盤和鼠標等沈善。許多其他設(shè)備也會在該頻段發(fā)射噪聲乡数,例如街燈和微波爐。
對于2.45G這個頻段有個很尷尬的特性:怕水闻牡。
舉個例子:微波爐的工作原理就是向帶有水分的物體發(fā)射2.45GHz的微波净赴,利用了水分子能夠很好的吸收2.45GHz電磁波,將電磁波能量轉(zhuǎn)換成為自身的熱量罩润。也正式這個特性玖翅,在很長一段時間里,2.4GHz信道不被人所重視割以,下雨金度、霧氣甚至是潮濕的墻壁都能吸收無線電波,使傳輸距離大大衰減严沥。估計這也是全球都對此頻段不屑而免費開放的理由之一吧猜极。當人站在兩塊藍牙設(shè)備中間,并且距離其中一塊模塊1米左右時祝峻,能夠檢測信號衰減了將近10dB左右魔吐!因為人體的70%左右是水分。
有人也許好奇為啥廣播信道這么設(shè)計莱找,請看下圖:
是為了盡量避開沖突頻段酬姆,增加通信的魯棒性。
6奥溺、關(guān)于autoConnect參數(shù)為true的意義辞色?
在藍牙核心文檔Vol3: Core System Package[Host volume]->Part C: Generic Access Profile的Connection Modes and Procedures章節(jié)中有涉及到自動連接建立規(guī)程(Auto Connection Establishment Procedure)的定義。
自動連接建立規(guī)程用來向多個設(shè)備同時發(fā)起連接浮定。一個中央設(shè)備的主機與多個外圍設(shè)備綁定相满,只要它們開始廣播,便立刻與其建立連接桦卒。跟多細節(jié)請參考藍牙核心文檔和協(xié)議棧源碼立美。
一些API使用問題
Android 4.3
此版本是首個支持BLE的Android版本,穩(wěn)定性一般方灾,現(xiàn)在的系統(tǒng)分布情況建蹄,基本可以把最低支持版本提高的Android4.4了
Android 5.0
Samsung手機出現(xiàn)BluetoothAdapter.startLeScan()方法使用不當導致的Crash
正常調(diào)用過程startLeScan() -> stopLeScan() -> startLeScan() -> stopLeScan(),不會出現(xiàn)Crash
異常調(diào)用startLeScan() -> startLeScan()會出現(xiàn)Crash
Android 6.0
在Android 6.0版本裕偿,需要APP獲取位置權(quán)限才可以使用藍牙API洞慎,部分機型在未授權(quán)時,調(diào)用藍牙API會引起Crash
Android 6.0.1
Android6.0.1有個連接問題嘿棘,是系統(tǒng)bug劲腿,影響連接問題。
Android 7.0
30s內(nèi)連續(xù)掃描次數(shù)不允許大于5次鸟妙,否則會引起無法掃描到設(shè)備的問題焦人,需要重啟才可以恢復正常挥吵。
并發(fā)執(zhí)行BluetoothGatt.readRemoterssi()會引發(fā)DeadObjectException,三星手機出現(xiàn)概率較高垃瞧。
**Android 8.1 **
掃描方法BluetoothAdapter.startLeScan(UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback);
部分手機如果沒有指定serviceuuids值蔫劣,手機鎖屏后,掃描回調(diào)會失敗个从,無法掃描到設(shè)備脉幢。Google親兒子Pixel系列必現(xiàn)。
待更新......
另外一些普遍問題
BluetoothDevice.getName() 獲取名字是有些不可靠的嗦锐,因為有些情況下獲取Name是空嫌松,慎用此方法獲取的值來作為掃描過濾條件。
BLE設(shè)備的建立和斷開連接的操作奕污,最好都放在主線程中:例如BluetoothDevice.connectGatt()萎羔,BluetoothGatt.connect(),BluetoothGatt.disconnect()碳默,BluetoothGatt.discoverServices()等
BLE 應(yīng)用異常耗電問題贾陷,在連接 BLE 設(shè)備的過程中,系統(tǒng)會持有這個 WakeLock嘱根,直到連接上或者主動斷開連接才會釋放髓废。如果BLE設(shè)備不在范圍內(nèi)构捡,這個超時時間大約為30s袱巨,而這時你可能又要嘗試重新連接怪瓶,這個WakeLock又被重新持有味滞,這樣系統(tǒng)就永遠不能休眠了。
Android BLE藍牙的各種問題烦感,只要做到如下幾點喜德,大部分問題會得到解決:
原則一:startLeScan()和stopLeScan()一定要確保成對出現(xiàn)逛绵、順序調(diào)用欧引。
否則會導致協(xié)議棧中mClientIf達到上限频伤,掃描registerClient失敗,再也不能掃描到設(shè)備芝此,此時onScanFailed會發(fā)生errorCode=2剂买。
原則二:BluetoothDevice.connectGatt()、BluetoothGatt.disconnect()和BluetoothGatt.close()一定要順序調(diào)用癌蓖。一些情況下可以直接越過disconnect()方法直接調(diào)用close()。
close()非常重要婚肆,對于一個執(zhí)行過連接方法的設(shè)備租副,不管是否連接成功,最后都要調(diào)用close()较性,讓系統(tǒng)底層回收掉資源用僧,否則會有各種問題讓你崩潰结胀。
對于連接成功的藍牙設(shè)備,想斷開時责循,可以先調(diào)用BluetoothGatt.disconnect()糟港,等待onConnectionStateChange響應(yīng)斷開后,再執(zhí)行close()院仿。
如果是執(zhí)行連接方法時出現(xiàn)了無法恢復的錯誤秸抚,比如133、8歹垫、19剥汤、22、62等排惨,可以直接調(diào)用close()吭敢。
原則三:讀/寫特征和描述、設(shè)置通知和指示等操作暮芭,要確保上一個執(zhí)行完成了鹿驼,再執(zhí)行下一個調(diào)用。
Android源碼中使用了mDeviceBusy全局變量辕宏,同時調(diào)用兩個API畜晰,會導致后調(diào)用的直接失敗。
附錄:API常見錯誤碼
GATT_ERROR 0x85 //133任何不懼名字的錯誤都出現(xiàn)這個錯誤碼匾效,出現(xiàn)了就認慫吧舷蟀,重新連接吧。
GATT_CONN_TIMEOUT 0x08 //8 連接超時面哼,大多數(shù)情況是設(shè)備離開可連接范圍野宜,然后手機端連接超時斷開返回此錯誤碼。
GATT_CONN_TERMINATE_PEER_USER 0x13 //19 連接被對端設(shè)備終止魔策,直白點就是手機去連接外圍設(shè)備匈子,外圍設(shè)備任性不讓連接執(zhí)行了斷開。
GATT_CONN_TERMINATE_LOCAL_HOST 0x16 //22 連接被本地主機終止闯袒,可以解釋為手機連接外圍設(shè)備虎敦,但是連接過程中出現(xiàn)一些比如鑒權(quán)等問題,無法繼續(xù)保持連接政敢,主動執(zhí)行了斷開操作其徙。
GATT_CONN_FAIL_ESTABLISH 03E //62 連接建立失敗。