StevenMHernandez / ESP32-CSI-Tool

Extract Channel State Information from WiFi-enabled ESP32 Microcontroller. Active and Passive modes available. (https://stevenmhernandez.github.io/ESP32-CSI-Tool/)
https://stevenmhernandez.github.io/ESP32-CSI-Tool/
MIT License
262 stars 72 forks source link

Why can the sta end also receive CSI? #70

Open cquptJiang opened 1 year ago

cquptJiang commented 1 year ago

I have read your code carefully, and I have a question that staion can receive CSI even though there is no code about sending data in AP. According to my guess, is it because the ap returns an ACK after receiving staion's packet, and staion uses this ACK to get CSI?? But I don't understand how can get CSI from ack. In addition, I used ESPNOW in staion to send data to AP, but I couldn't get CSI back. According to the official website, ESPNOW packets will return an ACK by default when received, What can I do to get CSI with ACK based on ESPNOW.

StevenMHernandez commented 1 year ago

I have never used ESPNOW. But I assume the ACK process is different from standard 802.11 protocols, thus it might not be able to receive CSI. Is the STA able to access CSI with ESPNOW? In this implementation, we have the connect which implies that we are using TCP (rather than UDP) which means that there is more back and forth communication (than UDP). Since ESPNOW is billed as a low-power communication method, they probably reduce the amount of frames sent.

cquptJiang commented 1 year ago

First of all, thank you for your reply. At the receiver, I can get CSI from each ESPNOW packet, but at the transmitter, I cannot get CSI directly from the ACK returned by the receiver. My goal is to obtain bi-directional CSI for localization. If using ACK doesn't work, I would like to see if I can detect this moment immediately after receiving a packet (with a subtlety of latency) and take some action, such as sending the packet back. The problem now is that I can easily get the packet arrival time from wifi_pkt_rx_ctrl_t, but I can't get some of my code blocks to start running at exactly that time (the callback wifi_csi_rx_cb is enabled for too long intervals). I want to get bidirectional CSI with a subtlety between sending and receiving. This problem has bothered me for a long time.

cquptJiang commented 1 year ago

By the way, the TCP based communication method you used is not suitable for our current positioning method due to its connection-oriented nature, because connection-oriented communication cannot implement frequency hopping with esp_wifi_set_channel.

cquptJiang commented 1 year ago

As a side note, I would like to know where the timestamp in wifi_pkt_rx_ctrl_t comes from. If I know the conditions under which I get the system time to get the timestamp, I can do other things under the same conditions. But I couldn't find the source code for the underlying principle.

StevenMHernandez commented 1 year ago

One of the greatest challenges with the ESP32 is that many of the binaries are closed-source. So I doubt that you will be able to access the timestamp in that way.

For your proposed system, is it important to have each frame trigger a reply in a back-and-forth way? I think it would be easier to just make each device transmit on their own schedule.

cquptJiang commented 1 year ago

I have considered the way you said before, but because the system time of the two ESP32 blocks is not synchronized, it is difficult for me to distinguish whether the interval between the two packets is within microseconds (the size of the interval time will directly seriously affect the error of ranging). And it is difficult to extract this pair of CSI when the amount of data is large. There may be other ways I haven't thought of yet, but I believe this one is possible on ESP32. Thanks again for your reply.

cquptJiang commented 1 year ago

I'm sorry to trouble you again, but I have a problem. There are two timestamps in csi_component.h, one is obtained with get_steady_clock_timestamp(), and the other is extracted from wifi_pkt_rx_ctrl_t. I want to know if these two timestamps are obtained from the same system time. And the difference between the two timestamps represents the delay of the callback function. Right?

StevenMHernandez commented 1 year ago

No worries. For me, time/clocks/dates/timezones are another important challenge facing many systems.

Previously, I found that d.rx_ctrl.timestamp (local_timestamp) was not very accurate. If I remember correctly, the times given were sometimes not in-order.

On the otherhand get_steady_clock_timestamp() (real_timestamp) returns the value of (https://en.cppreference.com/w/cpp/chrono/steady_clock) which is a:

"Monotonic clock. The time points of this clock cannot decrease as physical time moves forward and the time between ticks of this clock is constant."

Here is a plot from one of my experiments:

Screen Shot 2022-11-01 at 09 45 18

It might be nice to investigate into the specific reason why these timestamps are so different. If you are interested in spending some time researching into this, please share what you find. It also might be nice to add this timestamp information to the README.md somewhere. If you have any suggestions (big or small) for the documentation, please share a pull request. Thanks!

cquptJiang commented 1 year ago

I'm sorry that I don't know much about the generation principle of system time. I can only tell you some of my test results and conjections. Since my goal was to find the actual time interval (from the time the packet was received to the time the callback started working), as you showed, the difference between two timstamps is actually relatively stable (within a few tens), so I tested it again with get_system_clock_timestamp(). The value of system_time will be about 0.6ms larger than steady_time (excluding code running time). It's not clear to me which time difference best represents the actual time interval.

If these methods of obtaining timestamps are based on the same clock source (including local timestamps, do you think so?), then the reason why they are different is the delayed call of _wifi_csi_cb, because d.rx_ctrl.timestamp is generated and stored in the struct after the packet is received. However, get_steady_clock_timestamp does not get the time until the callback has worked (there is a delay). These timestamps and intervals will change every time the device is restarted, possibly due to the frequency offset of the ESP32 internal clock.