iTWT (Individual Target Wake Time) support - #5960
Conversation
While Wi-Fi is active, ESP-IDF blocks wifi_clock_disable calls from the blob: https://github.com/espressif/esp-idf/blob/release/v5.5/components/esp_hw_support/modem_clock.c#L77-L85 This is necessary because otherwise hardware-provided timers such as TWT do not fire.
The additional bindings PR got merged so this should become buildable by changing the git revision of the esp-wifi-sys dependencies |
dde6d48 to
eb5d2d3
Compare
Add individual Target Wake Time (iTWT) support for Wi-Fi 6 (802.11ax) chips (ESP32-C5, C6, C61), enabling significant power savings for periodic traffic patterns. Examples: - embassy_twt: comprehensively demonstrates usage of iTWT APIs - embassy_twt_udp: voice-over-WiFi (160B UDP on 20ms TWT wakeup)
eb5d2d3 to
f1dbfa1
Compare
|
This is an exciting addition - however the udp example doesn't seem to work for me - maybe "I'm holding it wrong" I see And nothing more - nothing is received. But the setup looks good, doesn't it? |
|
Oh no! Here is what I get with a Fritz!Box 7682 and my ESP32-C6: and so on I can think of a few possibilities:
Since you are also using a C6 it shouldn't be a hardware difference, but I originally saw the same problem and it was fixed by 734971d. |
And move twt-specific stuff outof the general wifi module
|
Did you configure anything special on your Fritz!Box 7682 ? Are you using WPA2+WPA3 (I enabled WPA2 only - not sure if that might make a difference) (Ah - there was a typo - mine is a 5590 not 5090) |
|
When changing |
|
I am using WPA2+WPA3, and all the settings on default as far as I can see. But in theory, the fact that you are getting a positive setup response should already be a definitive proof that your Fritz!Box can do iTWT and accepts your parameters. Also in my tests esp-hal doesn't even do WPA3 so that's another reason why it shouldn't matter. If you're hanging on the call to
I'm very confused because none of those sound plausible to me.
By receive you mean receiving the UDP packets on another host, or observing the wakeup events in the logs? Maybe if you listen in monitor mode you can see what's really going on (maybe deauthentication, maybe AP is tearing down the TWT agreement, etc) |
|
Yes for now we can't support WPA3 and I agree that accepting the iTWT setup should tell it should work 🤷♂️
Yes - seeing the packets getting received on the other host |
|
Given that I'm not able to reproduce the issue, I have no idea how to proceed here. Do you have the same issue with esp-idf? |
|
Maybe the esp-idf example also doesn't work correctly - I'm not sure how it should look like if it's working, can you paste your output of that example here? I asked a colleague to test the PR but also without luck - I'm still trying to check / fix my setup but the esp-idf example output might be helpful for me |
|
Right, the IDF example does not post events or send anything out of the box. Here are my changes that makes it similar to the udp example here: Diffdiff --git a/examples/wifi/itwt/main/itwt_main.c b/examples/wifi/itwt/main/itwt_main.c
index ae4914067cb..ee417d87eb8 100644
--- a/examples/wifi/itwt/main/itwt_main.c
+++ b/examples/wifi/itwt/main/itwt_main.c
@@ -18,6 +18,9 @@
start esp32c6 and when it connected to AP it will setup itwt.
*/
#include <netdb.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
@@ -37,6 +40,10 @@
*******************************************************/
static const char *TAG = "itwt";
+/* UDP target for TWT wakeup packets */
+#define TWT_WAKEUP_UDP_TARGET_IP "255.255.255.255"
+#define TWT_WAKEUP_UDP_TARGET_PORT 12345
+
/*******************************************************
* Structures
*******************************************************/
@@ -72,6 +79,10 @@ const int CONNECTED_BIT = BIT0;
const int DISCONNECTED_BIT = BIT1;
EventGroupHandle_t wifi_event_group;
+static int twt_udp_sock = -1;
+static struct sockaddr_in twt_udp_dest;
+static uint32_t twt_wakeup_counter = 0;
+
/*******************************************************
* Function Declarations
*******************************************************/
@@ -112,12 +123,44 @@ static const char *itwt_probe_status_to_str(wifi_itwt_probe_status_t status)
}
}
+static void twt_wakeup_handler(void *arg, esp_event_base_t event_base,
+ int32_t event_id, void *event_data)
+{
+return;
+ if (twt_udp_sock < 0) {
+ return;
+ }
+ twt_wakeup_counter++;
+ int ret = sendto(twt_udp_sock, &twt_wakeup_counter, sizeof(twt_wakeup_counter), 0,
+ (struct sockaddr *)&twt_udp_dest, sizeof(twt_udp_dest));
+ if (ret < 0) {
+ ESP_LOGD(TAG, "<TWT_WAKEUP> UDP send failed: errno %d", errno);
+ } else {
+ ESP_LOGI(TAG, "<TWT_WAKEUP> sent UDP pkt #%"PRIu32, twt_wakeup_counter);
+ }
+}
+
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);
+ /* Create UDP socket for TWT wakeup packets */
+ if (twt_udp_sock < 0) {
+ twt_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (twt_udp_sock < 0) {
+ ESP_LOGE(TAG, "Failed to create UDP socket: errno %d", errno);
+ } else {
+ memset(&twt_udp_dest, 0, sizeof(twt_udp_dest));
+ twt_udp_dest.sin_family = AF_INET;
+ twt_udp_dest.sin_port = htons(TWT_WAKEUP_UDP_TARGET_PORT);
+ inet_aton(TWT_WAKEUP_UDP_TARGET_IP, &twt_udp_dest.sin_addr);
+ ESP_LOGI(TAG, "TWT wakeup UDP socket created, target %s:%d",
+ TWT_WAKEUP_UDP_TARGET_IP, TWT_WAKEUP_UDP_TARGET_PORT);
+ }
+ }
+
/* setup a trigger-based announce individual TWT agreement. */
wifi_phy_mode_t phymode;
wifi_config_t sta_cfg = { 0, };
@@ -260,6 +303,11 @@ static void wifi_itwt(void)
&itwt_probe_handler,
NULL,
NULL));
+ ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
+ WIFI_EVENT_TWT_WAKEUP,
+ &twt_wakeup_handler,
+ NULL,
+ NULL));
wifi_config_t wifi_config = {
.sta = {
@@ -271,7 +319,7 @@ static void wifi_itwt(void)
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
wifi_twt_config_t wifi_twt_config = {
- .post_wakeup_event = false,
+ .post_wakeup_event = true,
.twt_enable_keep_alive = keep_alive_enabled,
};
ESP_ERROR_CHECK(esp_wifi_sta_twt_config(&wifi_twt_config)); |
|
Ok this at least indicates something bad I guess |
|
It's confusing that IDF gives you a timeout during setup when you were getting a success response before. Are you running the same wifi blob in both cases? |
|
Yes - it's run from the same commit I took the blobs from Maybe I should retry the Rust example since my router did an auto-update since then - but I don't expect much to have changed |
|
Aha - so maybe the update did something - now I also get an error for the Rust example: |
|
Interestingly - at least with new firmware - I see that with "WPA2" only enabled, by default PMF is disabled, enabling it doesn't help. "WPA2+WPA3" enabled PMF automatically (and there is no option to disable it anymore) I also tried a few other config changes which made kind of sense but none of them made a difference. At least ESP-IDF and the Rust implementation show the same behavior |
|
This is strange, your Fritz!Box claims to support WiFi 6, so the iTWT setup request should definitely not go unanswered. But if you're getting the same issue with IDF then it looks like at least it's not caused by any problem with the code in this PR. 🤷 |
Submission Checklist 📝
cargo xtask fmt-packagescommand to ensure that all changed code is formatted correctly.skip-changelogormanual-changeloglabel as appropriate.Extra:
Pull Request Details 📖
Description
Add individual Target Wake Time (iTWT) support for Wi-Fi 6 (802.11ax) chips (ESP32-C5, C6, C61), enabling significant power savings for periodic traffic patterns. After negotiating iTWT with the AP, the entire model will go to sleep and only wake up during the negotiated time windows.
Depends on esp-rs/esp-wifi-sys#505.
Testing
Tested on ESP32-C6.
Measured power consumption in an example that sends a 160 byte UDP packet every 20ms (simulating a VoIP use case):
Changelog
esp-radio
wifi::twtmodule with iTWT configuration types and constantsWifiControllermethods for iTWT setup, teardown, suspend, probing, and configuration (Wi-Fi 6 chips only)TwtFull,TwtSetupTimeout,TwtSetupTxFail,TwtSetupRejected, andTwtSetupFailedvariants added toWifiErrorwifi_clock_disableOS adapter callback now keeps clocks on during modem-sleep, matching ESP-IDF behavioresp-phy