diff --git a/examples/wifi/itwt/CMakeLists.txt b/examples/wifi/itwt/CMakeLists.txt new file mode 100644 index 0000000000..de90c34187 --- /dev/null +++ b/examples/wifi/itwt/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components + $ENV{IDF_PATH}/examples/common_components/iperf) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(itwt) diff --git a/examples/wifi/itwt/README.md b/examples/wifi/itwt/README.md new file mode 100644 index 0000000000..14c753355d --- /dev/null +++ b/examples/wifi/itwt/README.md @@ -0,0 +1,26 @@ +| Supported Targets | ESP32-C6 | +| ----------------- | -------- | + +# Wifi itwt Example + +## Introduction +This example shows how to use itwt of wifi. + +Itwt only works in station mode. And AP needs to support the capability of itwt. + +This example support command "itwt, itwt_probe, itwt_info" to config itwt. + +* itwt: this command is for itwt setup/teardown. + +* itwt_probe: this command will send a probe request to update tsf time with ap + +* itwt_info: this command will send a TWT Information frame to AP for suspending/resuming extablished iTWT agreements. + +### Typical current consumption with Itwt enabled + + + +### Typical current consumption with Itwt disabled + + +Note that current consumption and average current are higher when disabled. diff --git a/examples/wifi/itwt/main/CMakeLists.txt b/examples/wifi/itwt/main/CMakeLists.txt new file mode 100644 index 0000000000..3a2fe809a1 --- /dev/null +++ b/examples/wifi/itwt/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "itwt.c" + INCLUDE_DIRS ".") \ No newline at end of file diff --git a/examples/wifi/itwt/main/Kconfig.projbuild b/examples/wifi/itwt/main/Kconfig.projbuild new file mode 100644 index 0000000000..d7a8c0f71d --- /dev/null +++ b/examples/wifi/itwt/main/Kconfig.projbuild @@ -0,0 +1,107 @@ +menu "Example Configuration" + + config EXAMPLE_WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + + config EXAMPLE_WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + + menu "iTWT Configuration" + config EXAMPLE_ITWT_TRIGGER_ENABLE + bool "trigger-enabled" + default y + help + 0- a non-trigger-enabled TWT, 1-a trigger-enabled TWT + config EXAMPLE_ITWT_ANNOUNCED + bool "announced" + default y + help + 0- an unannounced TWT, 1-an announced TWT + config EXAMPLE_ITWT_MIN_WAKE_DURA + int "itwt minimum wake duration" + range 1 255 + default 255 + help + Nominal Minimum Wake Duration, indicates the minimum amount of time, in unit of 256 us, that the TWT + requesting STA expects that it needs to be awake. The value range is [1, 255]. + config EXAMPLE_ITWT_WAKE_INVL_EXPN + int "itwt wake interval exponent" + range 0 31 + default 10 + help + TWT Wake Interval Exponent, in microseconds. The value range is [0, 31]. + config EXAMPLE_ITWT_WAKE_INVL_MANT + int "itwt wake interval mantissa" + range 1 65535 + default 512 + help + TWT Wake Interval Mantissa, in microseconds. The value range is [1, 65535]. + endmenu + + choice EXAMPLE_MAX_CPU_FREQ + prompt "Maximum CPU frequency" + default EXAMPLE_MAX_CPU_FREQ_80 + depends on PM_ENABLE + help + Maximum CPU frequency to use for dynamic frequency scaling. + + config EXAMPLE_MAX_CPU_FREQ_80 + bool "80 MHz" + config EXAMPLE_MAX_CPU_FREQ_120 + bool "120 MHz" + depends on IDF_TARGET_ESP32C2 + config EXAMPLE_MAX_CPU_FREQ_160 + bool "160 MHz" + depends on !IDF_TARGET_ESP32C2 + config EXAMPLE_MAX_CPU_FREQ_240 + bool "240 MHz" + depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + endchoice + + config EXAMPLE_MAX_CPU_FREQ_MHZ + int + default 80 if EXAMPLE_MAX_CPU_FREQ_80 + default 120 if EXAMPLE_MAX_CPU_FREQ_120 + default 160 if EXAMPLE_MAX_CPU_FREQ_160 + default 240 if EXAMPLE_MAX_CPU_FREQ_240 + + choice EXAMPLE_MIN_CPU_FREQ + prompt "Minimum CPU frequency" + default EXAMPLE_MIN_CPU_FREQ_10M + depends on PM_ENABLE + help + Minimum CPU frequency to use for dynamic frequency scaling. + Should be set to XTAL frequency or XTAL frequency divided by integer. + + config EXAMPLE_MIN_CPU_FREQ_40M + bool "40 MHz (use with 40MHz XTAL)" + depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO + config EXAMPLE_MIN_CPU_FREQ_20M + bool "20 MHz (use with 40MHz XTAL)" + depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO + config EXAMPLE_MIN_CPU_FREQ_10M + bool "10 MHz (use with 40MHz XTAL)" + depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO + config EXAMPLE_MIN_CPU_FREQ_26M + bool "26 MHz (use with 26MHz XTAL)" + depends on XTAL_FREQ_26 || XTAL_FREQ_AUTO + config EXAMPLE_MIN_CPU_FREQ_13M + bool "13 MHz (use with 26MHz XTAL)" + depends on XTAL_FREQ_26 || XTAL_FREQ_AUTO + endchoice + + config EXAMPLE_MIN_CPU_FREQ_MHZ + int + default 40 if EXAMPLE_MIN_CPU_FREQ_40M + default 20 if EXAMPLE_MIN_CPU_FREQ_20M + default 10 if EXAMPLE_MIN_CPU_FREQ_10M + default 26 if EXAMPLE_MIN_CPU_FREQ_26M + default 13 if EXAMPLE_MIN_CPU_FREQ_13M + +endmenu diff --git a/examples/wifi/itwt/main/itwt.c b/examples/wifi/itwt/main/itwt.c new file mode 100644 index 0000000000..5f35d8b568 --- /dev/null +++ b/examples/wifi/itwt/main/itwt.c @@ -0,0 +1,296 @@ +/* itwt Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +/* + this example shows how to use itwt + set a router or a AP using the same SSID&PASSWORD as configuration of this example. + start esp32c6 and when it connected to AP it will setup itwt. +*/ +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_console.h" +#include "cmd_system.h" +#include "wifi_cmd.h" +#include "esp_wifi_he.h" + +/******************************************************* + * Constants + *******************************************************/ +static const char *TAG = "itwt"; + +/******************************************************* + * Structures + *******************************************************/ + +/******************************************************* + * Variable Definitions + *******************************************************/ +/*set the ssid and password via "idf.py menuconfig"*/ +#define DEFAULT_SSID CONFIG_EXAMPLE_WIFI_SSID +#define DEFAULT_PWD CONFIG_EXAMPLE_WIFI_PASSWORD + +#if CONFIG_EXAMPLE_ITWT_TRIGGER_ENABLE +bool trigger_enabled = true; +#else +bool trigger_enabled = false; +#endif + +#if CONFIG_EXAMPLE_ITWT_ANNOUNCED +bool flow_type_announced = true; +#else +bool flow_type_announced = false; +#endif + +esp_netif_t *netif_sta = NULL; +const int CONNECTED_BIT = BIT0; +const int DISCONNECTED_BIT = BIT1; +EventGroupHandle_t wifi_event_group; + +/******************************************************* + * Function Declarations + *******************************************************/ + +/******************************************************* + * Function Definitions + *******************************************************/ +static const char *itwt_probe_status_to_str(wifi_itwt_probe_status_t status) +{ + switch (status) { + case ITWT_PROBE_FAIL: return "itwt probe fail"; + case ITWT_PROBE_SUCCESS: return "itwt probe success"; + case ITWT_PROBE_TIMEOUT: return "itwt probe timeout"; + case ITWT_PROBE_STA_DISCONNECTED: return "Sta disconnected"; + default: return "Unknown status"; + } +} + +static void got_ip_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + xEventGroupClearBits(wifi_event_group, DISCONNECTED_BIT); + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + + /* setup a trigger-based announce individual TWT agreement. */ + esp_err_t err = ESP_OK; + int flow_id = 0; + wifi_config_t sta_cfg = { 0, }; + esp_wifi_get_config(WIFI_IF_STA, &sta_cfg); + if (sta_cfg.sta.phymode == WIFI_PHY_MODE_HE20) { + err = esp_wifi_sta_itwt_setup(TWT_REQUEST, trigger_enabled, flow_type_announced ? 0 : 1, + CONFIG_EXAMPLE_ITWT_MIN_WAKE_DURA, CONFIG_EXAMPLE_ITWT_WAKE_INVL_EXPN, + CONFIG_EXAMPLE_ITWT_WAKE_INVL_MANT, &flow_id); + if (err != ESP_OK) { + ESP_LOGE(TAG, "itwt setup failed, err:0x%x", err); + } + + } else { + ESP_LOGE(TAG, "Must be in 11ax mode to support itwt"); + } +} + +static void connect_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ESP_LOGI(TAG, "sta connect to %s", DEFAULT_SSID); + esp_wifi_connect(); +} + +static void disconnect_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ESP_LOGI(TAG, "sta disconnect, reconnect..."); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + esp_wifi_connect(); +} + +static void itwt_setup_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_sta_itwt_setup_t *setup = (wifi_event_sta_itwt_setup_t *) event_data; + if (setup->setup_cmd == TWT_ACCEPT) { + /* TWT Wake Interval = TWT Wake Interval Mantissa * (2 ^ TWT Wake Interval Exponent) */ + ESP_LOGI(TAG, "flow_id:%d, %s, %s, wake_dura:%d, wake_invl_e:%d, wake_invl_m:%d", setup->flow_id, + setup->trigger ? "trigger-enabled" : "non-trigger-enabled", setup->flow_type ? "unannounced" : "announced", + setup->min_wake_dura, setup->wake_invl_expn, setup->wake_invl_mant); + ESP_LOGI(TAG, "wake duration:%d us, service period:%d ms", setup->min_wake_dura << 8, setup->wake_invl_mant << setup->wake_invl_expn); + } else { + ESP_LOGE(TAG, "unexpected setup command:%d", setup->setup_cmd); + } +} + +static void itwt_teardown_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_sta_itwt_teardown_t *teardown = (wifi_event_sta_itwt_teardown_t *) event_data; + ESP_LOGI(TAG, "flow_id %d%s", teardown->flow_id, (teardown->flow_id == 8) ? "(all twt)" : ""); +} + +static void itwt_suspend_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_sta_itwt_suspend_t *suspend = (wifi_event_sta_itwt_suspend_t *) event_data; + ESP_LOGI(TAG, "status:%d, flow_id_bitmap:0x%x, actual_suspend_time_ms:[%lu %lu %lu %lu %lu %lu %lu %lu]", + suspend->status, suspend->flow_id_bitmap, + suspend->actual_suspend_time_ms[0], suspend->actual_suspend_time_ms[1], suspend->actual_suspend_time_ms[2], suspend->actual_suspend_time_ms[3], + suspend->actual_suspend_time_ms[4], suspend->actual_suspend_time_ms[5], suspend->actual_suspend_time_ms[6], suspend->actual_suspend_time_ms[7]); +} + +static void itwt_probe_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + wifi_event_sta_itwt_probe_t *probe = (wifi_event_sta_itwt_probe_t *) event_data; + ESP_LOGI(TAG, "status:%s, reason:0x%x", itwt_probe_status_to_str(probe->status), probe->reason); +} + +static void wifi_itwt(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + netif_sta = esp_netif_create_default_wifi_sta(); + assert(netif_sta); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_STA_START, + &connect_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_STA_DISCONNECTED, + &disconnect_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &got_ip_handler, + NULL, + NULL)); + /* itwt */ + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_ITWT_SETUP, + &itwt_setup_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_ITWT_TEARDOWN, + &itwt_teardown_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_ITWT_SUSPEND, + &itwt_suspend_handler, + NULL, + NULL)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + WIFI_EVENT_ITWT_PROBE, + &itwt_probe_handler, + NULL, + NULL)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = DEFAULT_SSID, + .password = DEFAULT_PWD, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + + esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20); + esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N | WIFI_PROTOCOL_11AX); + esp_wifi_set_ps(WIFI_PS_MIN_MODEM); + + ESP_ERROR_CHECK(esp_wifi_start()); + +#if CONFIG_ENABLE_WIFI_RX_STATS +#if CONFIG_ENABLE_WIFI_RX_MU_STATS + esp_wifi_enable_rx_statistics(true, true); +#else + esp_wifi_enable_rx_statistics(true, false); +#endif +#endif +#if CONFIG_ENABLE_WIFI_TX_STATS + esp_wifi_enable_tx_statistics(ESP_WIFI_ACI_VO, true); //VO, mgmt + esp_wifi_enable_tx_statistics(ESP_WIFI_ACI_BE, true); //BE, data +#endif + +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + + // TODO: WIFI-5150 +#if CONFIG_PM_ENABLE + io_toggle_pmu_internal_signal_map_to_io_init(); + io_toggle_gpio_init(); + + sleep_clock_system_retention_init(); + sleep_clock_modem_retention_init(); + sleep_peripheral_retention_init(); + sleep_modem_wifi_modem_state_init(); + + // Configure dynamic frequency scaling: + // maximum and minimum frequencies are set in sdkconfig, + // automatic light sleep is enabled if tickless idle support is enabled. + esp_pm_config_esp32c6_t pm_config = { + .max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ, + .min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ, +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = true +#endif + }; + ESP_ERROR_CHECK( esp_pm_configure(&pm_config) ); + ESP_ERROR_CHECK( ret ); + +#else + printf("\n =================================================\n"); + printf(" | Test WiFi 6 itwt |\n"); + printf(" =================================================\n\n"); + + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + repl_config.prompt = "itwt>"; + + // init console REPL environment +#if CONFIG_ESP_CONSOLE_UART + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); +#elif CONFIG_ESP_CONSOLE_USB_CDC + esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl)); +#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + esp_console_dev_usb_serial_jtag_config_t usbjtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl)); +#endif + + // start console REPL + ESP_ERROR_CHECK(esp_console_start_repl(repl)); +#endif + + //start wifi + wifi_itwt(); + // register commands + register_system(); + register_wifi_itwt(); + register_wifi_stats(); + +} diff --git a/examples/wifi/itwt/sdkconfig.defaults b/examples/wifi/itwt/sdkconfig.defaults new file mode 100644 index 0000000000..6c4793752f --- /dev/null +++ b/examples/wifi/itwt/sdkconfig.defaults @@ -0,0 +1,21 @@ +# Use lower CPU frequency +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=y +# Enable support for power management +CONFIG_PM_ENABLE=y +# Enable tickless idle mode +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +# Put related source code in IRAM +CONFIG_PM_SLP_IRAM_OPT=y +CONFIG_PM_RTOS_IDLE_OPT=y +# Disable all GPIO at light sleep +CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL=y +CONFIG_PM_SLP_DISABLE_GPIO=y +# Enable wifi sleep iram optimization +CONFIG_ESP_WIFI_SLP_IRAM_OPT=y + +CONFIG_ESP_GRATUITOUS_ARP=n +CONFIG_LWIP_ESP_GRATUITOUS_ARP=n + +# CONFIG_LWIP_ESP_GRATUITOUS_ARP is not set +# CONFIG_ESP_GRATUITOUS_ARP is not set + diff --git a/examples/wifi/itwt/sdkconfig.defaults.esp32c6 b/examples/wifi/itwt/sdkconfig.defaults.esp32c6 new file mode 100644 index 0000000000..d2b6e22382 --- /dev/null +++ b/examples/wifi/itwt/sdkconfig.defaults.esp32c6 @@ -0,0 +1,19 @@ +# +# ESP32C6-Specific +# +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=20 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=38 +CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=35 +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=20 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=20 +CONFIG_ESP32_WIFI_NVS_ENABLED=n + +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=30000 +CONFIG_LWIP_TCP_WND_DEFAULT=34000 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=64 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=64 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64 + +