LE Set Scan Parameters command


该指令中,需要 Host 传给 Controller 的参数有:
LE_Scan_Type
LE_Scan_Interval
LE_Scan_Window
Own_Address_Type
Scanning_Filter_Policy
Controller 返回给 Host 的参数只有一个:
Status
Description 翻译
原文
This command is used to set the scan parameters.
翻译
这个命令用于设置扫描参数。
也就是说,它不是用来"开始扫描"的,而是用来配置"扫描怎么进行"。
原文
The LE_Scan_Type parameter controls the type of scan to perform.
翻译
LE_Scan_Type 参数用于控制要执行的扫描类型。
这里主要就是两种:
Passive Scanning:被动扫描
Active Scanning:主动扫描
被动扫描只接收广播包,不主动发 SCAN_REQ。
主动扫描在收到可扫描广播包后,可以发送 SCAN_REQ,然后等待从设备回复 SCAN_RSP。
原文
The LE_Scan_Interval and LE_Scan_Window parameters are recommendations from the Host on how long (LE_Scan_Window) and how frequently (LE_Scan_Interval) the Controller should scan (See Vol 6 Part B, Section 4.4.3).
翻译
LE_Scan_Interval 和 LE_Scan_Window 参数是 Host 给 Controller 的建议,用来说明 Controller 应该扫描多长时间,以及多频繁地进行扫描。
其中:
LE_Scan_Window:每个扫描周期中,实际扫描的持续时间
LE_Scan_Interval:扫描周期的间隔
可以这样理解:
LE_Scan_Interval = 多久启动一次扫描窗口
LE_Scan_Window = 每次扫描窗口持续多久
例如:
LE_Scan_Interval = 100 ms
LE_Scan_Window = 50 ms
大概意思就是:
每 100 ms 作为一个扫描周期,其中有 50 ms 在扫描,剩下 50 ms 不扫描。
原文
The LE_Scan_Window parameter shall always be set to a value smaller or equal to the value set for the LE_Scan_Interval parameter.
翻译
LE_Scan_Window 参数必须始终设置为小于或等于 LE_Scan_Interval 参数的值。
也就是:
LE_Scan_Window <= LE_Scan_Interval
不能出现:
LE_Scan_Window > LE_Scan_Interval
因为扫描窗口不可能比扫描周期还长。
原文
If they are set to the same value, scanning should be run continuously.
翻译
如果这两个参数被设置为相同的值,那么扫描应该连续进行。
也就是:
LE_Scan_Window = LE_Scan_Interval
表示连续扫描。
例如:
LE_Scan_Interval = 100 ms
LE_Scan_Window = 100 ms
含义就是:
整个扫描周期都在扫描,没有空档。
原文
Own_Address_Type parameter indicates the type of address being used in the scan request packets.
翻译
Own_Address_Type 参数表示在扫描请求包中使用的本机地址类型。
这里要注意,它主要影响 Active Scanning 时发出的:
SCAN_REQ
因为 SCAN_REQ 里面会带主设备自己的地址,也就是:
ScanA
所以 Own_Address_Type 决定的是主设备在 SCAN_REQ 里使用什么类型的地址,比如 Public Device Address 或 Random Device Address。
Errors 翻译
原文
See Section 4.5.2 for a list of error types and descriptions.
翻译
错误类型和描述列表请参见 4.5.2 节。
错误表格翻译
| Type | Condition | Error code |
|---|---|---|
| MC | Controller 中已经启用了扫描 | Command Disallowed,0x0C |
意思是:
如果 Controller 当前已经处于扫描开启状态,这时候你再发送:
HCI_LE_Set_Scan_Parameters
Controller 可以返回:
Command Disallowed,0x0C
因为扫描参数不能在扫描已经开启时修改。
正确流程应该是:
LE Set Scan Enable = 0x00 // 先关闭扫描
LE Set Scan Parameters // 再设置扫描参数
LE Set Scan Enable = 0x01 // 再开启扫描
必要 Tip
Tip 1:这个命令只"配置扫描",不"开启扫描"
LE Set Scan Parameters 只是设置扫描参数。
真正开启扫描的是:
LE Set Scan Enable
所以 Legacy Scanning 的基础流程是:
LE Set Scan Parameters
↓
LE Set Scan Enable
↓
Controller 开始监听 37 / 38 / 39 广播信道
↓
收到广播包后,通过 LE Advertising Report Event 上报给 Host
Tip 2:LE_Scan_Window 不能大于 LE_Scan_Interval
这是这个命令里非常关键的约束:
LE_Scan_Window <= LE_Scan_Interval
可以这样记:
Interval 是整个周期
Window 是周期中真正扫描的时间
所以 Window 不能比 Interval 还大。
Tip 3:Window = Interval 表示连续扫描,但不等于一定能收到所有广播包
规范说:
If they are set to the same value, scanning should be run continuously.
意思是扫描会尽量连续进行。
但是实际中还要考虑:
手机系统调度
Controller 实现
多任务共存
蓝牙和 Wi-Fi 共存
功耗策略
扫描信道切换
广播包碰撞
所以连续扫描并不等于"空口上所有广播包都百分百收到"。
Tip 4:Active Scanning 才会发 SCAN_REQ
LE_Scan_Type 如果设置为 Passive Scanning,那么中心设备只听广播,不会主动问从设备要扫描响应数据。
如果设置为 Active Scanning,中心设备才可能对可扫描广播包发送:
SCAN_REQ
然后从设备回复:
SCAN_RSP
所以完整名称、厂商自定义数据等如果被放在 Scan Response Data 里,主设备就需要主动扫描才有机会拿到。
Tip 5:Own_Address_Type 主要和 SCAN_REQ 相关
截图里说:
Own_Address_Type parameter indicates the type of address being used in the scan request packets.
这里的 scan request packets 指的就是:
SCAN_REQ
也就是说,主设备主动扫描时发出的 SCAN_REQ 里面会带自己的地址。
Legacy SCAN_REQ 里有两个重要地址字段:
ScanA:Scanner Address,也就是主设备地址
AdvA :Advertiser Address,也就是广播设备地址
Own_Address_Type 影响的就是 ScanA 使用什么地址类型。
Tip 6:正在扫描时不能改扫描参数
这个截图最下面的错误表格非常重要。
如果扫描已经打开:
LE Set Scan Enable = 0x01
这时候再发:
LE Set Scan Parameters
可能会返回:
Command Disallowed,0x0C
所以要养成一个固定流程:
先 Disable Scan
再 Set Scan Parameters
再 Enable Scan
也就是:
HCI_LE_Set_Scan_Enable(0x00)
HCI_LE_Set_Scan_Parameters(...)
HCI_LE_Set_Scan_Enable(0x01)
Tip 7:这个命令是 Legacy Scanning 用的,不是 Extended Scanning 的新命令
LE Set Scan Parameters 是传统 BLE Legacy Scanning 里的命令。
如果是 Bluetooth 5 之后的 Extended Advertising / Extended Scanning,还会涉及:
LE Set Extended Scan Parameters
LE Set Extended Scan Enable
所以你现在看这个 7.8.10 LE Set Scan Parameters command,可以先把它放在 Legacy Scanning 体系里理解。

LE_Scan_Type
| Value | Parameter Description |
|---|---|
| 0x00 | 被动扫描。不会发送扫描 PDU,默认值 |
| 0x01 | 主动扫描。可以发送扫描 PDU |
| All other values | 保留,供将来使用 |
这里的 Scanning PDU,主要就是指主动扫描时发出的:
SCAN_REQ
所以可以理解为:
LE_Scan_Type = 0x00
只听广播,不主动发 SCAN_REQ
LE_Scan_Type = 0x01
收到可扫描广播后,可以主动发 SCAN_REQ
LE_Scan_Interval
| Value | Parameter Description |
|---|---|
| N = 0xXXXX | 该参数定义为:从 Controller 开始上一次 LE 扫描,到它开始下一次 LE 扫描之间的时间间隔。 |
详细说明:
Range: 0x0004 to 0x4000
Default: 0x0010 (10 ms)
Time = N × 0.625 ms
Time Range: 2.5 ms to 10.24 s
翻译:
取值范围:0x0004 到 0x4000
默认值:0x0010,也就是 10 ms
时间 = N × 0.625 ms
时间范围:2.5 ms 到 10.24 s
也就是说,LE_Scan_Interval 不是直接填毫秒,而是填一个单位值 N。
换算公式是:
实际时间 = N × 0.625 ms
例如:
N = 0x0010 = 16
时间 = 16 × 0.625 ms = 10 ms
所以默认值 0x0010 对应 10 ms。
LE_Scan_Window
| Value | Parameter Description |
|---|---|
| N = 0xXXXX | LE 扫描的持续时间。LE_Scan_Window 必须小于或等于 LE_Scan_Interval。 |
详细说明:
Range: 0x0004 to 0x4000
Default: 0x0010 (10 ms)
Time = N × 0.625 ms
Time Range: 2.5 ms to 10.24 s
翻译:
取值范围:0x0004 到 0x4000
默认值:0x0010,也就是 10 ms
时间 = N × 0.625 ms
时间范围:2.5 ms 到 10.24 s
也就是说,LE_Scan_Window 也不是直接填毫秒,也要通过 N × 0.625 ms 换算。
例如:
N = 0x0010 = 16
时间 = 16 × 0.625 ms = 10 ms
Tip 1:Interval 是扫描周期,Window 是真正扫描的时间
这两个参数很容易混淆。
可以这样理解:
LE_Scan_Interval:扫描周期
LE_Scan_Window:每个扫描周期里面真正扫描的时间
例如:
LE_Scan_Interval = 100 ms
LE_Scan_Window = 50 ms
含义大概是:
每 100 ms 一个扫描周期
其中 50 ms 在扫描
剩下 50 ms 不扫描
画成图就是:
|<----------- 100 ms ----------->|
|<--- 50 ms scan --->| idle......|
|<----------- 100 ms ----------->|
|<--- 50 ms scan --->| idle......|
Tip 2:Window 必须小于或等于 Interval
规范要求:
LE_Scan_Window <= LE_Scan_Interval
不能配置成:
LE_Scan_Window > LE_Scan_Interval
因为 Window 是 Interval 里面的一段时间,不能比整个扫描周期还长。
Tip 3:Window = Interval 表示连续扫描
如果:
LE_Scan_Window = LE_Scan_Interval
那么表示连续扫描。
例如默认值就是:
LE_Scan_Interval = 0x0010 = 10 ms
LE_Scan_Window = 0x0010 = 10 ms
也就是:
扫描周期 10 ms
扫描窗口 10 ms
整个周期都在扫描
可以理解为:
|<--- 10 ms scan --->|
|<--- 10 ms scan --->|
|<--- 10 ms scan --->|
Tip 4:Passive Scanning 不会拿到 Scan Response
如果:
LE_Scan_Type = 0x00
就是被动扫描。
被动扫描只接收广播包,比如:
ADV_IND
ADV_NONCONN_IND
ADV_SCAN_IND
它不会发送:
SCAN_REQ
所以它也不会触发从设备回复:
SCAN_RSP
因此,如果蓝牙模块把完整名称、部分厂商数据、额外 Service UUID 放在 Scan Response Data 里面,被动扫描可能就看不到这些内容。
Tip 5:Active Scanning 是"可以发",不是"一定发"
截图里面写的是:
Scanning PDUs may be sent.
这里的 may be sent 很关键,意思是:
可以发送扫描 PDU
不是:
一定会发送扫描 PDU
因为 Controller 是否真的发 SCAN_REQ,还要看广播包类型、过滤策略、地址匹配、扫描时机、Controller 实现等因素。
比如收到下面这种广播包时,才有扫描响应的意义:
ADV_IND
ADV_SCAN_IND
如果收到的是不可扫描广播,例如:
ADV_NONCONN_IND
那么即使你设置了 Active Scanning,也不会正常去要 Scan Response。
Tip 6:Interval / Window 的单位不是 1 ms,而是 0.625 ms
这点很容易踩坑。
规范中的值不是直接写毫秒,而是:
Time = N × 0.625 ms
所以:
0x0004 = 4 × 0.625 ms = 2.5 ms
0x0010 = 16 × 0.625 ms = 10 ms
0x00A0 = 160 × 0.625 ms = 100 ms
0x4000 = 16384 × 0.625 ms = 10240 ms = 10.24 s
如果你想配置 100 ms,应该填:
100 / 0.625 = 160 = 0x00A0
而不是直接填 100。
Tip 7:这三个参数组合起来看,Legacy Scanning 就清楚了
可以把它们合起来理解:
LE_Scan_Type
决定是被动扫描还是主动扫描
LE_Scan_Interval
决定多久启动一次扫描窗口
LE_Scan_Window
决定每次扫描窗口持续多久
一个典型的主动连续扫描配置可以是:
LE_Scan_Type = 0x01 // Active Scanning
LE_Scan_Interval = 0x0010 // 10 ms
LE_Scan_Window = 0x0010 // 10 ms
含义是:
主动扫描
扫描周期 10 ms
扫描窗口 10 ms
连续扫描
可以发送 SCAN_REQ
有机会拿到 SCAN_RSP
一句话总结:
LE_Scan_Type 决定扫不扫 Scan Response;
LE_Scan_Interval 决定扫描周期;
LE_Scan_Window 决定周期内真正扫描多久。

Own_Address_Type
| Value | Parameter Description |
|---|---|
| 0x00 | Public Device Address,公共设备地址,默认值 |
| 0x01 | Random Device Address,随机设备地址 |
| 0x02 | Controller 根据 Resolving List 中本地 IRK 生成 Resolvable Private Address。如果 Resolving List 中没有匹配项,则使用 Public Address |
| 0x03 | Controller 根据 Resolving List 中本地 IRK 生成 Resolvable Private Address。如果 Resolving List 中没有匹配项,则使用 LE_Set_Random_Address 设置的 Random Address |
| All other values | 保留,供将来使用 |
这里的 Own_Address_Type 表示中心设备在扫描请求包里使用什么类型的本机地址。
对于 Legacy Active Scanning 来说,中心设备可能会发送:
SCAN_REQ
SCAN_REQ 里面有两个地址字段:
ScanA:Scanner Address,扫描设备地址,也就是中心设备自己的地址
AdvA :Advertiser Address,广播设备地址,也就是外设地址
所以 Own_Address_Type 主要决定 ScanA 使用什么地址类型。
Scanning_Filter_Policy
| Value | Parameter Description |
|---|---|
| 0x00 | 基础的不过滤扫描策略 |
| 0x01 | 基础的过滤扫描策略 |
| 0x02 | 扩展的不过滤扫描策略 |
| 0x03 | 扩展的过滤扫描策略 |
| All other values | 保留,供将来使用 |
这里的 Scanning_Filter_Policy 用来控制扫描时是否使用过滤策略。
简单理解:
0x00:不过滤,正常扫描所有广播设备
0x01:使用基础过滤策略
0x02:扩展的不过滤策略
0x03:扩展的过滤策略
Return parameters
| Value | Parameter Description |
|---|---|
| 0x00 | HCI_LE_Set_Scan_Parameters 命令执行成功 |
| 0x01 to 0xFF | HCI_LE_Set_Scan_Parameters 命令执行失败。错误码和描述请参考 [Vol 1] Part F, Controller Error Codes |
也就是说,Controller 收到 HCI_LE_Set_Scan_Parameters 之后,会返回一个 Status。
如果:
Status = 0x00
表示设置扫描参数成功。
如果:
Status != 0x00
表示设置失败,需要根据错误码进一步判断原因。
Event(s) generated,unless masked away
原文
When the HCI_LE_Set_Scan_Parameters command has completed, an HCI_Command_Complete event shall be generated.
翻译
当 HCI_LE_Set_Scan_Parameters 命令完成后,应当生成一个 HCI_Command_Complete 事件。
也就是说,这个命令不是通过普通数据包返回结果,而是通过 HCI Event 返回结果。
流程可以理解为:
Host 发送 HCI_LE_Set_Scan_Parameters
↓
Controller 执行该命令
↓
Controller 返回 HCI_Command_Complete Event
↓
Event 里面带 Status