Introduction
The ESP32-C5 is Espressif's first RISC-V microcontroller with dual-band WiFi 6 (802.11ax) support. This guide demonstrates advanced GDB debugging techniques for WiFi monitor mode, including real-time 802.11 frame analysis, runtime threshold tuning, and WiFi collapse detection.
New in This Edition: WiFi Monitor Mode
- 802.11 Frame Capture: Debug WiFi at the packet level
- Runtime Threshold Tuning: Adjust detection parameters without rebuilding
- Duration Analysis: Analyze PHY rates, NAV, and expected vs actual duration
- WiFi Collapse Detection: Real-time network degradation analysis
- GDB Integration: Combine C code performance with GDB flexibility
WiFi Monitor Mode Debugging
The WiFi monitor mode implementation in the feature/wifi-monitor-mode branch provides real-time 802.11 frame capture and analysis capabilities. This section shows how to debug WiFi at the packet level using GDB.
Branch Setup
cd ~/Code/esp32/esp32-iperf
git checkout feature/wifi-monitor-mode
git pull
# Build and flash
idf.py build
idf.py -p /dev/ttyACM0 flash
Component Architecture
The WiFi monitor is implemented as a reusable ESP-IDF component:
esp32-iperf/
├── components/
│ └── wifi_monitor/
│ ├── wifi_monitor.c # Frame capture & analysis
│ ├── wifi_monitor.h # API definitions
│ └── CMakeLists.txt
└── main/
└── main.c # Monitor mode integration
Starting a WiFi Monitor Debug Session
# Terminal 1: Start OpenOCD
cd ~/Code/esp32/esp32-iperf
idf.py openocd
# Terminal 2: Start GDB
idf.py gdb
.gdbinit file with WiFi debugging commands. Enable it once:
mkdir -p ~/.config/gdb
echo "set auto-load safe-path /" >> ~/.config/gdb/gdbinit
802.11 Frame Analysis
GDB can inspect captured WiFi frames in real-time, showing detailed 802.11 MAC header information.
Frame Callback Breakpoint
(gdb) break monitor_frame_callback
Breakpoint 1 at 0x4200e926
(gdb) continue
# When frame is captured:
Thread 6 "main" hit Breakpoint 1, monitor_frame_callback (
frame=0x4082a6e4,
payload=0x40833c34,
len=1268
) at main.c:212
Displaying Frame Information
Use the show_frame_full command (auto-loaded from .gdbinit):
(gdb) show_frame_full
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Frame: DATA
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
RSSI: -45 dBm
Channel: 36
Retry: no
PHY Rate: 433500 Kbps (433.5 Mbps)
Mode: MCS 8, BW 80MHz, SGI Yes
Byte Count: 1500 bytes
Expected Duration: 71 us (27 tx + 44 overhead)
Actual Duration (NAV): 68 us
Difference: -3 us shorter
Dest: ff:ff:ff:ff:ff:ff
Source: e0:46:ee:07:df:01
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Frame Structure Breakdown
| Field | GDB Access | Description |
|---|---|---|
| Frame Type | frame->type |
0=Management, 1=Control, 2=Data |
| Subtype | frame->subtype |
Specific frame subtype (e.g., BEACON, ACK, DATA) |
| NAV | frame->duration_id |
Network Allocation Vector (microseconds) |
| Retry Bit | frame->retry |
true if frame is a retransmission |
| RSSI | frame->rssi |
Received Signal Strength (dBm) |
| PHY Rate | frame->phy_rate_kbps |
Physical layer rate (Kbps) |
| MAC Addresses | frame->addr1/2/3 |
Destination, Source, BSSID |
Conditional Breakpoints for WiFi Analysis
Break on High NAV (Potential Collapse)
(gdb) break monitor_frame_callback if frame->duration_id > 10000
Breakpoint 2 at 0x4200e926
(gdb) commands 2
>printf "⚠ HIGH NAV: %u us\n", frame->duration_id
>show_duration
>continue
>end
(gdb) continue
Break on Retry Frames (Collisions)
(gdb) break monitor_frame_callback if frame->retry == 1
Breakpoint 3 at 0x4200e926
(gdb) continue
Break on Collision Indicators
# Retry + High NAV = Strong collision indicator
(gdb) break monitor_frame_callback if frame->retry && frame->duration_id > 5000
Breakpoint 4 at 0x4200e926
(gdb) commands 4
>printf "🚨 COLLISION DETECTED!\n"
>show_frame_full
>end
(gdb) continue
Runtime Threshold Tuning
One of the most powerful features is the ability to adjust WiFi detection thresholds at runtime via GDB without rebuilding firmware.
Tunable Thresholds
The WiFi monitor exposes 9 threshold variables that control detection sensitivity:
| Variable | Default | Purpose |
|---|---|---|
threshold_high_nav_us |
5000 | NAV above this = "high" |
threshold_duration_mismatch_us |
10000 | Log mismatches when NAV exceeds this |
threshold_phy_rate_fallback_mbps |
100 | PHY rate below this = fallback |
threshold_duration_multiplier |
2 | NAV > expected × this = mismatch |
threshold_retry_rate_percent |
20.0 | Retry % for collapse detection |
threshold_avg_nav_collapse_us |
10000 | Average NAV threshold for collapse |
threshold_collision_percent |
10.0 | Collision % for collapse |
threshold_mismatch_percent |
5.0 | Duration mismatch % for collapse |
log_every_n_mismatches |
1 | Log every Nth mismatch (1=all) |
GDB Commands for Threshold Control
View Current Thresholds
(gdb) show_thresholds
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
WiFi Monitor Thresholds (GDB-tunable)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
High NAV threshold: 5000 us
Duration mismatch log: 10000 us
PHY rate fallback: 100 Mbps
Duration multiplier: 2x expected
Collapse Detection:
Retry rate threshold: 20.0%
Avg NAV collapse: 10000 us
Collision percentage: 10.0%
Mismatch percentage: 5.0%
Logging Control:
Log every N mismatches: 1 (1=all, 10=every 10th)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Preset Profiles
Three pre-configured profiles for different scenarios:
# Sensitive - Catch more issues (stricter thresholds)
(gdb) tune_sensitive
Thresholds set to SENSITIVE (catch more issues)
# Normal - Default balanced settings
(gdb) tune_normal
Thresholds set to NORMAL (default)
# Relaxed - Fewer false positives (lenient thresholds)
(gdb) tune_relaxed
Thresholds set to RELAXED (fewer false positives)
Adjust Individual Thresholds
# Set high NAV threshold to 8000 us (8ms)
(gdb) set_high_nav 8000
High NAV threshold set to 8000 us
# Set mismatch logging threshold to 15000 us
(gdb) set_mismatch_log 15000
Duration mismatch logging threshold set to 15000 us
# Set rate fallback to 50 Mbps
(gdb) set_rate_fallback 50
PHY rate fallback threshold set to 50 Mbps
# Set duration multiplier (NAV > 3x expected = mismatch)
(gdb) set_multiplier 3
Duration multiplier set to 3x expected
# Log every 10th mismatch (reduce verbosity)
(gdb) set_log_rate 10
Logging every 10 mismatch(es)
Direct Variable Modification
You can also modify threshold variables directly:
(gdb) set threshold_high_nav_us = 7500
(gdb) set threshold_phy_rate_fallback_mbps = 75
(gdb) set log_every_n_mismatches = 5
(gdb) continue
# Changes take effect immediately!
Real-World Tuning Examples
Example 1: Noisy 2.4GHz Environment
Problem: Too many false positives on 2.4GHz
(gdb) tune_relaxed
(gdb) set_rate_fallback 24 # 2.4GHz rates lower
(gdb) set_log_rate 10 # Reduce log spam
(gdb) continue
Example 2: Clean 5GHz Network
Problem: Want to catch subtle issues early
(gdb) tune_sensitive
(gdb) set_rate_fallback 200 # Expect >200 Mbps
(gdb) set_multiplier 1.5 # Catch 1.5x mismatches
(gdb) continue
Example 3: Production Monitoring
Problem: Need to reduce log spam while maintaining detection
(gdb) tune_normal
(gdb) set_log_rate 100 # Log every 100th mismatch
(gdb) set_mismatch_log 20000 # Only log severe (>20ms)
(gdb) continue
Duration Analysis
The WiFi monitor calculates expected frame duration based on PHY rate and compares it with the actual NAV (Network Allocation Vector). Large mismatches indicate WiFi problems.
Duration Calculation
For each captured frame:
TX Time = (Frame Bytes × 8000) / PHY Rate (Kbps)
Overhead = Preamble + PLCP + SIFS + ACK ≈ 44 us
Expected Duration = TX Time + Overhead
Mismatch = Actual NAV - Expected Duration
GDB Commands for Duration Analysis
Quick Duration Check
(gdb) break monitor_frame_callback
(gdb) continue
(gdb) show_duration
DATA: 1500 bytes @ 433.5 Mbps → Expected 71 us, NAV 68 us (-3)
Watch DATA Frames
(gdb) watch_data
Watching DATA frames
Continuing.
# Output streams:
DATA: 1500 bytes @ 433.5 Mbps → Expected 71 us, NAV 68 us (-3)
DATA: 1200 bytes @ 433.5 Mbps → Expected 66 us, NAV 64 us (-2)
DATA: 800 bytes @ 54.0 Mbps → Expected 162 us, NAV 158 us (-4)
Find Duration Mismatches
(gdb) find_mismatch
Watching for NAV 2x+ expected duration
Continuing.
# Stops when mismatch detected:
DATA: 1200 bytes @ 54.0 Mbps → Expected 222 us, NAV 8500 us (+8278)
⚠ DURATION MISMATCH!
Interpreting Duration Differences
| Difference | Interpretation |
|---|---|
| -5 to +500 us | ✅ Normal overhead variation |
| +500 to +5000 us | ⚠️ Possible retransmission or fragmentation |
| +5000 to +20000 us | ⚠️⚠️ Likely collision or high contention |
| +20000+ us | 🚨 Severe WiFi collapse |
Example: Detecting WiFi Collapse
# Normal WiFi
(gdb) show_duration
DATA: 1500 bytes @ 433.5 Mbps → Expected 71 us, NAV 68 us (-3)
✅ Healthy
# WiFi Collapse
(gdb) show_duration
DATA: 1200 bytes @ 54.0 Mbps → Expected 222 us, NAV 32000 us (+31778)
🚨 Severe collapse!
- PHY rate dropped: 433.5 → 54 Mbps
- NAV 144x expected duration
- Likely severe contention/collisions
Debugging Strategies
WiFi Collapse Investigation Workflow
- Start with normal thresholds
(gdb) tune_normal (gdb) continue - Run WiFi traffic test
# From another machine iperf -c 192.168.1.81 -t 60 -P 4 - Monitor serial output for automatic detection
- If too noisy, adjust thresholds
(gdb) Ctrl-C (gdb) set_log_rate 10 (gdb) continue - If not catching issues, increase sensitivity
(gdb) Ctrl-C (gdb) tune_sensitive (gdb) continue - Document optimal settings for your network
Best Practices
Threshold Tuning
- Start conservative (tune_sensitive), then relax if needed
- Use log_every_n_mismatches to control verbosity
- Match thresholds to band (2.4GHz vs 5GHz)
- Document final thresholds for each network/environment
Frame Analysis
- Use conditional breakpoints to catch specific issues
- Focus on DATA frames for throughput analysis
- Watch for retry+high NAV combination (collision indicator)
- Compare RSSI across frames to detect signal issues
Performance Monitoring
- C code processes 10,000+ frames/sec
- GDB adds minimal overhead for threshold tuning
- Use GDB for deep inspection, C code for continuous monitoring
- Combine automated detection (C) with interactive debugging (GDB)
Real-World Examples
Example 1: Debugging Rate Fallback
Symptom: WiFi throughput suddenly drops
# Set breakpoint on low PHY rates
(gdb) break monitor_frame_callback if frame->phy_rate_kbps < 100000
Breakpoint 1 at 0x4200e926
(gdb) commands 1
>printf "Low PHY rate: %u Kbps, RSSI: %d dBm\n", frame->phy_rate_kbps, frame->rssi
>show_frame_full
>end
(gdb) continue
# Output reveals:
Low PHY rate: 54000 Kbps, RSSI: -82 dBm
# Root cause: Weak signal → rate adaptation → lower throughput
Example 2: Finding Collision Hotspots
Goal: Identify devices causing collisions
# Break on collision indicators
(gdb) break monitor_frame_callback if frame->retry && frame->duration_id > 5000
Breakpoint 1 at 0x4200e926
(gdb) commands 1
>printf "Collision from: %02x:%02x:%02x:%02x:%02x:%02x\n", \
frame->addr2[0], frame->addr2[1], frame->addr2[2], \
frame->addr2[3], frame->addr2[4], frame->addr2[5]
>continue
>end
(gdb) continue
# Track which MAC addresses retry most frequently
Example 3: Tuning for 2.4GHz vs 5GHz
# 2.4GHz network (more interference, lower rates)
(gdb) set_high_nav 8000 # More lenient
(gdb) set_rate_fallback 24 # Expected lower rates
(gdb) set_log_rate 20 # Reduce noise
(gdb) continue
# Later, switch to 5GHz
(gdb) Ctrl-C
(gdb) set_high_nav 5000 # Stricter
(gdb) set_rate_fallback 100 # Expect higher rates
(gdb) set_log_rate 1 # Log all
(gdb) continue
Troubleshooting
GDB Commands Not Found
Symptom: show_thresholds, tune_sensitive, etc. not recognized
Solution: Enable .gdbinit auto-loading
mkdir -p ~/.config/gdb
echo "set auto-load safe-path /" >> ~/.config/gdb/gdbinit
# Restart GDB
quit
idf.py gdb
Compilation Errors
Symptom: Build fails with "has no member named 'mcs'" errors
Solution: Make sure you have the latest code from feature/wifi-monitor-mode branch
git checkout feature/wifi-monitor-mode
git pull
cp wifi_monitor.h components/wifi_monitor/
cp wifi_monitor.c components/wifi_monitor/
rm -rf build
idf.py build
No Frames Captured
Symptom: Breakpoint never hits, no frames captured
Possible Causes:
- WiFi not connected or monitor mode not started
- Wrong channel
- RSSI too low (out of range)
Solution: Check monitor mode status
(gdb) print current_led_state
# Should be LED_STATE_MONITORING (4)
(gdb) print frame->channel
# Should match your AP's channel
Too Much Logging
Symptom: Serial output floods with mismatch logs
Solution: Increase log rate or mismatch threshold
(gdb) set_log_rate 50 # Log every 50th
(gdb) set_mismatch_log 20000 # Only log >20ms NAV
(gdb) continue
Advanced Techniques
Creating Custom .gdbinit Profiles
Add your own tuning profiles to .gdbinit:
define tune_my_network
set threshold_high_nav_us = 6500
set threshold_phy_rate_fallback_mbps = 120
set log_every_n_mismatches = 5
printf "Custom profile loaded for my network\n"
end
Logging Frame Data to File
(gdb) set logging file wifi_frames.log
(gdb) set logging on
(gdb) watch_data
# All output goes to wifi_frames.log
Combining Multiple Conditions
# Break on: High NAV + Retry + Low RSSI
(gdb) break monitor_frame_callback if \
frame->duration_id > 10000 && \
frame->retry == 1 && \
frame->rssi < -70
# Very specific debugging target
Performance: C Code vs GDB
| Method | Speed | Use Case |
|---|---|---|
| C Code (Running) | 10,000+ frames/sec | Continuous monitoring, production |
| GDB (Breakpoints) | ~10 frames/sec | Interactive inspection, debugging |
| GDB (Threshold Tuning) | Full speed | Runtime configuration, no overhead |
Resources
Git Repository
# Clone repository
git clone https://github.com/yourusername/esp32-iperf.git
cd esp32-iperf
# Checkout WiFi monitor branch
git checkout feature/wifi-monitor-mode
Key Files
components/wifi_monitor/wifi_monitor.c- Frame capture implementationcomponents/wifi_monitor/wifi_monitor.h- API definitionsmain/main.c- Monitor mode integration.gdbinit- GDB commands for WiFi debugging
Documentation Files
GDB_THRESHOLD_TUNING_GUIDE.md- Complete threshold tuning guideDURATION_ANALYSIS_GUIDE.md- Duration analysis detailsC_DURATION_ANALYSIS_GUIDE.md- C code implementation guideCOMPILATION_FIX_GUIDE.md- Troubleshooting build issuesWIFI_MONITOR_MODE_GUIDE.md- Full WiFi monitor documentation
External Resources
Quick Reference
| Command | Purpose |
|---|---|
show_thresholds |
Display current thresholds |
tune_sensitive |
Strict thresholds (catch more) |
tune_normal |
Default balanced settings |
tune_relaxed |
Lenient thresholds (fewer alerts) |
set_high_nav <us> |
Set high NAV threshold |
set_rate_fallback <mbps> |
Set rate fallback threshold |
set_log_rate <n> |
Log every Nth mismatch |
show_frame_full |
Complete frame analysis |
show_duration |
Quick duration comparison |
watch_data |
Monitor DATA frames |
find_mismatch |
Auto-break on NAV mismatches |