espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.34k stars 7.2k forks source link

ESP32-C6 not reporting L-LTF data in WiFi CSI callback and wrong subcarrier order for HT-LTF (IDFGH-13358) #14271

Open benjamin-kl opened 1 month ago

benjamin-kl commented 1 month ago

Answers checklist.

IDF version.

v5.3

Espressif SoC revision.

ESP32-C6

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32-C6-DevKitC-1

Power Supply used.

USB

What is the expected behavior?

Scenario: receiving a csi_rx_cb callback for a HT20 PPDU. Expected behavior: Receive 256 bytes in the wifi_csi_info_t buffer, which is 64 (subcarriers) 2 bytes (Im/Re) L-LTF CSI data + 64 (subcarriers) 2 bytes (Im/Re) HT-LTF CSI data. The order of the subcarriers is 0~31,-32~-1 in both cases, as described in the WiFi API guide (https://docs.espressif.com/projects/esp-idf/en/stable/esp32c6/api-guides/wifi.html#wi-fi-channel-state-information)

What is the actual behavior?

Actual behavior (esp32s3 DevKitC-1U): same as expected behavior

Actual behavior (esp32): same as expected behavior

Actual behavior (esp32c6 DevKitC-1): Receive 128 bytes in the callback. L-LTF data is missing. The order of the subcarriers is different from what is described in the WiFi API guide (null subcarriers/guard band in front?)

Steps to reproduce.

Minimal reproducible example (receive):

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include <sstream>

void _wifi_csi_cb(void *ctx, wifi_csi_info_t *csi_i) {
    std::stringstream ss;
    ss << "num values: " << csi_i->len << " [ ";
    for (int i = 0; i < csi_i->len; i++) {
        ss << static_cast<int>(csi_i->buf[i]) << " ";
    }
    ss << "]\n";
    printf(ss.str().c_str());
    fflush(stdout);
}

extern "C" void app_main(void) {
    ESP_ERROR_CHECK(nvs_flash_init());
    wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&wifi_cfg));
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT20));
    ESP_ERROR_CHECK(esp_wifi_start());
    const wifi_promiscuous_filter_t filt = {
            .filter_mask = WIFI_PROMIS_FILTER_MASK_DATA
    };
    ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
    ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filt));
    ESP_ERROR_CHECK(esp_wifi_set_channel(13, WIFI_SECOND_CHAN_NONE));
    ESP_ERROR_CHECK(esp_wifi_set_csi(true));
#ifdef CONFIG_SOC_WIFI_HE_SUPPORT
    wifi_csi_config_t configuration_csi = {
        .enable = 1,
        .acquire_csi_legacy = 1, //should give L-LTF CSI, but doesn't
        .acquire_csi_ht20 = 1, //should give HT-LTF CSI, but gives wrong subcarrier order
        .acquire_csi_ht40 = 0,
        .acquire_csi_su = 0,
        .acquire_csi_mu = 0,
        .acquire_csi_dcm = 0,
        .acquire_csi_beamformed = 0,
        .acquire_csi_he_stbc = 0,
        .val_scale_cfg = 0,
    };
#else
    wifi_csi_config_t configuration_csi = {
        .lltf_en = 1, //gives L-LTF CSI
        .htltf_en = 1, //gives HT-LTF CSI
        .stbc_htltf2_en = 0,
        .ltf_merge_en = 0,
        .channel_filter_en = 0,
        .manu_scale = 0,
        .shift = 0,
    };
#endif
    ESP_ERROR_CHECK(esp_wifi_set_csi_config(&configuration_csi));
    ESP_ERROR_CHECK(esp_wifi_set_csi_rx_cb(&_wifi_csi_cb, NULL));

    while(true) {
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

Debug Logs.

Example CSI from esp32c6 (with code above):
num values: 128 [ 0 0 0 0 0 0 0 0 -1 -24 0 -24 2 -24 4 -23 6 -25 7 -24 9 -24 10 -23 11 -23 12 -23 12 -21 13 -22 11 -22 11 -21 11 -21 10 -20 10 -20 10 -22 9 -21 9 -22 9 -22 9 -23 9 -23 8 -23 9 -25 9 -26 9 -25 9 -26 0 0 10 -25 9 -26 9 -25 9 -26 9 -25 105 29 59 -99 12 69 -35 10 -67 -83 79 94 -75 84 114 33 -3 -123 39 102 94 -2 -32 95 67 -105 109 99 -13 -87 25 -57 70 -16 52 -39 -25 118 83 127 -128 109 -78 54 83 -77 49 37 -93 22 -58 -116 ]

Example CSI from esp32s3 (with code above):
num values: 256 [ 0 0 -11 -6 -11 -9 -12 -8 -10 -8 -11 -7 -11 -6 -11 -6 -11 -5 -12 -5 -11 -5 -12 -4 -12 -4 -12 -4 -13 -3 -13 -3 -13 -3 -13 -3 -14 -3 -14 -4 -13 -4 -13 -5 -13 -5 -12 -6 -12 -6 -11 -7 -11 -7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -7 -10 -6 -10 -6 -11 -6 -11 -5 -11 -5 -12 -5 -12 -5 -12 -5 -11 -5 -11 -5 -11 -5 -11 -5 -11 -5 -10 -5 -10 -6 -10 -7 -10 -7 -10 -8 -10 -8 -9 -9 -9 -9 -9 -10 -8 -10 -8 -9 -8 -7 -9 0 0 -51 -26 -51 -26 -45 -19 -52 -24 -48 -17 -47 -18 -49 -16 -47 -16 -51 -13 -51 -13 -49 -9 -51 -6 -50 -5 -51 -3 -56 -6 -51 -1 -56 -7 -54 -3 -58 -10 -58 -11 -55 -12 -54 -15 -53 -19 -49 -18 -48 -20 -44 -21 -42 -29 -37 -29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -41 -26 -38 -26 -36 -31 -35 -31 -37 -39 -33 -33 -32 -40 -33 -37 -33 -42 -28 -44 -31 -43 -26 -43 -27 -40 -28 -40 -28 -39 -32 -37 -30 -32 -33 -39 -33 -30 -34 -33 -37 -28 -40 -28 -40 -30 -43 -30 -46 -31 -46 -25 -45 -22 -46 -19 ]

More Information.

No response

QingzhaoYin commented 2 weeks ago

@benjamin-kl Actually, the CSI of the ESP32C6 differs from that of the ESP32C3. In the ESP32C6, the HT-LTF overrides the L-LTF, with a subcarrier index range of (-32 to -1, 0 to 32) and an effective subcarrier index range of (-28 to -1, 1 to 28). The current ESP32C6 documentation contains inaccuracies, but we will update it promptly.

benjamin-kl commented 1 week ago

@QingzhaoYin Thanks for taking a look at this. However I think this is not only an issue with the documentation, but there is a bug in the software.

If the subcarrier order is as you said it is, I would expect to see zero-values at the beginning and zero-values at the end of the CSI data. If you take a look at the CSI I provided (recorded with C6), the CSI values for the first four subcarriers are indeed zero. However, the last three are not.

Even worse, the C6 seems to occasionally report completely wrong CSI data. Three examples:

num values: 128 [0, 0, 0, 0, 0, 0, 0, 0, -3, 1, 0, 0, 8, -4, 7, -6, 4, -10, 2, -15, 0, -20, -1, -25, -1, -29, 0, -32, -1, -34, -1, -35, -1, -35, -1, -33, -2, -30, -1, -23, 0, -17, -1, -11, -2, -5, -2, 3, 0, 14, 1, 23, -2, 31, -5, 40, -6, 47, -7, 52, -7, 57, -4, 58, 0, 0, -5, 47, -5, 42, -5, 35, -5, 42, -5, 35, -1, -1, -1, 0, -4, 0, -2, 2, -1, 2, -1, 2, -2, 2, -2, 4, -3, 2, -3, 3, 1, 0, 4, -1, 2, 1, 0, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 3, 5, 2, 6, 3, -1, 13, 7, 0, 0, 0, 0, 0, 0]

num values: 128 [0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 2, 1, 10, 0, 6, -4, 2, -10, 0, -14, 3, -17, 3, -21, 3, -25, 4, -28, 6, -30, 8, -32, 8, -32, 6, -31, 3, -28, 1, -23, 2, -17, 3, -12, 1, -5, -1, 4, -4, 13, -7, 22, -11, 30, -13, 37, -15, 42, -17, 46, -20, 48, -22, 47, 0, 0, -22, 40, -19, 35, -17, 27, -19, 35, -17, 27, -25, -19, -24, -18, -25, -19, -24, -18, 91, -5, 83, -89, 36, -24, -17, -76, -71, -24, 59, 33, 114, -80, -83, -15, 113, 14, -50, -43, -44, -85, 2, 114, -41, 46, -54, 48, -46, -2, -15, -94, -53, 3, 60, 5, -127, -62, 46, -66, -103, -82, 66, 0]

num values: 128 [-119, 48, -65, 117, 118, 32, -27, -85, -56, 124, 41, 72, -90, -60, -8, -84, 113, 39, 45, -99, -11, -101, -95, 47, -122, 27, 90, -98, -31, -13, -73, -12, 69, -22, 63, 78, -93, 28, 81, 19, -33, 94, -12, -26, 36, -126, -23, 5, 59, -70, 88, 122, -91, 75, 20, 122, 42, 23, -45, 12, 63, 22, 59, -71, -44, 6, 83, 71, 63, 63, 66, 76, -106, 104, -106, 111, -53, -81, 69, 66, 57, -119, 102, 8, 0, 81, 87, -4, 69, 1, -86, -58, 99, -73, 57, 14, -73, 90, -94, 84, 82, -41, 91, 47, -19, -61, 16, -94, -42, -82, -94, -103, -50, 59, 47, -105, -66, -57, 19, 107, -22, -58, -66, -115, 0, -46, -81, -29]

All three samples were received from the same transmitter during a very short timeframe.

The first sample is as we expect. The second sample does not have zero-values at the end The third sample is completely malformed

QingzhaoYin commented 1 week ago

@benjamin-kl Actually, invalid CSI data may be read in wifi_csi_rx_cb . The "rx_channel_estimate_info_vld" field in wifi_pkt_rx_ctrl_t indicates whether the channel information is valid. If you do not use this bit as a filter, it's possible to get the data as you provided.