本文通过配置不同的预设扫描参数来测试 ESP8266 实际扫描信道总时间。
passive scan: 被动扫描,将 ESP8266 设置为 passive scan, ESP8266 将处于被动扫描状态,通过监听每个信道上,AP 定时发出的 beacon 帧,从而扫描到 AP 的详细信息。
active scan: 主动扫描,将 ESP8266 设置为 active scan, ESP8266 将处于主动扫描状态,在每个信道发送 probe request 帧来发送请求发现 AP, 如果 AP 同意其发现自己,发送 probe respond 帧来回复 ESP8266.
ESP8266 扫描的参数主要有下面的结构体描述。
/** @brief Range of active scan times per channel */
typedef struct {
uint32_t min; /**< minimum active scan time per channel, units: millisecond */
uint32_t max; /**< maximum active scan time per channel, units: millisecond, values above 1500ms may cause station to disconnect from AP and are not recommended. */
} wifi_active_scan_time_t;
/** @brief Aggregate of active & passive scan time per channel */
typedef union {
wifi_active_scan_time_t active; /**< active scan time per channel, units: millisecond. */
uint32_t passive; /**< passive scan time per channel, units: millisecond, values above 1500ms may
cause station to disconnect from AP and are not recommended. */
} wifi_scan_time_t;
struct scan_config {
uint8 *ssid; // Note: ssid == NULL, don't filter ssid.
uint8 *bssid; // Note: bssid == NULL, don't filter bssid.
uint8 channel; // Note: channel == 0, scan all channels, otherwise scan set channel.
uint8 show_hidden; // Note: show_hidden == 1, can get hidden ssid routers' info.
wifi_scan_type_t scan_type; // scan type, active or passive
wifi_scan_time_t scan_time; // scan time per channel
};
scan_type
决定主动扫描还是被动扫描。
scan_time
决定每个信道上扫描的驻留时间。
如果设置为主动扫描,则需要设置每个信道驻留最大时间和驻留最小时间。
扫描接口wifi_station_scan
可按如下方式进行。其中scan_done
为扫描完成时的回调。用户可在扫描完后处理扫描结果,如打印扫描到的AP详细信息等。
wifi_scan_time_t passive_scan_time;
passive_scan_time.passive = scan_time;
struct scan_config config = { NULL, NULL, 0, 0, WIFI_SCAN_TYPE_ACTIVE, passive_scan_time};
start_time_us = system_get_time();
if (wifi_station_scan(&config, scan_done) == 0) {
}
主动扫描参数说明:
min=0, max=0: scan dwells on each channel for 120 ms.
min>0, max=0: scan dwells on each channel for 120 ms.
min=0, max>0: scan dwells on each channel for max ms.
min>0, max>0: the minimum time the scan dwells on each channel is min ms.
If no AP is found during this time frame, the scan switches to the next channel.
Otherwise,the scan dwells on the channel for max ms.
测试基于 ESP8266_NONOS_SDK -master branch- CommitID:c67a270fa0ea718f1a99be3f8ef9ec21ac057a35
下面是测试结果,供读者参考。
(测试源码见附件)
通过配置wifi_scan_time_t
中passive
时间来测试实际扫描总时间。
联网模式下,如果设置扫描时间为0,回调将得不到执行。
通过配置wifi_scan_time_t
中active
的min
和max
时间来测试实际扫描总时间。
user_main.c // active scan
#include
#include "osapi.h"
#include "wifi.h"
#include "driver/uart.h"
#include "sntp.h"
#include "user_interface.h"
typedef unsigned long u32_t;
static ETSTimer sntp_timer;
#define MAX_SCAN_ARRAY 20
uint32 result[MAX_SCAN_ARRAY][MAX_SCAN_ARRAY]; // array for actual total scan time
uint32 start_time_us = 0; // scan start timestamp
uint32 end_time_us = 0; // scan callback timestamp
uint32 total_scan_time = 0;
uint32 s_min = 0; // preset scan min interval for every channel
uint32 s_max = 0; // preset scan max interval for every channel
#define CONNECT_WIFI 0
#define PRINT_AP 0 // print AP information, recommand to set to 0 for actual scan time calculate accuracy
void ICACHE_FLASH_ATTR scan_test(int min, int max);
void time_print(const char* note){
uint32 ts = 0;
os_printf("[%s] timestamp: %d\n", note, system_get_time());
}
static void ICACHE_FLASH_ATTR scan_done(void *arg, STATUS status) {
end_time_us = system_get_time(); // set to first command for accurate time
uint8 ssid[33];
char buffer[256];
time_print("scan callback");
if (status == OK) {
result[s_min][s_max] = (end_time_us - start_time_us)/1000;
total_scan_time += result[s_min][s_max];
os_printf("result[%d][%d]=%d\ttotal scan:%d\n", s_min, s_max, result[s_min][s_max], total_scan_time);
if(s_max == 15){
s_min++;
#if CONNECT_WIFI
s_max = 1; // if esp8266 had connected to wifi, scan parameter should not set to 0, otherwises, without callback
#else
s_max = 0;
#endif
}else{
s_max++;
}
if(s_min == 16){
os_printf("test over[success]!\n");
int i = 0, j = 0;
for(i = 0; i <= 15; ++i){
for(j = 0; j <= 15; ++j)
os_printf("%d\t", result[i][j]);
os_printf("\n");
}
os_printf("test over[success]!\n");
system_restart(); // restart and test again
}
scan_test(s_min * 100, s_max * 100); // call core scan function
#if PRINT_AP
struct bss_info *bss_link = (struct bss_info *)arg;
os_printf("status:%d pointer:%p\n", status, arg);
while (bss_link != NULL)
{
os_memset(ssid, 0, sizeof(ssid));
os_memset(buffer, 0, sizeof(buffer));
if (os_strlen(bss_link->ssid) <= 32)
{
os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid));
}
else
{
os_memcpy(ssid, bss_link->ssid, 32);
}
os_sprintf(buffer, "+PSCAN:(%d,\"%s\",%d,\""MACSTR"\",%d,%d,%d)\r\n", bss_link->authmode, ssid, bss_link->rssi, MAC2STR(bss_link->bssid),bss_link->channel, bss_link->freq_offset, bss_link->freqcal_val);
os_printf("scan result:%s\n", buffer);
bss_link = bss_link->next.stqe_next;
}
os_memset(buffer, 0, sizeof(buffer));
os_sprintf(buffer, "success status=%d\r\n",status);
#endif
}
else { // callback ret status != OK
#if PRINT_AP
os_memset(buffer, 0, sizeof(buffer));
os_sprintf(buffer, "status=%d\r\n",status);
#endif
os_printf("test over[failed]!\n");
int i = 0, j = 0;
for(i = 0; i <= 15; ++i){
for(j = 0; j <= 15; ++j)
os_printf("%d\t", result[i][j]);
os_printf("\n");
}
os_printf("test over[failed]!\n");
system_restart(); // restart and test again
}
}
void ICACHE_FLASH_ATTR
scan_test(int min, int max)
{
os_printf("start scan [%d %d]...\n", min, max);
wifi_active_scan_time_t to_set_scan_time;
to_set_scan_time.max = max;
to_set_scan_time.min = min;
s_min = min/100;
s_max = max/100;
wifi_scan_time_t active_scan_time;
active_scan_time.active = to_set_scan_time;
struct scan_config config = { NULL, NULL, 0, 0, WIFI_SCAN_TYPE_ACTIVE, active_scan_time};
start_time_us = system_get_time();
if (wifi_station_scan(&config, scan_done) == 0) {
}
}
void sntpfn()
{
u32_t ts = 0;
ts = sntp_get_current_timestamp();
os_printf("current time : %s\n", sntp_get_real_time(ts));
if (ts == 0) {
// did not got a valid time
} else {
os_timer_disarm(&sntp_timer);
scan_test(100,100);
}
}
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
void start_sntp(){
sntp_setservername(0, "pool.ntp.org"); // set sntp server after got ip address
sntp_init();
os_timer_disarm(&sntp_timer);
os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntpfn, NULL);
os_timer_arm(&sntp_timer, 1000, 1);//1s
}
// esp_err_t event_handler(void *ctx, system_event_t *event)
void event_handler(System_Event_t *event)
{
switch (event->event)
{
case EVENT_STAMODE_GOT_IP:
os_printf("got ip...\n");
start_sntp();
break;
case EVENT_STAMODE_DISCONNECTED:
os_printf("disconnect ...\n");
wifi_station_connect();
break;
default:
break;
}
}
void user_init_cb()
{
os_printf("user_init_cb start.\n");
int i = 0, j = 0;
for(i = 0; i < MAX_SCAN_ARRAY; ++i){
for(j = 0; j < MAX_SCAN_ARRAY; ++j)
result[i][j] = 0;
os_printf("\n");
}
#if CONNECT_WIFI
// set AP parameter
struct station_config config;
bzero(&config, sizeof(struct station_config));
sprintf(config.ssid, "BL_841R");
sprintf(config.password, "1234567890");
wifi_station_set_config(&config);
wifi_station_set_auto_connect(true);
wifi_station_set_reconnect_policy(true);
wifi_station_connect();
#else
scan_test(0,0);
#endif
}
void user_init(void)
{
uart_init(BIT_RATE_115200, BIT_RATE_115200);
wifi_set_opmode(STATION_MODE);
wifi_station_set_auto_connect(0);
system_init_done_cb(user_init_cb);
wifi_set_event_handler_cb(event_handler);
}
user_main.c // passive scan
#include
#include "osapi.h"
#include "wifi.h"
#include "driver/uart.h"
#include "sntp.h"
#include "user_interface.h"
typedef unsigned long u32_t;
static ETSTimer sntp_timer;
#define MAX_SCAN_ARRAY 20
uint32 result[MAX_SCAN_ARRAY]; // array for actual total scan time
uint32 start_time_us = 0; // scan start timestamp
uint32 end_time_us = 0; // scan callback timestamp
uint32 total_scan_time = 0;
uint32 s_time_index = 0;
#define CONNECT_WIFI 1
#define PRINT_AP 0 // print AP information, recommand to set to 0 for actual scan time calculate accuracy
void ICACHE_FLASH_ATTR scan_test(uint32_t scan_time);
void time_print(const char* note){
uint32 ts = 0;
os_printf("[%s] timestamp: %d\n", note, system_get_time());
}
static void ICACHE_FLASH_ATTR scan_done(void *arg, STATUS status) {
end_time_us = system_get_time(); // set to first command for accurate time
uint8 ssid[33];
char buffer[256];
time_print("scan callback");
if (status == OK) {
result[s_time_index] = (end_time_us - start_time_us)/1000;
total_scan_time += result[s_time_index];
os_printf("result[%d]=%d\ttotal scan:%d\n", s_time_index, result[s_time_index], total_scan_time);
s_time_index++;
if(s_time_index == 16){
os_printf("test over[success]!\n");
int i = 0;
for(i = 0; i <= 15; ++i){
os_printf("%d\t", result[i]);
}
os_printf("\n");
os_printf("test over[success]!\n");
system_restart(); // restart and test again
}
scan_test(s_time_index * 100); // call core scan function
#if PRINT_AP
struct bss_info *bss_link = (struct bss_info *)arg;
os_printf("status:%d pointer:%p\n", status, arg);
while (bss_link != NULL)
{
os_memset(ssid, 0, sizeof(ssid));
os_memset(buffer, 0, sizeof(buffer));
if (os_strlen(bss_link->ssid) <= 32)
{
os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid));
}
else
{
os_memcpy(ssid, bss_link->ssid, 32);
}
os_sprintf(buffer, "+PSCAN:(%d,\"%s\",%d,\""MACSTR"\",%d,%d,%d)\r\n", bss_link->authmode, ssid, bss_link->rssi, MAC2STR(bss_link->bssid),bss_link->channel, bss_link->freq_offset, bss_link->freqcal_val);
os_printf("scan result:%s\n", buffer);
bss_link = bss_link->next.stqe_next;
}
os_memset(buffer, 0, sizeof(buffer));
os_sprintf(buffer, "success status=%d\r\n",status);
#endif
}
else { // callback ret status != OK
#if PRINT_AP
os_memset(buffer, 0, sizeof(buffer));
os_sprintf(buffer, "status=%d\r\n",status);
#endif
os_printf("test over[failed]!\n");
int i = 0;
for(i = 0; i <= 15; ++i){
os_printf("%d\t", result[i]);
}
os_printf("\n");
os_printf("test over[failed]!\n");
system_restart(); // restart and test again
}
}
void ICACHE_FLASH_ATTR
scan_test(uint32_t scan_time)
{
os_printf("start scan [%d]...\n", scan_time/100);
s_time_index = scan_time/100;
wifi_scan_time_t passive_scan_time;
passive_scan_time.passive = scan_time;
struct scan_config config = { NULL, NULL, 0, 0, WIFI_SCAN_TYPE_PASSIVE, passive_scan_time};
start_time_us = system_get_time();
if (wifi_station_scan(&config, scan_done) == 0) {
}
}
void sntpfn()
{
u32_t ts = 0;
ts = sntp_get_current_timestamp();
os_printf("current time : %s\n", sntp_get_real_time(ts));
if (ts == 0) {
// did not got a valid time
} else {
os_timer_disarm(&sntp_timer);
scan_test(100);
}
}
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void)
{
enum flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
case FLASH_SIZE_64M_MAP_1024_1024:
rf_cal_sec = 2048 - 5;
break;
case FLASH_SIZE_128M_MAP_1024_1024:
rf_cal_sec = 4096 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
void start_sntp(){
sntp_setservername(0, "pool.ntp.org"); // set sntp server after got ip address
sntp_init();
os_timer_disarm(&sntp_timer);
os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntpfn, NULL);
os_timer_arm(&sntp_timer, 1000, 1);//1s
}
// esp_err_t event_handler(void *ctx, system_event_t *event)
void event_handler(System_Event_t *event)
{
switch (event->event)
{
case EVENT_STAMODE_GOT_IP:
os_printf("got ip...\n");
start_sntp();
break;
case EVENT_STAMODE_DISCONNECTED:
os_printf("disconnect ...\n");
wifi_station_connect();
break;
default:
break;
}
}
void user_init_cb()
{
os_printf("user_init_cb start.\n");
int i = 0;
for(i = 0; i < MAX_SCAN_ARRAY; ++i){
result[i] = 0;
}
os_printf("\n");
#if CONNECT_WIFI
// set AP parameter
struct station_config config;
bzero(&config, sizeof(struct station_config));
sprintf(config.ssid, "BL_841R");
sprintf(config.password, "1234567890");
wifi_station_set_config(&config);
wifi_station_set_auto_connect(true);
wifi_station_set_reconnect_policy(true);
wifi_station_connect();
#else
scan_test(0);
#endif
}
void user_init(void)
{
uart_init(BIT_RATE_115200, BIT_RATE_115200);
wifi_set_opmode(STATION_MODE);
wifi_station_set_auto_connect(0);
system_init_done_cb(user_init_cb);
wifi_set_event_handler_cb(event_handler);
}