Files
esp32-hacking/docs/USAGE.md

10 KiB

Usage Guide

Firmware Variants

This repo contains three firmware approaches for CSI data collection:

Firmware Directory Output Use Case
csi_recv_router get-started/csi_recv_router/ UDP to Pi Production - deployed on 3 sensors
csi_recv get-started/csi_recv/ Serial console Development/debugging
csi_send get-started/csi_send/ N/A (transmit only) Paired with csi_recv

csi_recv_router (Deployed Firmware)

How It Works

  1. ESP32 connects to WiFi router as a station
  2. Pings the gateway at 100 Hz (10ms interval)
  3. Each ping response triggers a CSI callback
  4. CSI data is formatted as CSV and sent via UDP

Data Flow

Router ←── ping ──→ ESP32 ──── UDP ──→ Pi (192.168.129.11:5500)
         (100 Hz)         (CSI_DATA)

CSI Data Format (ESP32)

CSI_DATA,<seq>,<mac>,<rssi>,<rate>,<sig_mode>,<mcs>,<cwb>,<smoothing>,
<not_sounding>,<aggregation>,<stbc>,<fec_coding>,<sgi>,<noise_floor>,
<ampdu_cnt>,<channel>,<secondary_channel>,<timestamp>,<ant>,<sig_len>,
<rx_state>,<len>,<first_word_invalid>,"[csi_values]"
Field Type Description
seq int Packet sequence number (increments from 0)
mac MAC Gateway MAC address
rssi int8 Received signal strength (dBm)
rate uint8 PHY rate
sig_mode uint8 0=non-HT, 1=HT, 3=VHT
mcs uint8 Modulation and coding scheme
cwb uint8 Channel bandwidth (0=20MHz, 1=40MHz)
smoothing uint8 Channel estimate smoothing
not_sounding uint8 Not sounding frame
aggregation uint8 AMPDU aggregation
stbc uint8 Space-time block coding
fec_coding uint8 FEC coding (0=BCC, 1=LDPC)
sgi uint8 Short guard interval
noise_floor int8 Noise floor (dBm)
ampdu_cnt uint8 AMPDU sub-frame count
channel uint8 Primary channel number
secondary_channel uint8 Secondary channel offset
timestamp uint32 Local timestamp (microseconds)
ant uint8 Antenna number
sig_len uint16 Signal length
rx_state uint32 RX state (0 = valid)
len int CSI data length (bytes)
first_word_invalid bool First 4 bytes invalid flag
csi_values int8[] Raw CSI I/Q values (interleaved)

CSI Values Interpretation

The csi_values array contains interleaved I/Q pairs per subcarrier:

[I0, Q0, I1, Q1, I2, Q2, ...]
  • Each pair represents one OFDM subcarrier
  • Amplitude: sqrt(I^2 + Q^2)
  • Phase: atan2(Q, I)
  • Typical length: 128 bytes (64 subcarriers x 2 values) for HT20

csi_recv vs csi_recv_router Comparison

Aspect csi_recv csi_recv_router
WiFi mode STA, no AP connection STA, connects to router
CSI source ESP-NOW packets from csi_send Ping responses from gateway
Output Serial (ets_printf) UDP socket
Requires Paired csi_send device WiFi router only
Promiscuous mode Yes No
MAC filtering Fixed 1a:00:00:00:00:00 Gateway BSSID
WiFi credentials Not needed Required (menuconfig)
CSI config (ESP32) All LTF types enabled LLTF only (router compat)
Gain compensation Logged to serial Applied to UDP data
Sequence counter From ESP-NOW payload (rx_id) Local counter (s_count)
Network Standalone (no router needed) Depends on router
Deployment Lab/testing Production

Key Differences in CSI Config (ESP32 target)

Setting csi_recv csi_recv_router
lltf_en true true
htltf_en true false
stbc_htltf2_en true false
manu_scale false true
shift false true

The router firmware uses only LLTF for broader router compatibility. The ESP-NOW firmware enables all LTF types since it controls both endpoints.

CSI Configuration Reference

sdkconfig.defaults

WiFi Settings

Config Value Description
CONFIG_ESP32_WIFI_CSI_ENABLED y Required. Enables CSI extraction from received frames
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED (empty) Disables TX aggregation. Aggregated frames combine CSI, reducing quality
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED (empty) Disables RX aggregation (csi_recv_router only)
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 128 Number of dynamic RX buffers. Higher = fewer drops at high CSI rates. Default is 32
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32 Number of dynamic TX buffers

Performance Settings

Config Value Description
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 240 Max CPU clock. Ensures CSI callback and UDP send complete within 10ms
CONFIG_COMPILER_OPTIMIZATION_PERF y -O2 optimization. Faster CSI processing
CONFIG_FREERTOS_HZ 1000 1ms tick resolution. Required for 100 Hz ping timer accuracy

System Settings

Config Value Description
CONFIG_ESP_TASK_WDT_TIMEOUT_S 30 Watchdog timeout. Extended from default 5s to avoid false resets during WiFi reconnect
CONFIG_ESP_CONSOLE_UART_BAUDRATE 921600 Fast serial for debug output
CONFIG_ESPTOOLPY_MONITOR_BAUD 921600 Monitor baud rate (must match console)

Kconfig.projbuild (Custom Settings)

Config Default Range Description
CONFIG_CSI_UDP_TARGET_IP 192.168.129.11 Any IPv4 Destination IP for UDP CSI packets
CONFIG_CSI_UDP_TARGET_PORT 5500 1024-65535 Destination UDP port

wifi_csi_config_t (Code-Level Settings)

ESP32 (Xtensa)

Field csi_recv_router Description
lltf_en true Enable Legacy Long Training Field. Most compatible with routers
htltf_en false HT-LTF. Only in HT (802.11n) frames. Disabled for router compat
stbc_htltf2_en false STBC HT-LTF2. Only with STBC encoding
ltf_merge_en true Merge multiple LTF into one CSI report
channel_filter_en true Apply channel estimation filter
manu_scale true Manual amplitude scaling
shift true Bit shift for value range

Compile-Time Defines (app_main.c)

Define Value Description
CONFIG_SEND_FREQUENCY 100 Ping rate in Hz (10ms interval)
CONFIG_FORCE_GAIN 0 Force AGC/FFT gain to baseline (disabled)
CONFIG_GAIN_CONTROL 1 (auto) Enable gain compensation (ESP32-S3, C3, C5, C6, C61)

Remote Management

Commands (esp-cmd)

Send commands to individual devices over UDP port 5501:

esp-cmd <host> STATUS        # Uptime, heap, RSSI, tx_power, rate, version
esp-cmd <host> IDENTIFY      # LED solid 5s
esp-cmd <host> RATE <10-100> # Set ping rate (NVS saved)
esp-cmd <host> POWER <2-20>  # Set TX power dBm (NVS saved)
esp-cmd <host> OTA <url>     # Trigger OTA update (prefer esp-ota)
esp-cmd <host> REBOOT        # Restart device

Fleet Management (esp-fleet)

Send commands to all sensors in parallel:

esp-fleet status             # Query all devices
esp-fleet identify           # Blink all LEDs
esp-fleet rate 50            # Set rate on all
esp-fleet reboot             # Reboot all
esp-fleet ota                # OTA update all (sequential)
esp-fleet ota /path/to/fw    # OTA with custom firmware

OTA Updates

Overview

Firmware updates are delivered over WiFi using ESP-IDF's esp_https_ota with a dual OTA partition layout. The device downloads a new binary from an HTTP server on the Pi, writes it to the inactive OTA slot, and reboots.

Partition Layout

Partition Offset Size Purpose
nvs 0x9000 16 KB NVS config storage
otadata 0xd000 8 KB OTA boot selection
phy_init 0xf000 4 KB PHY calibration
ota_0 0x10000 1920 KB App slot A
ota_1 0x1F0000 1920 KB App slot B

Using esp-ota

The esp-ota tool handles the full OTA workflow:

esp-ota amber-maple.local               # Default build path
esp-ota amber-maple.local -f custom.bin # Custom firmware
esp-ota amber-maple.local --no-wait     # Don't verify reboot

What it does:

  1. Verifies the device is alive (STATUS)
  2. Starts a temporary HTTP server on port 8070
  3. Sends OTA http://<pi-ip>:8070/<firmware>.bin to the device
  4. Waits for the device to download, flash, reboot
  5. Verifies the device responds with the new version

Rollback

The bootloader supports automatic rollback on failed updates:

  1. New firmware is written to the inactive OTA slot
  2. Device reboots into the new firmware in PENDING_VERIFY state
  3. If the firmware boots successfully (WiFi connects, mDNS starts, command listener ready), it marks itself as valid
  4. If the firmware crashes or hangs, the 30s watchdog triggers a reboot and the bootloader rolls back to the previous slot

First-Time Setup

The initial flash must be done via USB because switching from a single-app to a dual-OTA partition table requires erasing the entire flash. After the first USB flash, all subsequent updates can be done via OTA.

idf.py -p /dev/ttyUSB0 flash   # First time: USB required
esp-ota amber-maple.local       # All subsequent updates: OTA

Receiving CSI Data on the Pi

Listen on UDP port 5500:

# Quick test
nc -lu 5500

# Save to file
nc -lu 5500 > csi_capture.csv

# With socat (more reliable)
socat UDP-RECV:5500 STDOUT

Python Visualization Tools

get-started/tools/

pip install -r get-started/tools/requirements.txt
python get-started/tools/csi_data_read_parse.py

Requires serial connection (not UDP). Use for development with csi_recv firmware.

esp-radar/console_test/tools/

pip install -r esp-radar/console_test/tools/requirements.txt
python esp-radar/console_test/tools/esp_csi_tool.py
python esp-radar/console_test/tools/esp_csi_tool_gui.py

CLI and GUI tools for CSI analysis with presence detection algorithms.