a friend of mine and I managed to enable extraction of CSI (Channel State Information) on Mediatek based Wi-Fi chipsets. The project can be found here: https://github.com/MtkWifiRev/MtkCSIdump
No firmware modifications are necessary, its purely done by some patches in mt76. The driver changes are based on this patch set. We provide squashfs images for two mt7981 based routers which we tested:
OpenWRT One
Xiaomi Mi AX3000T
It should work for other chipsets as well, but Wi-Fi 7 based cards might need a different interpretation of the CSI data.
In our repo you can find:
A tool to run on the OpenWRT based router to start collection of the CSI data
A Python based GUI which can be used to receive the CSI data via UDP from the OpenWRT router.
I hope this is interesting and helpful to some people.
Update:
Here is a link to a recording from Nullcon this year were we presented this (sorry for the bad audio). And a link to the slides.
Not all channels return noise floor from what I can see.
root@OpenWrt:~# iw dev phy0-ap0 survey dump
Survey data from phy0-ap0
frequency: 2412 MHz
noise: -91 dBm
channel active time: 48 ms
channel busy time: 11 ms
channel receive time: 8 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2417 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2422 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2427 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2432 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2437 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2442 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2447 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2452 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2457 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2462 MHz [in use]
noise: -90 dBm
channel active time: 234027155 ms
channel busy time: 74846531 ms
channel receive time: 72670783 ms
channel BSS receive time: 12505 ms
channel transmit time: 916557 ms
Survey data from phy0-ap0
frequency: 2467 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
Survey data from phy0-ap0
frequency: 2472 MHz
channel active time: 0 ms
channel busy time: 0 ms
channel receive time: 0 ms
channel BSS receive time: 0 ms
channel transmit time: 0 ms
We can try, but I think the question is always how to maintain it. And I can't do it in the long run.
We do have another project were we enabled raw I/Q capture on a specific Android chipset, see MtkICAPtool. We are trying to get this working on other chipsets, but no luck so far. But I don't think this is the level of data you are looking for, right?
All devices I have seen that support this feature have an Atheros chip. This feature is supported by the ath9k/ath10k and ath11k drivers. Here is the interface documentation. It would be ideal if Mediatek had the same interface.
There are even more details in mt_wifi. We already tried to enable this but it did not work so far, we will keep trying to figure out how to get this one enabled.
Took a quick look at the driver code, and it's completely crazy. TLVs from the firmware are parsed using a packed struct:
This is unnecessarily fragile and unmaintainable. Extending it to more chipsets is meaningless. Why not start mapping the TLVs? I bet they are the same across different chipsets and firmwares, but possibly with variable lengths and order