802.11 Client Active, Passive Scanning, BGScan, On-roam scanning

本文介绍了无线客户端进行主动和被动扫描的基本原理及应用。详细解释了主动扫描与被动扫描的区别,并探讨了背景扫描与即时扫描的不同行为。此外还讨论了如何通过优化扫描策略来减少对数据传输的影响。

转自http://www.my80211.com/home/2010/1/11/80211-client-active-and-passive-scanning.html &http://madwifi-project.org/wiki/ChipsetFeatures/BackgroundScanning

It is important to understand the difference between active and passive client scanning. Here is an overview ~ Wireless clients learn about available APs by scanning other IEEE 802.11 channels for available APs on the same WLAN/SSID. Scanning other IEEE 802.11 channels can be performed actively or passively as follows: 

Active scan—Active scanning occurs when the client changes its IEEE 802.11 radio tothe channel being scanned,broadcasts a probe request, and then waits to hear any probe responses (or periodic beacons) from APson that channel (with a matching SSID). The IEEE 802.11 standards do not specify how long the client should wait, but 10 ms is a representative period. The probe request frames used in an active scan are one of two types:

Directed probe—The client sends a probe request with a specific destination SSID; only APs with a matching SSID will reply with a probe response 

Broadcast probe—The client sends a broadcast SSID (actually a null SSID) in the probe request; all APs receiving the probe-request will respond, with a probe-response for each SSID they support.

Passive scan—Passive scanning is performed by simply changing the clients IEEE 802.11 radio tothe channel being scanned and waiting for a periodic beacon from any APs on that channel. By default, APs send beacons every 100 ms. Because it may take 100 ms to hear a periodic beacon broadcast,most clients prefer an active scan.

 

During a channel scan, the client is unable to transmit or receive client data traffic.There are a number of approaches clients take to minimize this impact to client data traffic:

Background scanning—Clients may scan available channels before they need to roam. This allows them to build-up knowledge of the RF environment and available APs so they may roam faster if it becomes necessary. Impact to client traffic can be minimized by only scanning when the client is not actively transmitting data, or by periodically scanning only a single alternate channel at a time (scanning a single channel incurs minimal data loss)

BGSCAN is The possibility to scan available channels without losing the current AP association. Since the Atheros card is always operating at a single frequency the driver can only optimize the time when to scan. If you are transferring data continuously, a scan will delay data packets. The driver behaves as if the device went into sleep mode, APs will queue data for a while.

The term "background" is quite misleading and many people thought that the hardware will somehow scan without having an effect on the transfer rate. This is certainly not true. In cases where scanning causes problems a second radio is needed (e.g. a second card just for scanning).

Usage: You can do

iwlist ath0 scan

or

wlanconfig ath0 list scan

in order to scan for instance for APs.

A complete scan requires a few seconds, during that time no data can be transferred. This is critical to certain applications if they require a reliable connection.

On-roam scanning—In contrast with background, on-roam scanning occurs after a roam has been determined necessary. Each vendor/device may implement its own algorithms to minimize the roam latency and the impact to data traffic. For example, some clients might only scan the non-overlapping channels.

Typical Scanning Behavior

Although most client roaming algorithms are proprietary, it is possible to generalize the typical behavior.

Typical wireless client roam behavior consists of the following activities:

•On-roam scanning—This ensures clients have the most up-to-date information at the time of the roam.

•Active scan—An active scan is preferred over a passive scan, due to lower latency when roaming.
There are some informational attributes that may be used to dynamically alter the roam algorithm:

•Client data type—For example, voice call in progress

•Background scan information—Obtained during routine periodic background scans

Ways in which attributes can be used to alter the scan algorithm include:

•Scan a subset of channels—For example, information from the background scan can be used to determine which channels are being used by APs in the vicinity.

•Terminate the scan early—For example, if a voice call is in progress, the first acceptable AP might be used instead of waiting to discover all APs on all channels.

•Change scan timers—For example, if a voice call is in progress, the time spent waiting for probe responses might be shortened during an active scan.

From -- Cisco Voice Over Wireless LAN 4.1 Design Guide

 

#include <esp_wifi.h> #include <esp_event.h> #include <esp_log.h> #include <esp_timer.h> #include <esp_sleep.h> // 状态枚举 enum class WifiState { INIT, // 初始化 SCANNING, // AP扫描 AUTHENTICATING, // 认证中 ASSOCIATING, // 关联中 CONNECTED, // 已连接 DISCONNECTED, // 断开连接 ROAMING_SCAN, // 漫游扫描 ROAMING_AUTH, // 漫游认证 ROAMING_ASSOC, // 漫游关联 LIGHT_SLEEP, // 轻睡眠模式 DEEP_SLEEP // 深睡眠模式 }; // 事件枚举 enum class WifiEvent { SCAN_COMPLETE, // 扫描完成 AUTH_REQ, // 认证请求 AUTH_RESP, // 认证响应 ASSOC_REQ, // 关联请求 ASSOC_RESP, // 关联响应 CONNECTED, // 连接成功 DISCONNECTED, // 连接断开 ROAM_TRIGGER, // 漫游触发 BEACON_LOST, // 信标丢失 SLEEP_ENTER, // 进入睡眠 WAKE_UP // 唤醒事件 }; class WiFiStateMachine { private: // 当前状态 WifiState currentState = WifiState::INIT; // 状态转移表(状态 -> 事件 -> 新状态) std::map<WifiState, std::map<WifiEvent, WifiState>> transitionTable = { {WifiState::INIT, { {WifiEvent::SCAN_COMPLETE, WifiState::SCANNING} }}, {WifiState::SCANNING, { {WifiEvent::AUTH_REQ, WifiState::AUTHENTICATING} }}, {WifiState::AUTHENTICATING, { {WifiEvent::AUTH_RESP, WifiState::ASSOCIATING}, {WifiEvent::DISCONNECTED, WifiState::DISCONNECTED} }}, {WifiState::ASSOCIATING, { {WifiEvent::ASSOC_RESP, WifiState::CONNECTED}, {WifiEvent::DISCONNECTED, WifiState::DISCONNECTED} }}, {WifiState::CONNECTED, { {WifiEvent::DISCONNECTED, WifiState::DISCONNECTED}, {WifiEvent::ROAM_TRIGGER, WifiState::ROAMING_SCAN}, {WifiEvent::SLEEP_ENTER, WifiState::LIGHT_SLEEP} }}, {WifiState::ROAMING_SCAN, { {WifiEvent::AUTH_REQ, WifiState::ROAMING_AUTH} }}, {WifiState::ROAMING_AUTH, { {WifiEvent::AUTH_RESP, WifiState::ROAMING_ASSOC} }}, {WifiState::ROAMING_ASSOC, { {WifiEvent::ASSOC_RESP, WifiState::CONNECTED} }}, {WifiState::LIGHT_SLEEP, { {WifiEvent::WAKE_UP, WifiState::CONNECTED}, {WifiEvent::BEACON_LOST, WifiState::SCANNING} }} }; // 低功耗配置参数 struct { int beacon_interval = 5000; // 默认信标监测间隔(ms) int sleep_delay = 300; // 进入休眠等待时间(s) int roam_threshold = -75; // 漫游触发RSSI阈值(dBm) int roam_scan_duration = 100; // 漫游扫描时长(ms) } powerConfig; // 连接稳定性计数器 int stableCounter = 0; const int STABLE_THRESHOLD = 5; // 连续稳定计数阈值 // 定时器句柄 esp_timer_handle_t beacon_timer; esp_timer_handle_t sleep_timer; /** * 处理状态转移 * @param event 触发事件 */ void handleEvent(WifiEvent event) { auto stateTransitions = transitionTable.find(currentState); if (stateTransitions != transitionTable.end()) { auto newState = stateTransitions->second.find(event); if (newState != stateTransitions->second.end()) { // 执行状态转移前的清理 exitStateActions(currentState); // 更新状态 currentState = newState->second; ESP_LOGI("StateMachine", "Transition: %s -> %s", stateToString(currentState).c_str(), stateToString(newState->second).c_str()); // 执行新状态的入口动作 enterStateActions(newState->second); } } } /** * 状态退出动作 * @param state 退出的状态 */ void exitStateActions(WifiState state) { switch(state) { case WifiState::SCANNING: esp_timer_stop(beacon_timer); break; case WifiState::LIGHT_SLEEP: // 唤醒后恢复活动 esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); break; default: break; } } /** * 状态进入动作 * @param state 进入的状态 */ void enterStateActions(WifiState state) { switch(state) { case WifiState::SCANNING: startScan(); break; case WifiState::AUTHENTICATING: sendAuthRequest(); break; case WifiState::CONNECTED: startBeaconMonitoring(); checkConnectionStability(); break; case WifiState::ROAMING_SCAN: startRoamScan(); break; case WifiState::LIGHT_SLEEP: enterLightSleep(); break; default: break; } } /** * 启动AP扫描 */ void startScan() { wifi_scan_config_t scan_config = { .ssid = nullptr, .bssid = nullptr, .channel = 0, .show_hidden = true, .scan_type = WIFI_SCAN_TYPE_ACTIVE, .scan_time = { .active = 120 } // 120ms主动扫描 }; ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false)); } /** * 启动低功耗漫游扫描 */ void startRoamScan() { wifi_scan_config_t scan_config = { .scan_type = WIFI_SCAN_TYPE_PASSIVE, // 被动扫描省电 .scan_time = { .passive = powerConfig.roam_scan_duration } }; ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, false)); } /** * 进入轻睡眠模式(ESP32优化) */ void enterLightSleep() { // 配置唤醒源 esp_sleep_enable_timer_wakeup(powerConfig.sleep_delay * 1000000); esp_sleep_enable_wifi_wakeup(); // 保存当前状态 WifiState preSleepState = currentState; // 进入轻睡眠(保留WiFi连接) esp_light_sleep_start(); // 唤醒后恢复状态 currentState = preSleepState; handleEvent(WifiEvent::WAKE_UP); } /** * 动态调整信标监测周期 */ void adjustBeaconMonitoring() { // 获取当前信号强度 wifi_ap_record_t ap_info; esp_wifi_sta_get_ap_info(&ap_info); int8_t rssi = ap_info.rssi; // 根据信号质量调整监测频率 if (rssi > -60) { // 强信号 powerConfig.beacon_interval = 10000; // 10秒 stableCounter++; } else if (rssi > -70) { // 中等信号 powerConfig.beacon_interval = 5000; // 5秒 stableCounter = 0; } else { // 弱信号 powerConfig.beacon_interval = 2000; // 2秒 stableCounter = 0; } // 重启定时器 esp_timer_stop(beacon_timer); esp_timer_start_periodic(beacon_timer, powerConfig.beacon_interval * 1000); } /** * 检查连接稳定性 */ void checkConnectionStability() { if (stableCounter >= STABLE_THRESHOLD) { handleEvent(WifiEvent::SLEEP_ENTER); } } /** * 状态转字符串(调试用) */ std::string stateToString(WifiState state) { const std::map<WifiState, std::string> stateMap = { {WifiState::INIT, "INIT"}, {WifiState::SCANNING, "SCANNING"}, {WifiState::AUTHENTICATING, "AUTHENTICATING"}, {WifiState::ASSOCIATING, "ASSOCIATING"}, {WifiState::CONNECTED, "CONNECTED"}, {WifiState::DISCONNECTED, "DISCONNECTED"}, {WifiState::ROAMING_SCAN, "ROAMING_SCAN"}, {WifiState::ROAMING_AUTH, "ROAMING_AUTH"}, {WifiState::ROAMING_ASSOC, "ROAMING_ASSOC"}, {WifiState::LIGHT_SLEEP, "LIGHT_SLEEP"}, {WifiState::DEEP_SLEEP, "DEEP_SLEEP"} }; return stateMap.at(state); } public: WiFiStateMachine() { // 初始化定时器 esp_timer_create_args_t beacon_timer_args = { .callback = [](void* arg) { static_cast<WiFiStateMachine*>(arg)->checkBeacon(); }, .arg = this, .name = "beacon_timer" }; esp_timer_create(&beacon_timer_args, &beacon_timer); esp_timer_create_args_t sleep_timer_args = { .callback = [](void* arg) { static_cast<WiFiStateMachine*>(arg)->handleEvent(WifiEvent::SLEEP_ENTER); }, .arg = this, .name = "sleep_timer" }; esp_timer_create(&sleep_timer_args, &sleep_timer); // 注册WiFi事件处理 esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, [](void* arg, esp_event_base_t base, int32_t id, void* data) { auto self = static_cast<WiFiStateMachine*>(arg); switch(id) { case WIFI_EVENT_STA_CONNECTED: self->handleEvent(WifiEvent::CONNECTED); break; case WIFI_EVENT_STA_DISCONNECTED: self->handleEvent(WifiEvent::DISCONNECTED); break; case WIFI_EVENT_STA_AUTHMODE_CHANGE: // 认证处理 break; } }, this); } /** * 启动状态机 */ void start() { handleEvent(WifiEvent::SCAN_COMPLETE); } /** * 信标监测函数 */ void checkBeacon() { if (currentState == WifiState::CONNECTED) { // 检查信标是否丢失 if (/* 信标丢失检测逻辑 */) { handleEvent(WifiEvent::BEACON_LOST); } // 动态调整监测频率 adjustBeaconMonitoring(); // 检查漫游触发条件 wifi_ap_record_t ap_info; esp_wifi_sta_get_ap_info(&ap_info); if (ap_info.rssi < powerConfig.roam_threshold) { handleEvent(WifiEvent::ROAM_TRIGGER); } } } }; // 初始化WiFi(乐鑫专用API) extern "C" void app_main() { // WiFi初始化 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); // 启动状态机 WiFiStateMachine stateMachine; stateMachine.start(); }不用针对乐鑫芯片写,直接用C++写代码,该有的功能要完整,注释要详细
最新发布
06-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值