espressif / esp-csi

Applications based on Wi-Fi CSI (Channel state information), such as indoor positioning, human detection
Apache License 2.0
706 stars 111 forks source link

Cannot add a short data payload to the esp_now_send function (AEGHB-776) #198

Closed Yaqi3707 closed 3 months ago

Yaqi3707 commented 3 months ago

Greetings ESP32 developers,

I have been learning this amazing tool and successfully run the _esp-csi/examples/get-started/csi_send & csirecv, and esp-idf/examples/wifi/espnow functions on my two ESP32s.

However, I want to add a short payload (8 bytes) for basic communication between my two ESP32s so I revised the _csi_send/appmain.c :

static const uint8_t data[8] = {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc};
esp_err_t ret = esp_now_send(peer.peer_addr, data, sizeof(data));

And I used the _wifi_promoscuous_rxcb from the receiver to capture all the incoming packets but got no packets containing these 8-byte data.

(While I attempted to set up the MAC address for capturing the packets I need, the toolkit crashed after I flashed it.) recv2.txt

I did this in _esp-idf/examples/wifi/espnow/main.espnow_examplemain.c but still received no packets containing the data.

memcpy(buf->payload, data, sizeof(data));
 /* Fill all remaining bytes after the data with random values */
esp_fill_random(buf->payload, send_param->len - sizeof(example_espnow_data_t));
  1. My first question is how I should implement this function.

To further diagnose this issue, I used Wireshark to observe the traffic with my PAU05 wireless dongle in monitor mode. The weird thing is I cannot see any packets when using _csisend but some packets when using espnow. Nevertheless, the captured packets still do not contain the 8-byte data.

  1. My second question is why the packets are invisible through _csisend but visible through espnow in Wireshark monitor mode. Why the captured packets still do not cotain the data I added from sender?

My eventual goal is to continuously transfer the frames with the data payload (less than 250 bytes) between two ESP32s while both sides can capture the CSI from the receiving packets simultaneously. My project is time-sensitive so I want to use frames in the second layer to reduce the delay as much as possible.

These questions have confused me for a while. I sincerely appreciate any comments and guidance on them. Many thanks in advance.

MacChu0315-Espressif commented 3 months ago

Hi i would like to first ask which version of idf you are using? Because I didn't find the definition of wifi_promiscuous_rx_cb.

Yaqi3707 commented 3 months ago

Hi, my idf version is: ESP-IDF v5.4-dev-1873-g41dd1a351b.

My rpi4 is the latest OS: Linux raspberrypi 6.6.31+rpt-rpi-v8 #1 SMP PREEMPT Debian 1:6.6.31-1+rpt1 (2024)-05-29) aarch64 GNU/Linux

The _wifi_promiscuous_rxcb is the function I searched online to receive the packets in promiscuous mode. I think it is similar to the _esp_wifi_set_promiscuous_rxcb function in the _csi_recv/main/appmain.c.

    ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
    // ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(g_wifi_radar_config->wifi_sniffer_cb));

I attempted to temporarily comment out the CSI capturing function _wifi_csi_rxcb and leverage the promiscuous mode to capture any packets from the sender and check whether it contains the data I am looking for.

MacChu0315-Espressif commented 3 months ago

Please add the following code to the wifi_csi_rx_cb function to retrieve the payload:

ESP_LOG_BUFFER_HEXDUMP(TAG, info->payload, info->payload_len, ESP_LOG_INFO);

This will allow you to log the payload data. However, payload_len should contain the length of the header, which needs to be subtracted when printing. If there is a connection, the header length is 28, and if there is no connection, it is 24.

Yaqi3707 commented 3 months ago

Thank you very much for your quick reply regarding this issue. However, I noticed that the payload data doesn't match the frame structure described in the ESP documentation.

The payload contains my data, which is [cc, cc, cc, cc, cc, cc, cc, cc]. However, it appears at index 15 instead of 24 in my connectionless (wireless) case. Additionally, the first 15 bytes do not correspond to the MAC address of either of my two ESP devices. What do those bytes represent? And what do the bytes following my data signify?

Screenshot 2024-08-15 215146

Thank you in advance for your kind explanation.

MacChu0315-Espressif commented 3 months ago
  1. If you want to obtain the MAC addresses of the sender and receiver from the header, you can add the following code to the receiver:
#include "esp_wifi_types.h"
#define IEEE80211_ADDR_LEN 6

typedef struct {
    uint8_t i_fc[2];
    uint8_t i_dur[2];
    uint8_t i_addr1[IEEE80211_ADDR_LEN];
    uint8_t i_addr2[IEEE80211_ADDR_LEN];
    uint8_t i_addr3[IEEE80211_ADDR_LEN];
    uint8_t i_seq[2];
    /* Followed by 'u8 addr4[6];' if ToDS and FromDS are set in the data frame */
} ieee80211_hdr_t;

Then, in the wifi_csi_rx_cb function, add the following:

ESP_LOG_BUFFER_HEXDUMP(TAG, info->payload, info->payload_len, ESP_LOG_INFO);

ieee80211_hdr_t *rx_hdr = (ieee80211_hdr_t *)info->hdr;

printf("rx_hdr->i_fc    = ");
for (int i = 0; i < 2; i++) {
    printf("0x%02x ", rx_hdr->i_fc[i]);
}
printf("\n");

printf("rx_hdr->i_dur   = ");
for (int i = 0; i < 2; i++) {
    printf("0x%02x ", rx_hdr->i_dur[i]);
}
printf("\n");

printf("rx_hdr->i_addr1 = " MACSTR " \n", MAC2STR(rx_hdr->i_addr1));
printf("rx_hdr->i_addr2 = " MACSTR " \n", MAC2STR(rx_hdr->i_addr2));
printf("rx_hdr->i_addr3 = " MACSTR " \n", MAC2STR(rx_hdr->i_addr3));

printf("rx_hdr->i_seq   = ");
for (int i = 0; i < 2; i++) {
    printf("0x%02x ", rx_hdr->i_seq[i]);
}
printf("\n");
  1. The bytes following your data (the last 24 bytes) represent the header, so in your case, the line ESP_LOG_BUFFER_HEXDUMP(TAG, info->payload, info->payload_len, ESP_LOG_INFO); should be modified to:
ESP_LOG_BUFFER_HEXDUMP(TAG, info->payload, info->payload_len - 24, ESP_LOG_INFO);
Yaqi3707 commented 3 months ago

Thanks again for your helpful response. I have my last two questions

  1. I realized the transmitted sequence number is random. I understant this is due to the auto-random function from the Wi-Fi driver. Is there any way to disable this function so that I can manually assign the sequence number starting from 1 and have it auto-increment consecutively? I would like to handle it manually since it helps me to track the corresponding packets between the sender and receiver and filter out the dropped packets during the wireless transmission.

Screenshot 2024-08-17 001111

  1. I reviewed the _esp_radar/consoletest example, and I saw that it stores the CSI data into a local CSV file. I browsed through the code but didn't find a clear indication of how it was done. The straightforward approach is to open a CSV file and write every received CSI data in it but I am concerned about whether this would impact the performance of packets capture and CSI data collection? I am currently doing this idf.py monitor | tee output.csv but it contains the system output as well. If I want to store only the CSI data into a local CSV file while using the Python Print GUI, should I write this similar function into the csi_data_read_parse.py?

I sincerely appreicate your assistance with these questions!

MacChu0315-Espressif commented 3 months ago
  1. Why not put the number of packets sent in the payload?
  2. When using the console_test routine, we recommend using console_test/tools/esp_csi_tool.py for CSI data display and CSV storage. If you want to modify the saved content, you can directly modify the code in it.
Yaqi3707 commented 3 months ago

I was previously advised to write the seq num into the payload, but I wonder if there is an effective way to directly modify the original seq num in the frame header. This has confused me for a long period without finding a good solution.

Anyway, thank you again for the helpful information. I am closing this one.