背景
我的一个工程中,有使用扫描附近wifi这个feature,借鉴了ESP32官方的示例程序,在原esp-idf v5.0.1 上可以运行,esp-idf v5.2.1 中却扫描不到。
核心流程:就是在STA模式或STA+AP模式下,启动wifi(不连接)后,可以使用esp_wifi_scan_start()函数进行扫描,扫描后,使用 esp_wifi_scan_get_ap_num 和 esp_wifi_scan_get_ap_records 进行获取扫描的结果。
问题解决方法
一顿“控制变量法”不断实验,以及深入阅读官方文档后,有了解决方案。
实验中发现
实验中发现,先 esp_wifi_scan_get_ap_num 后,再 esp_wifi_scan_get_ap_records 可以解决。
文档中发现
文档中发现:
esp_wifi_scan_get_ap_records的一个个参数竟然是inout类型的,并且有Attention说调用后 will free all memory occupied by scanned AP list. 也就是再读取后会清除缓存?
所以再esp_wifi_scan_get_ap_num就读出的是0? 这是个人猜测。
最终解决办法
所以,最后的解决办法是,干脆只用esp_wifi_scan_get_ap_records 函数,不用 esp_wifi_scan_get_ap_num ,这样就OK了。
放一个代码片段:
#define DEFAULT_SCAN_LIST_SIZE 16
my_ap_wifi_info my_aps_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t my_aps_num = 0;
typedef struct
{
uint8_t ssid[33];
int8_t rssi;
uint8_t rssi_level;
uint8_t rssi_percent;
uint8_t channel;
bool needpsw;
} my_ap_wifi_info;
//不能在AP模式下扫描,需要启动wifi,但不能连接。
void wifi_scan(void){
wifi_country_t country_config = {
.cc = "01",
.schan = 1,
.nchan = 11,
.policy = WIFI_COUNTRY_POLICY_AUTO,
};
esp_wifi_set_country(&country_config);
uint16_t ap_num = DEFAULT_SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;
memset(ap_info, 0, sizeof(ap_info));
static wifi_scan_config_t scanConf = {
.ssid = NULL,
.bssid = NULL,
.channel = 0,
.show_hidden = 0,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time.active.min = 0,
.scan_time.active.max = 0,
};//定义scanConf结构体,供函数esp_wifi_scan_start调用
ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, true));
// ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_num, ap_info));
// ESP_LOGI("[INFO]", "scan: %d", ap_num);
my_aps_num = ap_num;
if(my_aps_num > DEFAULT_SCAN_LIST_SIZE)
my_aps_num = DEFAULT_SCAN_LIST_SIZE; //只能装下这么多
ESP_LOGI(TAG, "[Info] Total APs scanned = %u", my_aps_num);
for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < my_aps_num); i++) {
strcpy(&my_aps_info[i].ssid, &ap_info[i].ssid);
my_aps_info[i].rssi = ap_info[i].rssi;
my_aps_info[i].rssi_level = rssi_to_5_level(ap_info[i].rssi);
my_aps_info[i].rssi_percent = rssi_to_percent(ap_info[i].rssi);
my_aps_info[i].channel = ap_info[i].primary;
my_aps_info[i].needpsw = ap_info[i].authmode != WIFI_AUTH_OPEN;
ESP_LOGI(TAG, "WIFI index \t\t%d", i+1);
ESP_LOGI(TAG, "SSID \t\t\t%s----%s", my_aps_info[i].ssid, my_aps_info[i].needpsw?"有密码":"无密码");
ESP_LOGI(TAG, "RSSI \t\t\t%d--%d--%d%%", my_aps_info[i].rssi, my_aps_info[i].rssi_level, my_aps_info[i].rssi_percent);
ESP_LOGI(TAG, "Channel \t\t%d\n", my_aps_info[i].channel);
}
}
一些小点
配置扫描的国家地区
wifi_country_t country_config = {
.cc = "01",
.schan = 1,
.nchan = 11,
.policy = WIFI_COUNTRY_POLICY_AUTO,
};
esp_wifi_set_country(&country_config);
配置扫描的方式
static wifi_scan_config_t scanConf = {
.ssid = NULL,
.bssid = NULL,
.channel = 0,
.show_hidden = 0,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time.active.min = 0,
.scan_time.active.max = 0,
};//定义scanConf结构体,供函数esp_wifi_scan_start调用
ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, true));
参数含义,具体详见官方api手册:https://docs.espressif.com/projects/esp-idf/zh_CN/v5.2.1/esp32c3/api-reference/network/esp_wifi.html?highlight=esp_wifi_scan_start#_CPPv419esp_wifi_scan_startPK18wifi_scan_config_tb
也可以用NULL,表示使用默认配置。
ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, true));
信号等级的转换
定义了2个小函数,将rssi变得可读性更高:
//将rssi转换成信号等级
uint8_t rssi_to_5_level(int8_t rssi){
if(rssi <= -100)
return 0;
else if (rssi <= -88)
return 1;
else if (rssi <= -77)
return 2;
else if (rssi <= -55)
return 3;
else
return 4;
}
//将rssi转换成百分数
uint8_t rssi_to_percent(int8_t rssi){
//-100:0 -50:100
int8_t rssi_percent = 200 + rssi*2;
if(rssi_percent > 100)
rssi_percent = 100;
else if(rssi_percent < 0)
rssi_percent = 0;
return rssi_percent;
}
来源:
链接:https://blog.csdn.net/weixin_43550576/article/details/137374231