mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(ci): add ci test for auto mode connect passive chnnel hidden ap
This commit is contained in:
@@ -2,6 +2,7 @@ idf_component_register(SRCS
|
||||
"app_main.c"
|
||||
"test_wifi_conn.c"
|
||||
"test_bss_max_idle.c"
|
||||
"test_connect_passive_channel_hidden_ap.c"
|
||||
|
||||
PRIV_INCLUDE_DIRS . ${CMAKE_CURRENT_BINARY_DIR}
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash esp_common esp_wifi esp_event
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_err.h"
|
||||
@@ -12,8 +14,7 @@
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// Some resources are lazy allocated in wifi and lwip
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-1896)
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-2100)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
@@ -21,7 +22,7 @@ static size_t before_free_32bit;
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, (unsigned)before_free, (unsigned)after_free, (int)delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
@@ -36,8 +37,10 @@ void setUp(void)
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_wifi_stop());
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ESP_ERROR_CHECK(esp_wifi_deinit());
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tests station association (L2 only; no DHCP / GOT_IP) to a hidden SoftAP when passive-hidden-AP support is enabled.
|
||||
*
|
||||
* Not in default wifi_connect builds: enable CONFIG_ESP_WIFI_PASSIVE_HIDDEN_AP_SUPPORT only via
|
||||
* sdkconfig.ci.passive_hidden_ap (pytest config "passive_hidden_ap"), or merge that file in
|
||||
* SDKCONFIG_DEFAULTS for local builds.
|
||||
*
|
||||
* Wi-Fi remote: CONFIG_WIFI_RMT_PASSIVE_HIDDEN_AP_SUPPORT maps to the same option.
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_ESP_WIFI_PASSIVE_HIDDEN_AP_SUPPORT
|
||||
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_default.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "test_utils.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifndef TEST_SUFFIX_STR
|
||||
#define TEST_SUFFIX_STR "_0000"
|
||||
#endif
|
||||
|
||||
#define TEST_DEFAULT_SSID "SSID_" CONFIG_IDF_TARGET TEST_SUFFIX_STR
|
||||
#define TEST_DEFAULT_PWD "PASS_" CONFIG_IDF_TARGET TEST_SUFFIX_STR
|
||||
|
||||
#if CONFIG_SOC_WIFI_SUPPORT_5G
|
||||
/* DFS channel: passive scan is required by regulatory rules on many domains. */
|
||||
#define TEST_PASSIVE_HIDDEN_AP_CHANNEL (52)
|
||||
#else
|
||||
/* 2.4 GHz passive scan scenario: channel 12 with CN regulatory (see apply_country_auto). */
|
||||
#define TEST_PASSIVE_HIDDEN_AP_CHANNEL (12)
|
||||
#endif
|
||||
|
||||
#define CONNECT_TIMEOUT_MS (30000)
|
||||
#define MAXIMUM_RETRY (5)
|
||||
|
||||
#define WIFI_DISCONNECT_EVENT (1 << 1)
|
||||
#define WIFI_STA_CONNECTED (1 << 2)
|
||||
#define WIFI_AP_STA_CONNECTED (1 << 3)
|
||||
|
||||
static const char *TAG = "test_passive_hidden_ap";
|
||||
|
||||
static EventGroupHandle_t s_wifi_events;
|
||||
static esp_netif_t *s_sta_netif;
|
||||
static esp_netif_t *s_ap_netif;
|
||||
static int s_retry_num;
|
||||
static bool s_sta_conn_first;
|
||||
|
||||
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||
{
|
||||
switch (event_id) {
|
||||
case WIFI_EVENT_AP_STACONNECTED:
|
||||
ESP_LOGI(TAG, "WIFI_EVENT_AP_STACONNECTED");
|
||||
if (s_wifi_events) {
|
||||
xEventGroupSetBits(s_wifi_events, WIFI_AP_STA_CONNECTED);
|
||||
}
|
||||
break;
|
||||
case WIFI_EVENT_STA_CONNECTED:
|
||||
ESP_LOGI(TAG, "WIFI_EVENT_STA_CONNECTED");
|
||||
if (s_wifi_events) {
|
||||
xEventGroupSetBits(s_wifi_events, WIFI_STA_CONNECTED);
|
||||
s_sta_conn_first = true;
|
||||
}
|
||||
break;
|
||||
case WIFI_EVENT_STA_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
|
||||
if (s_wifi_events) {
|
||||
if ((s_retry_num < MAXIMUM_RETRY) && !s_sta_conn_first) {
|
||||
s_retry_num++;
|
||||
ESP_LOGI(TAG, "retry connect to hidden passive-channel AP (%d/%d)", s_retry_num, MAXIMUM_RETRY);
|
||||
esp_wifi_connect();
|
||||
} else {
|
||||
xEventGroupSetBits(s_wifi_events, WIFI_DISCONNECT_EVENT);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t event_init_sta_side(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
|
||||
s_sta_netif = esp_netif_create_default_wifi_sta();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t event_deinit_sta_side(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler));
|
||||
esp_netif_destroy_default_wifi(s_sta_netif);
|
||||
s_sta_netif = NULL;
|
||||
ESP_ERROR_CHECK(esp_event_loop_delete_default());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t event_init_ap_side(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
|
||||
s_ap_netif = esp_netif_create_default_wifi_ap();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t event_deinit_ap_side(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler));
|
||||
esp_netif_destroy_default_wifi(s_ap_netif);
|
||||
s_ap_netif = NULL;
|
||||
ESP_ERROR_CHECK(esp_event_loop_delete_default());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void apply_country_auto(void)
|
||||
{
|
||||
wifi_country_t country = {0};
|
||||
memcpy(country.cc, "CN", 2);
|
||||
country.schan = 1;
|
||||
country.nchan = 13;
|
||||
country.policy = WIFI_COUNTRY_POLICY_AUTO;
|
||||
#if CONFIG_SOC_WIFI_SUPPORT_5G
|
||||
country.wifi_5g_channel_mask = 0;
|
||||
#endif
|
||||
TEST_ESP_OK(esp_wifi_set_country(&country));
|
||||
}
|
||||
|
||||
static void start_hidden_softap_on_passive_channel(void)
|
||||
{
|
||||
wifi_config_t w_config = {
|
||||
.ap.ssid = TEST_DEFAULT_SSID,
|
||||
.ap.password = TEST_DEFAULT_PWD,
|
||||
.ap.ssid_len = strlen(TEST_DEFAULT_SSID),
|
||||
.ap.channel = TEST_PASSIVE_HIDDEN_AP_CHANNEL,
|
||||
.ap.authmode = WIFI_AUTH_WPA2_PSK,
|
||||
.ap.ssid_hidden = true,
|
||||
.ap.max_connection = 4,
|
||||
.ap.beacon_interval = 100,
|
||||
};
|
||||
|
||||
event_init_ap_side();
|
||||
if (s_wifi_events == NULL) {
|
||||
s_wifi_events = xEventGroupCreate();
|
||||
}
|
||||
xEventGroupClearBits(s_wifi_events, 0x00ffffff);
|
||||
|
||||
apply_country_auto();
|
||||
TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_AP));
|
||||
TEST_ESP_OK(esp_wifi_set_config(WIFI_IF_AP, &w_config));
|
||||
TEST_ESP_OK(esp_wifi_start());
|
||||
ESP_LOGI(TAG, "hidden softap on channel %u, ssid (hidden): %s", (unsigned)TEST_PASSIVE_HIDDEN_AP_CHANNEL, TEST_DEFAULT_SSID);
|
||||
}
|
||||
|
||||
static void start_sta(void)
|
||||
{
|
||||
event_init_sta_side();
|
||||
if (s_wifi_events == NULL) {
|
||||
s_wifi_events = xEventGroupCreate();
|
||||
}
|
||||
xEventGroupClearBits(s_wifi_events, 0x00ffffff);
|
||||
|
||||
apply_country_auto();
|
||||
TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
TEST_ESP_OK(esp_wifi_start());
|
||||
}
|
||||
|
||||
static void stop_wifi_sta_side(void)
|
||||
{
|
||||
TEST_ESP_OK(esp_wifi_stop());
|
||||
event_deinit_sta_side();
|
||||
if (s_wifi_events) {
|
||||
vEventGroupDelete(s_wifi_events);
|
||||
s_wifi_events = NULL;
|
||||
}
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
static void stop_wifi_ap_side(void)
|
||||
{
|
||||
TEST_ESP_OK(esp_wifi_stop());
|
||||
event_deinit_ap_side();
|
||||
if (s_wifi_events) {
|
||||
vEventGroupDelete(s_wifi_events);
|
||||
s_wifi_events = NULL;
|
||||
}
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
static void sta_connect_hidden_on_passive_channel(void)
|
||||
{
|
||||
wifi_config_t w_config = { 0 };
|
||||
strncpy((char *)w_config.sta.ssid, TEST_DEFAULT_SSID, sizeof(w_config.sta.ssid));
|
||||
strncpy((char *)w_config.sta.password, TEST_DEFAULT_PWD, sizeof(w_config.sta.password));
|
||||
w_config.sta.channel = TEST_PASSIVE_HIDDEN_AP_CHANNEL;
|
||||
|
||||
TEST_ESP_OK(esp_wifi_set_config(WIFI_IF_STA, &w_config));
|
||||
s_retry_num = 0;
|
||||
s_sta_conn_first = false;
|
||||
TEST_ESP_OK(esp_wifi_connect());
|
||||
ESP_LOGI(TAG, "esp_wifi_connect hidden AP, channel hint %u", (unsigned)TEST_PASSIVE_HIDDEN_AP_CHANNEL);
|
||||
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_events,
|
||||
WIFI_STA_CONNECTED | WIFI_DISCONNECT_EVENT,
|
||||
pdTRUE,
|
||||
pdFALSE,
|
||||
pdMS_TO_TICKS(CONNECT_TIMEOUT_MS));
|
||||
TEST_ASSERT_MESSAGE(bits & WIFI_STA_CONNECTED, "STA did not connect (hidden passive-channel path, L2 only)");
|
||||
}
|
||||
|
||||
static void test_passive_hidden_channel_sta(void)
|
||||
{
|
||||
start_sta();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
sta_connect_hidden_on_passive_channel();
|
||||
stop_wifi_sta_side();
|
||||
}
|
||||
|
||||
static void test_passive_hidden_channel_softap(void)
|
||||
{
|
||||
start_hidden_softap_on_passive_channel();
|
||||
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_events,
|
||||
WIFI_AP_STA_CONNECTED,
|
||||
pdFALSE,
|
||||
pdFALSE,
|
||||
pdMS_TO_TICKS(CONNECT_TIMEOUT_MS));
|
||||
TEST_ASSERT_MESSAGE(bits & WIFI_AP_STA_CONNECTED, "No station connected to hidden softap in time");
|
||||
|
||||
stop_wifi_ap_side();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("connect passive channel hidden softap",
|
||||
"[wifi][passive_hidden_ap]",
|
||||
test_passive_hidden_channel_sta,
|
||||
test_passive_hidden_channel_softap);
|
||||
|
||||
#endif /* CONFIG_ESP_WIFI_PASSIVE_HIDDEN_AP_SUPPORT */
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded_idf.unity_tester import CaseTester
|
||||
@@ -55,3 +55,32 @@ def test_wifi_connect_cases_esp32c2_rev2_xtal26m(case_tester: CaseTester) -> Non
|
||||
@idf_parametrize('target', ['esp32c3'], indirect=['target'])
|
||||
def test_wifi_connect_cases_esp32c3_rev1(case_tester: CaseTester) -> None:
|
||||
case_tester.run_all_cases()
|
||||
|
||||
|
||||
# Must match TEST_CASE_MULTIPLE_DEVICES name string in test_connect_passive_channel_hidden_ap.c (menu line quoted text).
|
||||
_PASSIVE_HIDDEN_AP_CASE = 'connect passive channel hidden softap'
|
||||
|
||||
|
||||
@pytest.mark.two_duts
|
||||
@pytest.mark.parametrize(
|
||||
'count, config',
|
||||
[
|
||||
(2, 'passive_hidden_ap'),
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize(
|
||||
'target',
|
||||
['esp32', 'esp32c3', 'esp32s2', 'esp32s3', 'esp32c5', 'esp32c6', 'esp32c61'],
|
||||
indirect=['target'],
|
||||
)
|
||||
def test_wifi_connect_passive_hidden_ap(case_tester: CaseTester) -> None:
|
||||
"""Firmware uses sdkconfig.ci.passive_hidden_ap; runs only the passive hidden AP multi-DUT case."""
|
||||
for case in case_tester.test_menu:
|
||||
if case.name == _PASSIVE_HIDDEN_AP_CASE:
|
||||
case_tester.run_multi_dev_case(case=case, reset=True)
|
||||
return
|
||||
pytest.fail(
|
||||
f'Case {_PASSIVE_HIDDEN_AP_CASE!r} not in menu; build must merge sdkconfig.ci.passive_hidden_ap '
|
||||
'(CONFIG_ESP_WIFI_PASSIVE_HIDDEN_AP_SUPPORT).'
|
||||
)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Merged when pytest uses config "passive_hidden_ap" (or set SDKCONFIG_DEFAULTS to include this file).
|
||||
# Enables the hidden passive-channel AP test and WIFI_INIT passive-hidden feature bit only for that build.
|
||||
CONFIG_ESP_WIFI_PASSIVE_HIDDEN_AP_SUPPORT=y
|
||||
@@ -1,3 +1,6 @@
|
||||
# Passive hidden AP test: off by default. Merge sdkconfig.ci.passive_hidden_ap when building/running that case only
|
||||
# (see pytest test_wifi_connect_passive_hidden_ap). Example:
|
||||
# idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.ci.passive_hidden_ap" set-target esp32c3 build
|
||||
|
||||
# ignore task watchdog triggered by unity_run_menu
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
Reference in New Issue
Block a user