ESP32-C5 GDB Debugging Guide

WiFi Monitor Mode Edition - Real-Time WiFi Frame Analysis & Threshold Tuning

Author: Bob McMahon

Hardware: ESP32-C5 DevKit (RISC-V, Dual-Band WiFi 6)

ESP-IDF: v6.0 or later

Tools: GDB 16.3_20250913, OpenOCD v0.12.0-esp32-20250707

Last Updated: December 2025

📦 Git Branch: feature/wifi-monitor-mode
🔗 Repository: https://github.com/yourusername/esp32-iperf

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
Auto-Loading .gdbinit: The project includes a .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
Key Benefit: No rebuild needed! Tune thresholds live while monitoring WiFi traffic, see effects immediately, then document optimal settings for your network.

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
Note: PHY rate calculation is approximate on ESP32-C5 (ESP-IDF v6.0 doesn't expose detailed MCS/bandwidth fields). However, large duration mismatches still accurately indicate WiFi problems.

Debugging Strategies

WiFi Collapse Investigation Workflow

  1. Start with normal thresholds
    (gdb) tune_normal
    (gdb) continue
  2. Run WiFi traffic test
    # From another machine
    iperf -c 192.168.1.81 -t 60 -P 4
  3. Monitor serial output for automatic detection
  4. If too noisy, adjust thresholds
    (gdb) Ctrl-C
    (gdb) set_log_rate 10
    (gdb) continue
  5. If not catching issues, increase sensitivity
    (gdb) Ctrl-C
    (gdb) tune_sensitive
    (gdb) continue
  6. 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:

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
Best of Both Worlds: Use C code for real-time detection, GDB for threshold tuning and deep inspection. You get full performance with complete flexibility!

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

Documentation Files

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