BLE廣播數據包分析


原文  http://www.race604.com/ble-advertising/

 

從上一篇GATT Profile 簡介中提到過,BLE 設備工作的第一步就是向外廣播數據。廣播數據中帶有設備相關的信息。本文主要說一下 BLE 的廣播中的數據的規范以及廣播包的解析。

廣播模式

BLE 中有兩種角色 Central 和 Peripheral ,也就是中心設備和外圍設備。中心設備可以主動連接外圍設備,外圍設備發送廣播或者被中心設備連接。外圍通過廣播被中心設備發現,廣播中帶有外圍設備自身的相關信息。

廣播包有兩種: 廣播包 (Advertising Data)和 響應包 (Scan Response),其中廣播包是每個設備必須廣播的,而響應包是可選的。 數據包的格式如下圖所示(圖片來自官方 Spec):每個包都是 31 字節,數據包中分為有效數據(significant)和無效數據(non-significant)兩部分。

  • 有效數據部分 :包含若干個廣播數據單元,稱為 AD Structure 。如圖中所示,AD Structure 的組成是:第一個字節是長度值 Len ,表示接下來的 Len 個字節是數據部分。數據部分的第一個字節表示數據的類型 AD Type ,剩下的 Len - 1 個字節是真正的數據 AD data 。其中 AD type 非常關鍵,決定了 AD Data 的數據代表的是什么和怎么解析,這個在后面會詳細講;
  • 無效數據部分 :因為廣播包的長度必須是 31 個 byte,如果有效數據部分不到 31 自己,剩下的就用 0 補全。這部分的數據是無效的,解釋的時候,忽略即可。

廣播數據格式

所有的 AD type 的定義在文檔 Core Specification Supplement 中。 AD Type 包括如下類型:

  • Flags: TYPE = 0x01。這個數據用來標識設備 LE 物理連接的功能。DATA 是 0 到多個字節的 Flag 值,每個 bit 上用 0 或者 1 來表示是否為 True。如果有任何一個 bit 不為 0,並且廣播包是可連接的,就必須包含此數據。各 bit 的定義如下:

    • bit 0: LE 有限發現模式
    • bit 1: LE 普通發現模式
    • bit 2: 不支持 BR/EDR
    • bit 3: 對 Same Device Capable(Controller) 同時支持 BLE 和 BR/EDR
    • bit 4: 對 Same Device Capable(Host) 同時支持 BLE 和 BR/EDR
    • bit 5..7: 預留
  • Service UUID: 廣播數據中一般都會把設備支持的 GATT Service 廣播出來,用來告訴外面本設備所支持的 Service。有三種類型的 UUID:16 bit, 32bit, 128 bit。廣播中,每種類型類型有有兩個類別:完整和非完整的。這樣就共有 6 種 AD Type。

    • 非完整的 16 bit UUID 列表: TYPE = 0x02;
    • 完整的 16 bit UUID 列表: TYPE = 0x03;
    • 非完整的 32 bit UUID 列表: TYPE = 0x04;
    • 完整的 32 bit UUID 列表: TYPE = 0x05;
    • 非完整的 128 bit UUID 列表: TYPE = 0x06;
    • 完整的 128 bit UUID 列表: TYPE = 0x07;
  • Local Name: 設備名字,DATA 是名字的字符串。 Local Name 可以是設備的全名,也可以是設備名字的縮寫,其中縮寫必須是全名的前面的若干字符。

    • 設備全名: TYPE = 0x08
    • 設備簡稱: TYPE = 0x09
  • TX Power Level: TYPE = 0x0A,表示設備發送廣播包的信號強度。DATA 部分是一個字節,表示 -127 到 + 127 dBm。

  • 帶外安全管理(Security Manager Out of Band):TYPE = 0x11。DATA 也是 Flag,每個 bit 表示一個功能:

    • bit 0: OOB Flag,0 表示沒有 OOB 數據,1 表示有
    • bit 1: 支持 LE
    • bit 2: 對 Same Device Capable(Host) 同時支持 BLE 和 BR/EDR
    • bit 3: 地址類型,0 表示公開地址,1 表示隨機地址
  • 外設(Slave)連接間隔范圍:TYPE = 0x12。數據中定義了 Slave 最大和最小連接間隔,數據包含 4 個字節:

    • 前 2 字節:定義最小連接間隔,取值范圍:0x0006 ~ 0x0C80,而 0xFFFF 表示未定義;
    • 后 2 字節:定義最大連接間隔,同上,不過需要保證最大連接間隔大於或者等於最小連接間隔。
  • 服務搜尋:外圍設備可以要請中心設備提供相應的 Service。其數據定義和前面的 Service UUID 類似:

    • 16 bit UUID 列表: TYPE = 0x14
    • 32 bit UUID 列表: TYPE = 0x??
    • 128 bit UUID 列表: TYPE = 0x15
  • Service Data: Service 對應的數據。

    • 16 bit UUID Service: TYPE = 0x16, 前 2 字節是 UUID,后面是 Service 的數據;
    • 32 bit UUID Service: TYPE = 0x??, 前 4 字節是 UUID,后面是 Service 的數據;
    • 128 bit UUID Service: TYPE = 0x??, 前 16 字節是 UUID,后面是 Service 的數據;
  • 公開目標地址:TYPE = 0x17,表示希望這個廣播包被指定的目標設備處理,此設備綁定了公開地址,DATA 是目標地址列表,每個地址 6 字節。

  • 隨機目標地址:TYPE = 0x18,定義和前一個類似,表示希望這個廣播包被指定的目標設備處理,此設備綁定了隨機地址,DATA 是目標地址列表,每個地址 6 字節。

  • Appearance:TYPE = 0x19,DATA 是表示了設備的外觀。

  • 廠商自定義數據: TYPE = 0xFF,廠商自定義的數據中,前兩個字節表示廠商 ID,剩下的是廠商自己按照需求添加,里面的數據內容自己定義。

  • 還有一些其他的數據,我這里就不一一列舉了,有需要的可以從這個文檔查閱 Core Specification Supplement 。

廣播數據解析

在 Android 可以使用 BluetoothAdapter 來發起掃描。基本用法如下:

BluetoothAdapter.LeScanCallback mLeScanCallback =  
 new BluetoothAdapter.LeScanCallback() {   @Override   public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {    // 解析廣播數據    parseAdvData(scanRecord);   }  }; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // 開始掃描設備 mBluetoothAdapter.startLeScan(mLeScanCallback); ... // 停止掃描設備 mBluetoothAdapter.stopLeScan(mLeScanCallback); 

當掃描到設備以后,就會回調 onLeScan(...) ,這里的參數 scanRecord 就是廣播數據,這里同時包含 廣播數據 和 掃描相應數據 (如果有的話),所以長度一般就是 62 字節。

根據上一節的廣播數據格式的說明,可以實現解析廣播數據函數 parseAdvData(scanRecord); ,下面的代碼實現了解析幾個我關心的數據:

public static ParsedAd parseData(byte[] adv_data) {  ParsedAd parsedAd = new ParsedAd();  ByteBuffer buffer = ByteBuffer.wrap(adv_data).order(ByteOrder.LITTLE_ENDIAN);  while (buffer.remaining() > 2) {   byte length = buffer.get();   if (length == 0)    break;   byte type = buffer.get();   length -= 1;   switch (type) {    case 0x01: // Flags     parsedAd.flags = buffer.get();     length--;     break;    case 0x02: // Partial list of 16-bit UUIDs    case 0x03: // Complete list of 16-bit UUIDs    case 0x14: // List of 16-bit Service Solicitation UUIDs     while (length >= 2) {      parsedAd.uuids.add(UUID.fromString(String.format(        "%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));      length -= 2;     }     break;    case 0x04: // Partial list of 32 bit service UUIDs    case 0x05: // Complete list of 32 bit service UUIDs     while (length >= 4) {      parsedAd.uuids.add(UUID.fromString(String.format(        "%08x-0000-1000-8000-00805f9b34fb", buffer.getInt())));      length -= 4;     }     break;    case 0x06: // Partial list of 128-bit UUIDs    case 0x07: // Complete list of 128-bit UUIDs    case 0x15: // List of 128-bit Service Solicitation UUIDs     while (length >= 16) {      long lsb = buffer.getLong();      long msb = buffer.getLong();      parsedAd.uuids.add(new UUID(msb, lsb));      length -= 16;     }     break;    case 0x08: // Short local device name    case 0x09: // Complete local device name     byte sb[] = new byte[length];     buffer.get(sb, 0, length);     length = 0;     parsedAd.localName = new String(sb).trim();     break;    case (byte) 0xFF: // Manufacturer Specific Data     parsedAd.manufacturer = buffer.getShort();     length -= 2;     break;    default: // skip     break;   }   if (length > 0) {    buffer.position(buffer.position() + length);   }  }  return parsedAd; } 

其中 ParsedAd 是自定義的簡單 Java 對象,用來保存解析后的數據。這里只是解析了我關心的數據,你也可以根據前面的說明,解析更多的內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM