---
# System prepended metadata

title: DAY4-藍牙BLE封包結構

---


嗨，開始本章之前，我將先帶領你接觸一下藍芽封包的互動式介面：

<iframe src="https://catdogbird3.github.io/ble-packet-explorer/" frameborder="1" height="700">
  藍牙低功耗封包結構

</iframe>
## 1. BLE 封包大外觀：先鎖定 PDU

完整的 BLE 封包大致長這樣：前面是 **Preamble、Access Address**，接著是 **PDU**，最後是 **CRC**。
這一頁只關心中間的 **PDU（Protocol Data Unit）**，而 PDU 又分兩種：([Nordic Developer Academy][1])

* **Advertising PDU**：在 37/38/39 廣播頻道上的封包
* **Data PDU**：連線後，在 data channel 上跑來跑去的資料封包

現在在講的是「Advertising PDU」。

---

## 2. Advertising PDU 結構：Header + Payload

官方的圖長這樣：

![[reference link](https://academy.nordicsemi.com/courses/bluetooth-low-energy-fundamentals/lessons/lesson-2-bluetooth-le-advertising/topic/advertisement-packet/)](https://hackmd.io/_uploads/rkpLqMVzZl.png)
![reference](https://sp-ao.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_1201/https://academy.nordicsemi.com/wp-content/uploads/2023/04/blefund_less2_PDU_header-.png)

### 2.1 Header 裡有哪些欄位？

Header 幾個重點欄位（多數你在 stack 會看得到對應的 bit）([Nordic Developer Academy][1])：

* **PDU Type**

  * 決定這包是 `ADV_IND`、`ADV_NONCONN_IND`… 那幾種廣告型態（就是你上一頁學的那張表）。

* **RFU（Reserved For Future Use）**

  * 保留欄位，目前你基本上可以忽略，照規格設定就好。

* **ChSel**

  * 若裝置支援 **Channel Selection Algorithm #2** 就設為 1。
  * 這是 Link Layer 的細節，通常由 BLE stack 自己處理。

* **TxAdd（Tx Address bit）**

  * 告訴對方「**這包裡的發送者位址是 Public 還是 Random**」。
  * 0 = public，1 = random。
  * 跟你剛學的 Bluetooth Address 那一頁串在一起。

* **RxAdd（Rx Address bit）**

  * 在「定向廣播」時用，表示目標接收者位址是 public 還是 random。

* **Length**

  * Payload 長度（幾個 byte）。

這些大部分由控制器 / stack 幫你塞好，你在 nRF Connect SDK 通常不會一個 bit 去改，但看 sniffer log 時就會看到它們。

---

## 3. Payload：AdvA + AdvData

對 **legacy advertising** 來說，payload 的切法很固定：([Nordic Developer Academy][1])

> **前 6 bytes：AdvA（Advertiser Address）
> 後面：AdvData（真正的廣告內容）**

* **AdvA**：

  * 廣播者的藍牙位址（就是前一頁講的 public / random address 那串）。

* **AdvData**：

  * 這台裝置想對外宣傳的資料，例如旗標、名稱、服務 UUID、iBeacon data… 都塞在這裡。

🔸 特例：`ADV_DIRECT_IND`（定向廣播）

* 這種廣播要多放「目標接收者位址」6 bytes。
* 所以它把 AdvData 位置拿去放 **Rx Address**，**就沒有 AdvData 了**。
* 換句話說，定向廣播只有「誰在呼叫誰」的資訊，不再額外廣告別的資料。([Nordic Developer Academy][1])

---

## 4. AdvData 裡面又是小積木：AD structures

AdvData 不是一坨亂塞，而是由一塊一塊 **AD structure** 拼起來：([Nordic Developer Academy][1])

> 一個 AD structure = `Length` + `AD Type` + `AD Data`

* **Length**：

  * 1 byte，表示「**這個 AD structure 後面整塊有多長（含 Type + Data）**」。

* **AD Type**：

  * 1 byte，定義這塊資料是什麼類型，例如：Flags、完整名稱、Service UUID…
  * 型別值都在藍牙規格／nRF Connect SDK 文件 EIR/AD data type definitions 裡列出。([Nordic Developer Academy][1])

* **AD Data**：

  * 真正的內容，長度 = `Length - 1`（因為已包含 Type）。

整包 AdvData 就是：`[Len, Type, Data] [Len, Type, Data] [Len, Type, Data] ...`
像在一條 byte 串上排很多小積木。

---

## 5. 常見的 AD Type

Nordic 在文中列了幾個接下來會用到的型別：([Nordic Developer Academy][1])

* **Complete local name (`BT_DATA_NAME_COMPLETE`)**
  → 手機掃描時看到的**完整裝置名稱**。

* **Shortened local name (`BT_DATA_NAME_SHORTENED`)**
  → 名稱太長時，放簡短版在廣播裡（完整版本可以透過 GATT 讀 `Device Name` characteristic）。

* **URI (`BT_DATA_URI`)**
  → 放網址之類的 URI；很多「掃到會導向某網站」的小 Beacon 就靠這個。

* **Service UUID**
  → 放一個或多個 Service 的 UUID，讓 Central 一看就知道：
  「喔這顆有 Heart Rate / Battery / 自訂 Service。」

* **Manufacturer Specific Data (`BT_DATA_MANUFACTURER_DATA`)**
  → 給廠商自訂格式用的區塊。
  → 像 iBeacon 的 payload，就是塞在 Manufacturer Data 裡。

* **Flags**
  → 1 個 byte，裡面每一個 bit 是一個旗標（最多 8 個）。
  → 定義這顆裝置目前的模式，例如：

  * `BT_LE_AD_LIMITED`：Limited Discoverable Mode（只廣播一段時間就 timeout）
  * `BT_LE_AD_GENERAL`：General Discoverable Mode（一直可被找到，timeout = 0）
  * `BT_LE_AD_NO_BREDR`：這台**不支援 Classic Bluetooth（BR/EDR）**。([Nordic Developer Academy][1])

官方還示範了一個 AD structure，只用 Flags 這一 byte 把 `BT_LE_AD_NO_BREDR` 打開，你之後如果在 nRF Connect SDK 裡看到類似：

```c
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)
```

就可以直接跟這一段概念對上。

---

## 6. 實務心法

當你在 nRF Connect SDK 設廣告資料時，其實就是在建一個 **AdvData 的 AD structure 陣列**，然後交給 stack 去組成整包 Advertising PDU：

1. 你決定放哪些 AD structure（Flags、名稱、UUID、Manufacturer data…）
2. SDK 幫你算好 `Length`、排成一條 `AdvData` byte 串
3. 底層 Link Layer 再幫你包上 Header、Access Address、CRC，最後送出去

所以理解這一頁的重點就是兩句：

> 1. **Advertising PDU = Header + Payload（AdvA + AdvData）**
> 2. **AdvData = 很多個 [Length + Type + Data] 小積木**

之後你用 sniffer 抓廣播封包時，就可以一眼看出每個 byte 在哪一層、扮演什麼角色了 ✨

[1]: https://academy.nordicsemi.com/courses/bluetooth-low-energy-fundamentals/lessons/lesson-2-bluetooth-le-advertising/topic/advertisement-packet/ "Advertisement packet - Nordic Developer Academy"
