support for both monitor and sta modes, set in NVS using config_device.

This commit is contained in:
Bob 2025-12-07 17:29:59 -08:00
parent 9d402a02de
commit 7924da11c7
9 changed files with 2186 additions and 88 deletions

View File

@ -47,7 +47,7 @@ static esp_err_t nvs_set_str2(nvs_handle_t h, const char *key, const char *val){
return val ? nvs_set_str(h, key, val) : nvs_erase_key(h, key);
}
static void save_cfg(const char* ssid, const char* pass, const char* ip, const char* mask, const char* gw, bool dhcp, const char* band, const char* bw, const char* powersave){
static void save_cfg(const char* ssid, const char* pass, const char* ip, const char* mask, const char* gw, bool dhcp, const char* band, const char* bw, const char* powersave, const char* mode, uint8_t mon_ch){
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READWRITE, &h) != ESP_OK) return;
if (ssid) nvs_set_str2(h, "ssid", ssid);
@ -58,16 +58,20 @@ static void save_cfg(const char* ssid, const char* pass, const char* ip, const c
if (band) nvs_set_str2(h, "band", band);
if (bw) nvs_set_str2(h, "bw", bw);
if (powersave) nvs_set_str2(h, "powersave", powersave);
if (mode) nvs_set_str2(h, "mode", mode);
nvs_set_u8(h, "mon_ch", mon_ch);
nvs_set_u8(h, "dhcp", dhcp ? 1 : 0);
nvs_commit(h);
nvs_close(h);
cfg_dhcp = dhcp;
ESP_LOGI(TAG, "Config saved to NVS: SSID=%s Band=%s BW=%s PowerSave=%s", ssid?ssid:"", band?band:"", bw?bw:"", powersave?powersave:"NONE");
ESP_LOGI(TAG, "Config saved to NVS: SSID=%s Mode=%s MonCh=%d Band=%s BW=%s PowerSave=%s",
ssid?ssid:"", mode?mode:"STA", mon_ch, band?band:"", bw?bw:"", powersave?powersave:"NONE");
}
static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz,
char* ip, size_t isz, char* mask, size_t msz, char* gw, size_t gsz,
char* band, size_t bsz, char* bw, size_t bwsz, char* powersave, size_t pssz, bool* dhcp){
char* band, size_t bsz, char* bw, size_t bwsz, char* powersave, size_t pssz,
char* mode, size_t modesz, uint8_t* mon_ch, bool* dhcp){
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) return false;
size_t len;
@ -82,6 +86,8 @@ static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz,
len = bsz; e = nvs_get_str(h, "band", band, &len); if (e!=ESP_OK) strcpy(band, "2.4G");
len = bwsz; e = nvs_get_str(h, "bw", bw, &len); if (e!=ESP_OK) strcpy(bw, "HT20");
len = pssz; e = nvs_get_str(h, "powersave", powersave, &len); if (e!=ESP_OK) strcpy(powersave, "NONE");
len = modesz; e = nvs_get_str(h, "mode", mode, &len); if (e!=ESP_OK) strcpy(mode, "STA");
uint8_t ch=36; nvs_get_u8(h, "mon_ch", &ch); *mon_ch = ch;
uint8_t d=1; nvs_get_u8(h, "dhcp", &d); *dhcp = (d!=0);
nvs_close(h);
return true;
@ -89,6 +95,32 @@ static bool load_cfg(char* ssid, size_t ssz, char* pass, size_t psz,
void wifi_cfg_force_dhcp(bool enable){ cfg_dhcp = enable; }
bool wifi_cfg_get_mode(char *mode, uint8_t *mon_ch) {
if (!mode || !mon_ch) return false;
nvs_handle_t h;
if (nvs_open("netcfg", NVS_READONLY, &h) != ESP_OK) {
ESP_LOGW(TAG, "Failed to open NVS for mode - defaulting to STA");
strcpy(mode, "STA");
*mon_ch = 36;
return false;
}
size_t len = 16;
esp_err_t e = nvs_get_str(h, "mode", mode, &len);
if (e != ESP_OK) {
strcpy(mode, "STA"); // Default to STA mode
}
uint8_t ch = 36;
nvs_get_u8(h, "mon_ch", &ch);
*mon_ch = ch;
nvs_close(h);
ESP_LOGI(TAG, "Retrieved mode from NVS: %s (MonCh=%d)", mode, ch);
return true;
}
/* --- One-time net stack bring-up (thread-safe) --- */
static atomic_bool s_net_stack_ready = false;
@ -157,10 +189,11 @@ static void apply_ip_static(const char* ip, const char* mask, const char* gw){
bool wifi_cfg_apply_from_nvs(void) {
char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0};
char band[16]={0}, bw[16]={0}, powersave[16]={0};
char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0};
uint8_t mon_ch = 36;
bool dhcp = true;
if (!load_cfg(ssid,sizeof(ssid), pass,sizeof(pass), ip,sizeof(ip), mask,sizeof(mask), gw,sizeof(gw),
band,sizeof(band), bw,sizeof(bw), powersave,sizeof(powersave), &dhcp)){
band,sizeof(band), bw,sizeof(bw), powersave,sizeof(powersave), mode,sizeof(mode), &mon_ch, &dhcp)){
ESP_LOGW(TAG, "No WiFi config in NVS");
return false;
}
@ -169,8 +202,8 @@ bool wifi_cfg_apply_from_nvs(void) {
ESP_LOGW(TAG, "SSID in NVS is empty; treating as no Wi-Fi config");
return false;
}
ESP_LOGI(TAG, "Applying Wi-Fi config: SSID=%s DHCP=%d IP=%s MASK=%s GW=%s Band=%s BW=%s PowerSave=%s",
ssid, dhcp, ip, mask, gw, band, bw, powersave);
ESP_LOGI(TAG, "Applying Wi-Fi config: SSID=%s DHCP=%d IP=%s MASK=%s GW=%s Band=%s BW=%s PowerSave=%s Mode=%s MonCh=%d",
ssid, dhcp, ip, mask, gw, band, bw, powersave, mode, mon_ch);
static bool inited = false;
if (!inited){
@ -336,7 +369,7 @@ typedef struct {
bool (*fetch_line)(char *buf, size_t sz, void *ctx);
} cfg_io_t;
static void on_cfg_line(const char *line, char *ssid, char *pass, char *ip, char *mask, char *gw, char *band, char *bw, char *powersave, bool *dhcp){
static void on_cfg_line(const char *line, char *ssid, char *pass, char *ip, char *mask, char *gw, char *band, char *bw, char *powersave, char *mode, uint8_t *mon_ch, bool *dhcp){
if (strncmp(line, "SSID:",5)==0){ strncpy(ssid, line+5, 63); ssid[63]=0; return; }
if (strncmp(line, "PASS:",5)==0){ strncpy(pass, line+5, 63); pass[63]=0; return; }
if (strncmp(line, "IP:",3)==0){ strncpy(ip, line+3, 31); ip[31]=0; return; }
@ -345,13 +378,16 @@ static void on_cfg_line(const char *line, char *ssid, char *pass, char *ip, char
if (strncmp(line, "BAND:",5)==0){ strncpy(band, line+5, 15); band[15]=0; return; }
if (strncmp(line, "BW:",3)==0){ strncpy(bw, line+3, 15); bw[15]=0; return; }
if (strncmp(line, "POWERSAVE:",10)==0){ strncpy(powersave, line+10, 15); powersave[15]=0; return; }
if (strncmp(line, "MODE:",5)==0){ strncpy(mode, line+5, 15); mode[15]=0; return; }
if (strncmp(line, "MON_CH:",7)==0){ *mon_ch = atoi(line+7); return; }
if (strncmp(line, "DHCP:",5)==0){ *dhcp = atoi(line+5) ? true:false; return; }
}
static void cfg_worker(const cfg_io_t *io){
char line[160];
char ssid[64]={0}, pass[64]={0}, ip[32]={0}, mask[32]={0}, gw[32]={0};
char band[16]={0}, bw[16]={0}, powersave[16]={0};
char band[16]={0}, bw[16]={0}, powersave[16]={0}, mode[16]={0};
uint8_t mon_ch = 36;
bool dhcp = true;
bool in_cfg = false;
@ -365,7 +401,8 @@ static void cfg_worker(const cfg_io_t *io){
if (strcmp(line, "CFG")==0){
in_cfg = true;
ssid[0]=pass[0]=ip[0]=mask[0]=gw[0]=0;
band[0]=bw[0]=powersave[0]=0;
band[0]=bw[0]=powersave[0]=mode[0]=0;
mon_ch = 36;
dhcp = true;
}
continue;
@ -375,14 +412,15 @@ static void cfg_worker(const cfg_io_t *io){
if (!band[0]) strcpy(band, "2.4G");
if (!bw[0]) strcpy(bw, "HT20");
if (!powersave[0]) strcpy(powersave, "NONE");
if (!mode[0]) strcpy(mode, "STA");
save_cfg(ssid, pass, ip, mask, gw, dhcp, band, bw, powersave);
save_cfg(ssid, pass, ip, mask, gw, dhcp, band, bw, powersave, mode, mon_ch);
if (io->emit) io->emit("OK\n", io->ctx);
wifi_cfg_apply_from_nvs();
in_cfg = false;
continue;
}
on_cfg_line(line, ssid, pass, ip, mask, gw, band, bw, powersave, &dhcp);
on_cfg_line(line, ssid, pass, ip, mask, gw, band, bw, powersave, mode, &mon_ch, &dhcp);
}
}

View File

@ -46,6 +46,15 @@ wifi_ps_type_t wifi_cfg_get_power_save_mode(void);
*/
bool wifi_cfg_get_bandwidth(char *buf, size_t buf_size);
/**
* @brief Get operating mode and monitor channel from NVS
*
* @param mode Output buffer for mode string (min 16 bytes)
* @param mon_ch Output pointer for monitor channel
* @return true if mode retrieved, false if no config in NVS
*/
bool wifi_cfg_get_mode(char *mode, uint8_t *mon_ch);
/**
* @brief Ensure WiFi driver is initialized (thread-safe, idempotent)
*

View File

@ -15,11 +15,12 @@ def log_verbose(message, verbose=False):
def config_device(port, ip, ssid="ClubHouse2G", password="ez2remember",
gateway="192.168.1.1", netmask="255.255.255.0",
band="2.4G", bandwidth="HT20", powersave="NONE", reboot=True, verbose=False):
band="2.4G", bandwidth="HT20", powersave="NONE",
mode="STA", monitor_channel=36, reboot=True, verbose=False):
"""Configure ESP32 device via serial with static IP"""
print(f"\n{'='*70}")
print(f"ESP32 WiFi Configuration (Static IP)")
print(f"ESP32 WiFi Configuration (Static IP + Mode)")
print(f"{'='*70}")
print(f"Port: {port}")
print(f"SSID: {ssid}")
@ -27,6 +28,9 @@ def config_device(port, ip, ssid="ClubHouse2G", password="ez2remember",
print(f"IP: {ip} (DHCP disabled)")
print(f"Gateway: {gateway}")
print(f"Netmask: {netmask}")
print(f"Mode: {mode}")
if mode == "MONITOR":
print(f"Mon Ch: {monitor_channel}")
print(f"Band: {band}")
print(f"Bandwidth: {bandwidth}")
print(f"PowerSave: {powersave}")
@ -62,6 +66,8 @@ def config_device(port, ip, ssid="ClubHouse2G", password="ez2remember",
f"BAND:{band}",
f"BW:{bandwidth}",
f"POWERSAVE:{powersave}",
f"MODE:{mode}",
f"MON_CH:{monitor_channel}",
"END"
]
@ -270,23 +276,26 @@ def main():
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Basic 2.4GHz configuration with static IP (DHCP disabled automatically)
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.51
# Configure device #1 for STA mode (iperf baseline testing)
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.81 -M STA
# 5GHz with 80MHz bandwidth
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.81 -s ClubHouse5G -b 5G -B VHT80
# Configure device #25 for MONITOR mode on channel 36 (collapse detection)
%(prog)s -p /dev/ttyUSB1 -i 192.168.1.90 -M MONITOR -mc 36
# Monitor mode on 2.4GHz channel 6
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.91 -M MONITOR -mc 6 -b 2.4G
# STA mode on 5GHz with 40MHz bandwidth
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.81 -M STA -b 5G -B HT40
# Disable power save for best CSI quality
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.51 -ps NONE
# Enable minimum power save
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.51 -ps MIN
# With verbose output
%(prog)s -p /dev/ttyUSB0 -i 192.168.1.51 -v
Note: DHCP is always disabled when using this script since you're providing a static IP.
The device will use the exact IP address you specify with -i.
Note: Mode is saved to NVS and device will auto-start in configured mode on boot.
DHCP is always disabled when using this script since you're providing a static IP.
"""
)
@ -310,6 +319,11 @@ Note: DHCP is always disabled when using this script since you're providing a st
parser.add_argument('-ps', '--powersave', default='NONE',
choices=['NONE', 'MIN', 'MIN_MODEM', 'MAX', 'MAX_MODEM'],
help='Power save mode: NONE (no PS, best for CSI), MIN/MIN_MODEM, MAX/MAX_MODEM (default: NONE)')
parser.add_argument('-M', '--mode', default='STA',
choices=['STA', 'MONITOR'],
help='Operating mode: STA (connect to AP, CSI+iperf) or MONITOR (promiscuous, collapse detection) (default: STA)')
parser.add_argument('-mc', '--monitor-channel', type=int, default=36,
help='Monitor mode channel (1-11 for 2.4GHz, 36-165 for 5GHz) (default: 36)')
parser.add_argument('-r', '--no-reboot', action='store_true',
help='Do NOT reboot device after configuration')
parser.add_argument('-v', '--verbose', action='store_true',
@ -333,6 +347,8 @@ Note: DHCP is always disabled when using this script since you're providing a st
band=args.band,
bandwidth=args.bandwidth,
powersave=args.powersave,
mode=args.mode,
monitor_channel=args.monitor_channel,
reboot=not args.no_reboot,
verbose=args.verbose
)

View File

@ -0,0 +1,429 @@
# Bandwidth and Band Selection Guide
## 🎯 New Features
### Monitor Mode: Channel + Bandwidth Selection
Control both the channel AND bandwidth when monitoring:
```bash
mode_monitor 6/20 # 2.4GHz channel 6, 20MHz
mode_monitor 36/80 # 5GHz channel 36, 80MHz
```
### STA Mode: Band Preference
Force connection to specific band:
```bash
mode_sta 2.4 # Connect on 2.4GHz only
mode_sta 5 # Connect on 5GHz only
mode_sta auto # Auto select (default)
```
---
## 📡 Monitor Mode Bandwidth Control
### Syntax
```
mode_monitor <channel>/<bandwidth>
```
### 2.4GHz Band Bandwidth Options
**20MHz (HT20)** - Single channel
```bash
mode_monitor 1/20
mode_monitor 6/20
mode_monitor 11/20
```
- ✅ Maximum compatibility
- ✅ Less interference from adjacent channels
- ❌ Lower throughput (~72 Mbps max)
**40MHz (HT40)** - Channel bonding
```bash
mode_monitor 1/40
mode_monitor 6/40
mode_monitor 11/40
```
- ✅ Higher throughput (~150 Mbps max)
- ⚠️ Uses 2 adjacent channels (more interference)
- ⚠️ Not recommended in dense environments
**Default:** If bandwidth not specified, defaults to 20MHz
```bash
mode_monitor 6 # Same as 6/20
```
### 5GHz Band Bandwidth Options
**20MHz (HT20)** - Single channel
```bash
mode_monitor 36/20
mode_monitor 149/20
```
- ✅ Maximum compatibility
- ✅ Best for long range
- ❌ Lower throughput
**40MHz (HT40)** - Channel bonding
```bash
mode_monitor 36/40 # Channels 36+40
mode_monitor 149/40 # Channels 149+153
```
- ✅ Good balance of speed and compatibility
- ✅ WiFi 5 (802.11ac) standard
- ⚠️ Uses 2 channels
**80MHz (HT80)** - Wide channel bonding (WiFi 6)
```bash
mode_monitor 36/80 # Channels 36+40+44+48
mode_monitor 149/80 # Channels 149+153+157+161
```
- ✅ Maximum throughput (~866 Mbps+ with WiFi 6)
- ✅ WiFi 6 (802.11ax) optimized
- ⚠️ Uses 4 channels
- ⚠️ Shorter range than 20/40MHz
**Default:** If bandwidth not specified, defaults to 40MHz on 5GHz
```bash
mode_monitor 149 # Same as 149/40
```
---
## 🌐 STA Mode Band Selection
### Syntax
```
mode_sta [band]
```
### Band Options
**Auto (Default)** - Let ESP32 choose best band
```bash
mode_sta
mode_sta auto
```
- ✅ Connects to strongest signal
- ✅ Falls back if preferred band unavailable
- Use when: AP supports both bands
**2.4GHz Only**
```bash
mode_sta 2.4
mode_sta 2
```
- ✅ Forces connection on 2.4GHz
- ✅ Better range, wall penetration
- ❌ Lower speed, more interference
- Use when: Need maximum range
**5GHz Only**
```bash
mode_sta 5
mode_sta 5.0
```
- ✅ Forces connection on 5GHz
- ✅ Higher speed, less interference
- ❌ Shorter range
- Use when: AP is close, need best performance
---
## 📊 Usage Examples
### Example 1: 2.4GHz Narrow Band Monitoring
For maximum interference rejection in dense environment:
```bash
esp32> mode_monitor 6/20
I (+1733424645.234) MAIN: Switching to MONITOR MODE
I (+1733424645.235) MAIN: Channel: 6 (2.4GHz)
I (+1733424645.236) MAIN: Bandwidth: 20MHz
I (+1733424647.567) MAIN: ✓ Monitor mode active
```
### Example 2: 2.4GHz Wide Band Monitoring
For maximum throughput testing:
```bash
esp32> mode_monitor 6/40
I (+1733424645.234) MAIN: Switching to MONITOR MODE
I (+1733424645.235) MAIN: Channel: 6 (2.4GHz)
I (+1733424645.236) MAIN: Bandwidth: 40MHz
```
### Example 3: 5GHz WiFi 6 Monitoring
For WiFi 6 collapse detection with 80MHz:
```bash
esp32> mode_monitor 36/80
I (+1733424645.234) MAIN: Switching to MONITOR MODE
I (+1733424645.235) MAIN: Channel: 36 (5GHz)
I (+1733424645.236) MAIN: Bandwidth: 80MHz
I (+1733424647.567) MAIN: ✓ Monitor mode active
```
### Example 4: Force 5GHz Connection
Connect to AP on 5GHz band only:
```bash
esp32> mode_sta 5
I (+1733424645.234) MAIN: Switching to STA MODE
I (+1733424645.235) MAIN: Band preference: 5GHz only
I (+1733424647.234) MAIN: Got IP: 192.168.1.100
I (+1733424647.567) MAIN: ✓ STA mode active
```
### Example 5: Check Current Configuration
```bash
esp32> mode_status
=== WiFi Mode Status ===
Current mode: MONITOR
LED state: Blue solid (Monitoring)
Monitor channel: 36 (5GHz)
Monitor bandwidth: 80MHz
Monitor enabled: Yes
Frames captured: 15234
GPS synced: Yes (+)
```
### Example 6: Switch Between Bandwidths
Test different bandwidths on same channel:
```bash
# Start with 20MHz
esp32> mode_monitor 149/20
[collect data for 5 minutes...]
# Switch to 40MHz
esp32> mode_monitor 149/40
[collect data for 5 minutes...]
# Switch to 80MHz
esp32> mode_monitor 149/80
[collect data for 5 minutes...]
# Compare collapse rates vs bandwidth
```
---
## 🎯 Bandwidth Selection Strategy
### When to Use 20MHz
**Best for:**
- Dense environments with many APs
- Long-range connections
- Interference-prone areas
- Maximum compatibility
**Monitor mode:**
```bash
mode_monitor 6/20 # 2.4GHz
mode_monitor 149/20 # 5GHz
```
### When to Use 40MHz
**Best for:**
- Medium-density environments
- Balance of speed and range
- Most common configuration
- WiFi 5 (802.11ac)
**Monitor mode:**
```bash
mode_monitor 6/40 # 2.4GHz (not recommended in dense areas)
mode_monitor 149/40 # 5GHz (recommended)
```
### When to Use 80MHz
**Best for:**
- Low-density environments
- Maximum throughput
- WiFi 6 (802.11ax) testing
- Short-range, high-speed links
**Monitor mode (5GHz only):**
```bash
mode_monitor 36/80
mode_monitor 149/80
```
---
## 🔍 Real-World Scenarios
### Scenario 1: Office WiFi Collapse Detection
**Goal:** Monitor office WiFi on 5GHz with WiFi 6
```bash
# 1. Connect to AP and check its configuration
esp32> mode_sta
[wait for connection...]
esp32> mode_status
Connected band: 5GHz (channel 36)
Bandwidth: 80MHz
# 2. Switch to monitor mode with same config
esp32> mode_monitor 36/80
# 3. Monitor for collapse events
[Logs GPS-timestamped collapse events...]
```
### Scenario 2: 2.4GHz Congestion Analysis
**Goal:** Compare 20MHz vs 40MHz collapse rates
```bash
# Test 20MHz (narrow band)
esp32> mode_monitor 6/20
[collect for 30 minutes...]
# Note collapse count
# Test 40MHz (wide band)
esp32> mode_monitor 6/40
[collect for 30 minutes...]
# Compare: 40MHz likely has MORE collapses in dense area
```
### Scenario 3: Force 5GHz for Performance
**Goal:** Ensure device connects on 5GHz only
```bash
# Force 5GHz connection
esp32> mode_sta 5
# Verify connected on 5GHz
esp32> mode_status
Band preference: 5GHz only
Connected band: 5GHz (channel 149)
Bandwidth: 80MHz
# Now switch to monitor on same channel
esp32> mode_monitor 149/80
```
### Scenario 4: Multi-Device Deployment
**Goal:** Monitor different bandwidths across 32 devices
```bash
# Devices 1-8: 2.4GHz 20MHz
Device 1-8: mode_monitor 6/20
# Devices 9-16: 2.4GHz 40MHz
Device 9-16: mode_monitor 6/40
# Devices 17-24: 5GHz 40MHz
Device 17-24: mode_monitor 149/40
# Devices 25-32: 5GHz 80MHz
Device 25-32: mode_monitor 149/80
# Compare collapse rates across all configurations!
```
---
## 📈 Performance Expectations
### 2.4GHz Performance
| Bandwidth | Max PHY Rate | Typical Throughput | Range | Interference |
|-----------|-------------|-------------------|-------|--------------|
| 20MHz | ~72 Mbps | 40-50 Mbps | Best | Least |
| 40MHz | ~150 Mbps | 80-100 Mbps | Good | Most |
### 5GHz Performance
| Bandwidth | Max PHY Rate | Typical Throughput | Range | Best Use |
|-----------|-------------|-------------------|-------|----------|
| 20MHz | ~87 Mbps | 50-60 Mbps | Best | Long range |
| 40MHz | ~200 Mbps | 120-150 Mbps | Good | Balanced |
| 80MHz | ~433 Mbps | 300-400 Mbps | Short | Max speed |
*Note: WiFi 6 (802.11ax) can achieve higher rates with OFDMA and 1024-QAM*
---
## ⚙️ Advanced Usage
### Match Your AP's Configuration
Always match bandwidth to your AP for best results:
```bash
# 1. Check AP configuration (via router admin or WiFi analyzer)
# Example: AP is on channel 36 with 80MHz
# 2. Configure STA mode to connect
esp32> mode_sta 5
# 3. Verify connection
esp32> mode_status
Connected band: 5GHz (channel 36)
Bandwidth: 80MHz
# 4. Switch to monitor with SAME configuration
esp32> mode_monitor 36/80
```
### Test Bandwidth Impact on Collapse
```python
# After collecting data at different bandwidths:
import pandas as pd
df_20 = pd.read_csv('collapses_ch36_20mhz.csv')
df_40 = pd.read_csv('collapses_ch36_40mhz.csv')
df_80 = pd.read_csv('collapses_ch36_80mhz.csv')
print("Collapse rate (20MHz):", len(df_20) / 3600, "per hour")
print("Collapse rate (40MHz):", len(df_40) / 3600, "per hour")
print("Collapse rate (80MHz):", len(df_80) / 3600, "per hour")
# Hypothesis: Wider bandwidth = more collapses in dense environments
```
---
## ✅ Quick Reference
### Monitor Mode Bandwidths
| Band | Command | Bandwidth | Use Case |
|------|---------|-----------|----------|
| 2.4GHz | `mode_monitor 6/20` | 20MHz | Dense area, max compatibility |
| 2.4GHz | `mode_monitor 6/40` | 40MHz | Speed test (avoid in dense area) |
| 5GHz | `mode_monitor 149/20` | 20MHz | Long range |
| 5GHz | `mode_monitor 149/40` | 40MHz | Balanced (default) |
| 5GHz | `mode_monitor 149/80` | 80MHz | WiFi 6 max speed |
### STA Mode Bands
| Command | Behavior | Use Case |
|---------|----------|----------|
| `mode_sta` | Auto select | Default, best signal |
| `mode_sta 2.4` | Force 2.4GHz | Max range |
| `mode_sta 5` | Force 5GHz | Max performance |
---
## 🎉 Summary
**New capabilities:**
- ✅ Monitor mode with bandwidth control (20/40/80MHz)
- ✅ STA mode with band preference (2.4/5/auto)
- ✅ Full control over WiFi 6 configurations
- ✅ Test different bandwidths for collapse analysis
- ✅ Force band for optimal performance
**Syntax:**
```bash
mode_monitor <channel>/<bandwidth> # e.g., 36/80
mode_sta [band] # e.g., mode_sta 5
```
Now you can precisely control and test WiFi configurations across all supported bands and bandwidths!

View File

@ -0,0 +1,779 @@
================================================================================
ESP32-C5 CONFIGURATION DEVICE MANUAL
config_device.py v2.0
================================================================================
TABLE OF CONTENTS
-----------------
1. Overview
2. Installation Requirements
3. Quick Start
4. Command-Line Arguments
5. Usage Examples
6. Operating Modes
7. Configuration Parameters
8. Troubleshooting
9. Advanced Usage
10. Common Deployment Scenarios
================================================================================
1. OVERVIEW
================================================================================
config_device.py is a Python script that configures ESP32-C5 devices via
serial connection. It sets WiFi credentials, network parameters, operating
mode (STA or MONITOR), and all other device settings which are stored in
Non-Volatile Storage (NVS) for persistence across reboots.
Key Features:
• Static IP configuration with automatic DHCP disable
• Operating mode selection (STA for iperf, MONITOR for WiFi analysis)
• Monitor channel configuration
• Power save mode control
• WiFi band and bandwidth selection
• Automatic device reboot after configuration
• Comprehensive status feedback
================================================================================
2. INSTALLATION REQUIREMENTS
================================================================================
Python Requirements:
• Python 3.6 or later
• pyserial module
Install pyserial:
$ pip install pyserial
or
$ pip3 install pyserial
System Requirements:
• Serial port access (Linux: /dev/ttyUSB*, macOS: /dev/cu.*, Windows: COM*)
• User permissions for serial port access
Linux serial port permissions:
$ sudo usermod -a -G dialout $USER
(then logout and login)
Verify installation:
$ python3 config_device.py --help
================================================================================
3. QUICK START
================================================================================
Basic STA Mode Configuration:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81
Basic MONITOR Mode Configuration:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.90 \\
-M MONITOR -mc 36
With verbose output:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -v
================================================================================
4. COMMAND-LINE ARGUMENTS
================================================================================
REQUIRED ARGUMENTS
------------------
-p, --port PORT
Serial port device
Examples: /dev/ttyUSB0, /dev/ttyUSB1, COM3
Required: YES
-i, --ip IP_ADDRESS
Static IP address for the device
DHCP is automatically disabled when using this script
Examples: 192.168.1.81, 10.0.0.50
Required: YES
OPTIONAL ARGUMENTS - WiFi Settings
-----------------------------------
-s, --ssid SSID
WiFi network name (SSID)
Default: ClubHouse2G
Example: -s "MyNetwork"
-P, --password PASSWORD
WiFi password
Default: ez2remember
Example: -P "MySecurePassword123"
OPTIONAL ARGUMENTS - Network Settings
--------------------------------------
-g, --gateway IP_ADDRESS
Gateway IP address
Default: 192.168.1.1
Example: -g 192.168.1.1
-m, --netmask NETMASK
Network mask
Default: 255.255.255.0
Example: -m 255.255.255.0
OPTIONAL ARGUMENTS - WiFi Configuration
----------------------------------------
-b, --band {2.4G,5G}
WiFi frequency band
Options:
2.4G - 2.4 GHz band (channels 1-11 in US)
5G - 5 GHz band (channels 36-165)
Default: 2.4G
Example: -b 5G
-B, --bandwidth {HT20,HT40,VHT80}
Channel bandwidth
Options:
HT20 - 20 MHz (2.4GHz or 5GHz)
HT40 - 40 MHz (2.4GHz or 5GHz)
VHT80 - 80 MHz (5GHz only)
Default: HT20
Notes:
• VHT80 requires 5GHz band (-b 5G)
• Monitor mode forces 20MHz regardless of setting
Example: -B HT40
-ps, --powersave {NONE,MIN,MIN_MODEM,MAX,MAX_MODEM}
Power saving mode
Options:
NONE - No power saving (best for CSI, highest power)
MIN - Minimum power save (alias for MIN_MODEM)
MIN_MODEM - Minimum modem power save
MAX - Maximum power save (alias for MAX_MODEM)
MAX_MODEM - Maximum modem power save (lowest power)
Default: NONE
Recommendation: Use NONE for CSI capture and WiFi analysis
Example: -ps NONE
OPTIONAL ARGUMENTS - Operating Mode
------------------------------------
-M, --mode {STA,MONITOR}
Operating mode
Options:
STA - Station mode (connect to AP, run iperf, CSI capture)
MONITOR - Monitor mode (promiscuous WiFi packet capture)
Default: STA
Example: -M MONITOR
-mc, --monitor-channel CHANNEL
Monitor mode channel number
Valid ranges:
2.4GHz: 1-11 (US)
5GHz: 36, 40, 44, 48 (UNII-1)
149, 153, 157, 161, 165 (UNII-3)
Default: 36
Note: Only used when mode is MONITOR
Example: -mc 149
OPTIONAL ARGUMENTS - Script Behavior
-------------------------------------
-r, --no-reboot
Do NOT reboot device after configuration
Default: Device is rebooted automatically
Use this flag to configure without rebooting
Example: -r
-v, --verbose
Enable verbose output
Shows detailed serial communication and debug information
Example: -v
-h, --help
Show help message and exit
================================================================================
5. USAGE EXAMPLES
================================================================================
BASIC EXAMPLES
--------------
Example 1: Configure device for STA mode with defaults
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81
Result:
• SSID: ClubHouse2G
• Password: ez2remember
• IP: 192.168.1.81
• Mode: STA
• Band: 2.4GHz
• Bandwidth: 20MHz
Example 2: Configure device for MONITOR mode on channel 36
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.90 \\
-M MONITOR -mc 36
Result:
• Device boots in STA mode to connect to WiFi
• After GPS sync, auto-switches to MONITOR mode on channel 36
• Captures all WiFi traffic on channel 36
Example 3: 5GHz with 40MHz bandwidth, STA mode
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 \\
-s ClubHouse5G -b 5G -B HT40
Result:
• Connects to ClubHouse5G SSID
• Uses 5GHz band with 40MHz bandwidth
• STA mode (default)
Example 4: Custom WiFi credentials
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 \\
-s "MyNetwork" -P "MyPassword123"
Result:
• Connects to "MyNetwork" with password "MyPassword123"
• Uses default 2.4GHz, 20MHz, STA mode
Example 5: Configure without rebooting
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -r
Result:
• Configuration saved to NVS
• Device does NOT reboot
• Must manually reboot to apply settings
ADVANCED EXAMPLES
-----------------
Example 6: MONITOR mode on 2.4GHz channel 6
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.91 \\
-M MONITOR -mc 6 -b 2.4G
Result:
• Monitor mode on 2.4GHz channel 6
• Good for monitoring 2.4GHz WiFi collapse
Example 7: Verbose output for debugging
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -v
Result:
• Shows detailed serial communication
• Displays all bytes sent/received
• Useful for troubleshooting
Example 8: Multiple channels for different devices
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.90 \\
-M MONITOR -mc 36
$ python3 config_device.py -p /dev/ttyUSB1 -i 192.168.1.91 \\
-M MONITOR -mc 40
$ python3 config_device.py -p /dev/ttyUSB2 -i 192.168.1.92 \\
-M MONITOR -mc 44
Result:
• Device .90 monitors channel 36
• Device .91 monitors channel 40
• Device .92 monitors channel 44
• Comprehensive 5GHz band monitoring
Example 9: Different network settings
$ python3 config_device.py -p /dev/ttyUSB0 -i 10.0.0.100 \\
-g 10.0.0.1 -m 255.255.255.0 -s "OfficeWiFi" -P "Office2025"
Result:
• IP: 10.0.0.100
• Gateway: 10.0.0.1
• SSID: OfficeWiFi
• Different network configuration
================================================================================
6. OPERATING MODES
================================================================================
STA MODE (Station Mode)
-----------------------
Purpose: Connect to WiFi access point as a client
Use Cases:
• iperf baseline testing
• CSI (Channel State Information) capture
• Network performance measurement
• Standard WiFi connectivity
Behavior:
1. Device connects to configured WiFi AP
2. Obtains configured static IP address
3. Runs iperf server on port 5001
4. Captures CSI data
5. Maintains WiFi connection
6. LED: Green (connected)
Configuration:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -M STA
Features Active in STA Mode:
• WiFi connectivity
• iperf server
• CSI capture
• GPS timestamping
• Network services
MONITOR MODE (Promiscuous Mode)
--------------------------------
Purpose: Capture all WiFi packets on a specific channel
Use Cases:
• WiFi collapse detection
• Network traffic analysis
• Protocol debugging
• Security research
Behavior:
1. Device connects to WiFi AP initially (for GPS sync)
2. Gets static IP address
3. Waits for WiFi connection (LED: Green)
4. Waits 2 seconds for GPS sync
5. Switches to MONITOR mode on configured channel
6. Captures all WiFi packets on that channel
7. LED: Blue (monitoring)
Configuration:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.90 \\
-M MONITOR -mc 36
Features Active in MONITOR Mode:
• Promiscuous packet capture
• WiFi frame analysis (RTS/CTS/ACK/Beacon/Data)
• GPS timestamping
• CSI capture
• No WiFi connectivity (after switch)
Important Notes:
• Monitor mode is read-only (no transmit)
• Device disconnects from AP after switching to monitor
• Monitor mode always uses 20MHz bandwidth (driver limitation)
• Best for detecting WiFi collapse events
================================================================================
7. CONFIGURATION PARAMETERS
================================================================================
STORED IN NVS (Non-Volatile Storage)
-------------------------------------
The following parameters are stored in NVS and persist across reboots:
| Parameter | NVS Key | Type | Default | Description |
|------------|------------|---------|--------------|----------------------------|
| SSID | ssid | string | ClubHouse2G | WiFi network name |
| Password | pass | string | ez2remember | WiFi password |
| IP Address | ip | string | (required) | Static IP address |
| Netmask | mask | string | 255.255.255.0| Network mask |
| Gateway | gw | string | 192.168.1.1 | Gateway IP |
| DHCP | dhcp | bool | false | Always false (static IP) |
| Band | band | string | 2.4G | WiFi band (2.4G or 5G) |
| Bandwidth | bw | string | HT20 | Channel bandwidth |
| PowerSave | powersave | string | NONE | Power save mode |
| Mode | mode | string | STA | Operating mode |
| Mon Ch | mon_ch | uint8_t | 36 | Monitor mode channel |
BANDWIDTH OPTIONS
-----------------
HT20 (20 MHz):
• Compatible with: 2.4GHz and 5GHz
• Maximum throughput: ~72 Mbps (802.11n)
• Best for: Compatibility, monitor mode
• Channels used: 1 channel
HT40 (40 MHz):
• Compatible with: 2.4GHz and 5GHz
• Maximum throughput: ~150 Mbps (802.11n)
• Best for: Higher throughput
• Channels used: 2 adjacent channels
• Note: Monitor mode forces to 20MHz
VHT80 (80 MHz):
• Compatible with: 5GHz only
• Maximum throughput: ~433 Mbps (802.11ac)
• Best for: Maximum throughput
• Channels used: 4 adjacent channels
• Note: Monitor mode forces to 20MHz
• Requires: -b 5G
CHANNEL SELECTION
-----------------
2.4GHz Channels (US):
• Non-overlapping: 1, 6, 11
• All available: 1-11
• Bandwidth: 20MHz or 40MHz
• Example: -mc 6 -b 2.4G
5GHz Channels (US):
• UNII-1: 36, 40, 44, 48 (5.15-5.25 GHz)
• UNII-2: 52, 56, 60, 64 (5.25-5.35 GHz, DFS)
• UNII-2e: 100-144 (5.47-5.725 GHz, DFS)
• UNII-3: 149, 153, 157, 161, 165 (5.725-5.85 GHz)
• Bandwidth: 20MHz, 40MHz, or 80MHz
• Example: -mc 36 -b 5G
Recommended Monitor Channels:
• 2.4GHz: 1, 6, 11 (non-overlapping)
• 5GHz: 36, 149 (no DFS, always available)
================================================================================
8. TROUBLESHOOTING
================================================================================
COMMON ISSUES
-------------
Issue: "Serial error: [Errno 13] Permission denied: '/dev/ttyUSB0'"
Solution:
1. Add user to dialout group:
$ sudo usermod -a -G dialout $USER
2. Logout and login
3. Verify:
$ groups | grep dialout
Issue: "No response from device"
Possible Causes:
1. Wrong serial port
Solution: Check with: ls /dev/ttyUSB*
2. Another program using the port
Solution: Close other programs (idf.py monitor, screen, minicom)
3. Wrong baud rate
Solution: Script uses 115200 (correct for ESP32-C5)
4. Device not running config handler
Solution: Flash latest firmware
Issue: "Device got different IP than configured"
Possible Causes:
1. DHCP still enabled (shouldn't happen with this script)
Solution: Check device logs for "DHCP:0"
2. IP conflict on network
Solution: Use different IP address
3. Router forcing DHCP
Solution: Check router settings, reserve IP
Issue: "VHT80 error"
Message: "✗ Error: VHT80 (80MHz) is only supported on 5GHz band"
Solution:
• Use -b 5G with -B VHT80
• Or use -B HT20 or -B HT40 for 2.4GHz
Issue: "Device not switching to MONITOR mode"
Possible Causes:
1. WiFi not connected first
Solution: Check logs for "WiFi CONNECTED"
2. GPS not syncing
Solution: Wait 30-60 seconds for GPS lock
3. Wrong firmware version
Solution: Flash latest firmware with auto_monitor_task
Issue: "Configuration not persisting after reboot"
Possible Causes:
1. NVS partition corrupted
Solution: Erase flash and reconfigure:
$ idf.py -p /dev/ttyUSB0 erase-flash
$ idf.py -p /dev/ttyUSB0 flash
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81
VERBOSE MODE DEBUGGING
----------------------
Enable verbose mode to see detailed information:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -v
Verbose output shows:
• Serial port settings
• Bytes sent/received
• Configuration message contents
• Device response parsing
• Error details with traceback
SERIAL PORT VERIFICATION
-------------------------
List available serial ports:
Linux: $ ls -l /dev/ttyUSB*
macOS: $ ls -l /dev/cu.*
Windows: $ mode
Test serial port communication:
$ python3 -m serial.tools.miniterm /dev/ttyUSB0 115200
================================================================================
9. ADVANCED USAGE
================================================================================
BATCH CONFIGURATION
-------------------
Configure multiple devices with a script:
#!/bin/bash
# configure_devices.sh
# STA mode devices (.81-.89)
for i in {81..89}; do
port=$((i-81))
echo "Configuring device $i on /dev/ttyUSB$port (STA mode)"
python3 config_device.py -p /dev/ttyUSB$port -i 192.168.1.$i -M STA
sleep 2
done
# MONITOR mode devices (.90-.98)
for i in {90..98}; do
port=$((i-81))
echo "Configuring device $i on /dev/ttyUSB$port (MONITOR mode)"
python3 config_device.py -p /dev/ttyUSB$port -i 192.168.1.$i \\
-M MONITOR -mc 36
sleep 2
done
Usage:
$ chmod +x configure_devices.sh
$ ./configure_devices.sh
CONFIGURATION WITHOUT REBOOT
-----------------------------
Use -r flag to configure without rebooting:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -r
Then manually reboot later:
• Press RESET button on device
• Or use: idf.py -p /dev/ttyUSB0 monitor (then Ctrl+T, Ctrl+R)
• Or power cycle
MULTI-CHANNEL MONITORING
-------------------------
Deploy devices across multiple channels:
channels=(36 40 44 48 149 153 157 161)
start_ip=90
for i in "${!channels[@]}"; do
ch=${channels[$i]}
ip=$((start_ip + i))
port=$i
echo "Device $ip: Monitor channel $ch on /dev/ttyUSB$port"
python3 config_device.py -p /dev/ttyUSB$port -i 192.168.1.$ip \\
-M MONITOR -mc $ch -b 5G
done
DIFFERENT POWER SAVE MODES
---------------------------
Test different power save modes:
# Device 1: No power save (best for CSI)
python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -ps NONE
# Device 2: Minimum power save
python3 config_device.py -p /dev/ttyUSB1 -i 192.168.1.82 -ps MIN
# Device 3: Maximum power save
python3 config_device.py -p /dev/ttyUSB2 -i 192.168.1.83 -ps MAX
INTEGRATION WITH MONITORING SCRIPTS
------------------------------------
Configure device and start monitoring:
#!/bin/bash
# deploy_and_monitor.sh
DEVICE_IP="192.168.1.90"
PORT="/dev/ttyUSB0"
# Configure device
python3 config_device.py -p $PORT -i $DEVICE_IP -M MONITOR -mc 36
# Wait for reboot
sleep 10
# Start monitoring
idf.py -p $PORT monitor | tee device_90.log
================================================================================
10. COMMON DEPLOYMENT SCENARIOS
================================================================================
SCENARIO 1: WIFI COLLAPSE DETECTION (32 devices)
-------------------------------------------------
Goal: Detect WiFi collapse events and correlate with iperf degradation
Setup:
• 9 devices in STA mode (.81-.89) for iperf baseline
• 9 devices in MONITOR mode (.90-.98) for collapse detection
• All on 5GHz channel 36
Configuration:
# STA devices
for i in {81..89}; do
python3 config_device.py -p /dev/ttyUSB$((i-81)) \\
-i 192.168.1.$i -M STA -b 5G -B HT20 -ps NONE
done
# MONITOR devices
for i in {90..98}; do
python3 config_device.py -p /dev/ttyUSB$((i-81)) \\
-i 192.168.1.$i -M MONITOR -mc 36 -b 5G
done
Data Collection:
# Capture logs from all devices
for i in {0..17}; do
cat /dev/ttyUSB$i > logs/device_$((81+i)).log &
done
# Merge by GPS timestamp
cat logs/*.log | sort -t'(' -k2 -n > merged.log
SCENARIO 2: CHANNEL SURVEY (8 channels)
----------------------------------------
Goal: Monitor WiFi activity across multiple 5GHz channels
Setup:
• 8 devices in MONITOR mode on different channels
• Comprehensive 5GHz band coverage
Configuration:
channels=(36 40 44 48 149 153 157 161)
for i in "${!channels[@]}"; do
python3 config_device.py -p /dev/ttyUSB$i \\
-i 192.168.1.$((90+i)) -M MONITOR -mc ${channels[$i]} -b 5G
done
SCENARIO 3: 2.4GHz vs 5GHz COMPARISON
--------------------------------------
Goal: Compare WiFi behavior on 2.4GHz vs 5GHz
Setup:
• 4 devices on 2.4GHz channels 1, 6, 11 (MONITOR)
• 4 devices on 5GHz channels 36, 149 (MONITOR)
• 2 STA devices (1 on each band)
Configuration:
# 2.4GHz monitors
for ch in 1 6 11; do
python3 config_device.py -p /dev/ttyUSB$i \\
-i 192.168.1.$((90+i)) -M MONITOR -mc $ch -b 2.4G
((i++))
done
# 5GHz monitors
for ch in 36 149; do
python3 config_device.py -p /dev/ttyUSB$i \\
-i 192.168.1.$((90+i)) -M MONITOR -mc $ch -b 5G
((i++))
done
SCENARIO 4: POWER SAVE IMPACT TESTING
--------------------------------------
Goal: Measure impact of power save modes on CSI quality
Setup:
• 3 devices with different power save modes
• All in STA mode for CSI capture
Configuration:
python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -ps NONE
python3 config_device.py -p /dev/ttyUSB1 -i 192.168.1.82 -ps MIN
python3 config_device.py -p /dev/ttyUSB2 -i 192.168.1.83 -ps MAX
Compare CSI data quality across the three modes.
================================================================================
APPENDIX A: CONFIGURATION MESSAGE FORMAT
================================================================================
The script sends this message to the device over serial:
CFG
SSID:ClubHouse2G
PASS:ez2remember
IP:192.168.1.90
MASK:255.255.255.0
GW:192.168.1.1
DHCP:0
BAND:5G
BW:HT20
POWERSAVE:NONE
MODE:MONITOR
MON_CH:36
END
Device responds with:
OK
Then device logs:
I (1234) wifi_cfg: Config saved to NVS: SSID=ClubHouse2G Mode=MONITOR MonCh=36...
I (1234) wifi_cfg: Applying Wi-Fi config: ...
================================================================================
APPENDIX B: LED STATUS INDICATORS
================================================================================
| Color | Pattern | Meaning |
|--------|----------|------------------------------------------|
| Yellow | Solid | No WiFi config in NVS |
| Blue | Blinking | Connecting to WiFi |
| Green | Solid | Connected in STA mode |
| Blue | Solid | MONITOR mode active |
| Red | Blinking | Connection failed / Error |
================================================================================
APPENDIX C: QUICK REFERENCE CARD
================================================================================
Most Common Configurations:
STA mode (default everything):
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81
STA mode on 5GHz:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -b 5G
MONITOR mode channel 36:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.90 \\
-M MONITOR -mc 36
MONITOR mode 2.4GHz channel 6:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.91 \\
-M MONITOR -mc 6 -b 2.4G
Custom SSID/password:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 \\
-s "MyWiFi" -P "MyPassword"
Verbose debugging:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -v
No reboot:
$ python3 config_device.py -p /dev/ttyUSB0 -i 192.168.1.81 -r
================================================================================
END OF MANUAL
================================================================================
For more information and updates:
• See NVS_MODE_CONFIGURATION_GUIDE.md
• See QUICK_DEPLOYMENT_REFERENCE.md
• See WIFI_CFG_CHANGES_DETAILED.md
Version: 2.0
Last Updated: December 2025

256
doc/QUICK_REFERENCE.md Normal file
View File

@ -0,0 +1,256 @@
# Console Commands Quick Reference
## 🎮 All Available Commands
```bash
mode_monitor [channel/bandwidth] # Monitor mode with bandwidth control
mode_sta [band] # STA mode with band selection
mode_status # Show current configuration
csi_dump # Dump CSI data (STA mode only)
```
---
## 📡 Monitor Mode Examples
### 2.4GHz Band
```bash
mode_monitor 6/20 # Channel 6, 20MHz (narrow, less interference)
mode_monitor 6/40 # Channel 6, 40MHz (wide, more speed)
mode_monitor 11/20 # Channel 11, 20MHz
mode_monitor 1 # Channel 1, default 20MHz
```
### 5GHz Band
```bash
mode_monitor 36/20 # Channel 36, 20MHz (max range)
mode_monitor 36/40 # Channel 36, 40MHz (balanced)
mode_monitor 36/80 # Channel 36, 80MHz (max speed, WiFi 6)
mode_monitor 149/80 # Channel 149, 80MHz
mode_monitor 161 # Channel 161, default 40MHz
```
---
## 🌐 STA Mode Examples
### Auto Band Selection (Default)
```bash
mode_sta # Auto select 2.4GHz or 5GHz
mode_sta auto # Same as above
```
### Force 2.4GHz
```bash
mode_sta 2.4 # Connect on 2.4GHz only
mode_sta 2 # Same as above
```
### Force 5GHz
```bash
mode_sta 5 # Connect on 5GHz only
mode_sta 5.0 # Same as above
```
---
## 📊 Status Check
```bash
esp32> mode_status
=== WiFi Mode Status ===
Current mode: MONITOR
LED state: Blue solid (Monitoring)
Monitor channel: 36 (5GHz)
Monitor bandwidth: 80MHz
Monitor enabled: Yes
Frames captured: 15234
GPS synced: Yes (+)
```
---
## 🎯 Common Workflows
### Workflow 1: WiFi 6 Testing on 5GHz
```bash
# 1. Connect on 5GHz
esp32> mode_sta 5
# 2. Wait for connection (green LED)
# 3. Check AP channel
esp32> mode_status
Connected band: 5GHz (channel 36)
Bandwidth: 80MHz
# 4. Switch to monitor with same config
esp32> mode_monitor 36/80
# 5. Monitor collapse events with GPS timestamps
[Monitoring...]
```
### Workflow 2: 2.4GHz Congestion Analysis
```bash
# Test narrow bandwidth
esp32> mode_monitor 6/20
[collect for 30 min...]
# Test wide bandwidth
esp32> mode_monitor 6/40
[collect for 30 min...]
# Compare collapse rates
```
### Workflow 3: Force 5GHz for Performance
```bash
# Force 5GHz connection
esp32> mode_sta 5
# Verify connected on 5GHz
esp32> mode_status
# Collect CSI data on 5GHz
[wait 20 seconds for auto dump]
# Or dump manually
esp32> csi_dump
```
### Workflow 4: Multi-Bandwidth Testing
```bash
# Test same channel at different bandwidths
esp32> mode_monitor 149/20
[5 minutes...]
esp32> mode_monitor 149/40
[5 minutes...]
esp32> mode_monitor 149/80
[5 minutes...]
# Analyze which has fewer collapses
```
---
## 🎨 LED Status
| Color | State | Mode |
|-------|-------|------|
| Yellow solid | No WiFi config | - |
| Blue blink | Connecting to AP | STA |
| Green solid | Connected, CSI+iperf running | STA |
| Blue solid | Monitor mode active | Monitor |
| Red blink | Connection failed | - |
---
## 📝 GPS Timestamp Format
```
Log messages:
I (*1.234) MAIN: Waiting... (* = not synced)
I (+1733424645.234) MAIN: Ready! (+ = GPS synced)
CSV collapse events:
COLLAPSE,MonoMS,GpsMS,Synced,NAV,RSSI,Retry
COLLAPSE,5234567,1733424645234,1,5234.50,-65,1
```
---
## 🔧 Configuration Matrix
### Valid Bandwidth Combinations
| Band | Channel Examples | 20MHz | 40MHz | 80MHz |
|------|-----------------|-------|-------|-------|
| 2.4GHz | 1, 6, 11 | ✅ | ✅ | ❌ |
| 5GHz | 36, 149, 161 | ✅ | ✅ | ✅ |
### Valid Band Preferences
| Mode | 2.4GHz | 5GHz | Auto |
|------|--------|------|------|
| STA | ✅ | ✅ | ✅ (default) |
| Monitor | ✅ | ✅ | N/A |
---
## 🚀 Deployment Examples
### 32-Device Setup: Multi-Bandwidth Testing
```bash
# Devices 1-8: 2.4GHz 20MHz
mode_monitor 6/20
# Devices 9-16: 2.4GHz 40MHz
mode_monitor 6/40
# Devices 17-24: 5GHz 40MHz
mode_monitor 149/40
# Devices 25-32: 5GHz 80MHz
mode_monitor 149/80
```
### Production Deployment: Best Performance
```bash
# All devices: Force 5GHz connection
mode_sta 5
# After connection, monitor on AP's channel
mode_monitor 149/80
```
---
## ⚡ Performance Tips
### For Maximum Range
```bash
mode_sta 2.4 # Connect on 2.4GHz
mode_monitor 6/20 # Monitor with 20MHz
```
### For Maximum Speed
```bash
mode_sta 5 # Connect on 5GHz
mode_monitor 149/80 # Monitor with 80MHz
```
### For Dense Environments
```bash
mode_sta 5 # Prefer 5GHz (less congestion)
mode_monitor 149/20 # Narrow bandwidth (less interference)
```
### For WiFi 6 Testing
```bash
mode_sta auto # Auto select
mode_monitor 36/80 # 80MHz WiFi 6
```
---
## 🎉 Feature Summary
**ESP32-C5 Capabilities:**
- ✅ WiFi 6 (802.11ax) on 2.4GHz and 5GHz
- ✅ Bandwidths: 20MHz, 40MHz (both bands); 80MHz (5GHz only)
- ✅ Band selection: Auto, 2.4GHz only, 5GHz only
- ✅ Runtime mode switching (no reflashing needed)
- ✅ GPS-timestamped collapse detection
- ✅ CSI capture + iperf server in STA mode
- ✅ Visual LED status indicators
**Console Commands:**
- 4 commands total
- Bandwidth control in monitor mode
- Band preference in STA mode
- Real-time status checking
- One firmware for all configurations!

View File

@ -1,10 +1,17 @@
idf_component_register(
SRCS
"main.c"
SRCS "main.c"
INCLUDE_DIRS "."
PRIV_REQUIRES
csi_log
gps_sync
REQUIRES
nvs_flash
esp_wifi
esp_netif
esp_event
lwip
console # Console handles UART automatically
iperf
wifi_cfg
csi_log
wifi_monitor
gps_sync
led_strip
)

View File

@ -10,6 +10,8 @@
#include "esp_event.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_console.h"
#include "linenoise/linenoise.h"
#include "nvs_flash.h"
#include "esp_netif.h"
@ -22,7 +24,7 @@
#include "wifi_cfg.h"
#include "csi_log.h"
#include "wifi_monitor.h"
#include "gps_sync.h" // <--- ADDED: GPS Support
#include "gps_sync.h"
static const char *TAG = "MAIN";
@ -30,10 +32,22 @@ static const char *TAG = "MAIN";
#if CONFIG_IDF_TARGET_ESP32C5
#define RGB_LED_GPIO 27
#else
// Fallback for other chips if you switch boards
#define RGB_LED_GPIO 8
#endif
// --- WiFi Operation Mode ---
typedef enum {
WIFI_MODE_STA_CSI, // STA mode: Connected to AP, CSI + iperf (DEFAULT)
WIFI_MODE_MONITOR // Monitor mode: Promiscuous, collapse detection
} wifi_operation_mode_t;
// Note: wifi_band_mode_t is already defined in ESP-IDF's esp_wifi_types_generic.h
// Values: WIFI_BAND_MODE_2G_ONLY, WIFI_BAND_MODE_5G_ONLY, WIFI_BAND_MODE_AUTO
static wifi_operation_mode_t current_wifi_mode = WIFI_MODE_STA_CSI;
static wifi_band_mode_t preferred_band = WIFI_BAND_MODE_AUTO;
static uint8_t monitor_channel = 6; // Default monitor channel
// --- LED State Machine ---
static led_strip_handle_t led_strip;
static bool wifi_connected = false;
@ -49,6 +63,9 @@ typedef enum {
static led_state_t current_led_state = LED_STATE_NO_CONFIG;
// --- Forward Declarations ---
static void auto_monitor_task(void *arg);
static void rgb_led_init(void) {
ESP_LOGI(TAG, "Initializing RGB LED on GPIO %d", RGB_LED_GPIO);
led_strip_config_t strip_config = {
@ -105,7 +122,6 @@ static void led_task(void *arg) {
}
// --- GPS Logging Helper ---
// Replaces the old plain text log with your CSV + GPS Timestamp format
void log_collapse_event(float nav_duration_us, int rssi, int retry) {
gps_timestamp_t ts = gps_get_timestamp();
@ -137,33 +153,48 @@ static void wifi_enable_csi_once(void) {
vTaskDelay(pdMS_TO_TICKS(2000));
wifi_csi_config_t csi_cfg;
memset(&csi_cfg, 0, sizeof(csi_cfg));
csi_cfg.enable = true; // C5 specific simple config
csi_cfg.enable = true;
ESP_LOGI("CSI", "Configuring CSI...");
if (esp_wifi_set_csi_config(&csi_cfg) != ESP_OK) return;
if (esp_wifi_set_csi_rx_cb(csi_cb, NULL) != ESP_OK) return;
if (esp_wifi_set_csi(true) != ESP_OK) return;
if (esp_wifi_set_csi_config(&csi_cfg) != ESP_OK) {
ESP_LOGE("CSI", "Failed to set CSI config");
return;
}
if (esp_wifi_set_csi_rx_cb(csi_cb, NULL) != ESP_OK) {
ESP_LOGE("CSI", "Failed to set CSI callback");
return;
}
if (esp_wifi_set_csi(true) != ESP_OK) {
ESP_LOGE("CSI", "Failed to enable CSI");
return;
}
ESP_LOGI("CSI", "CSI enabled!");
s_csi_enabled = true;
}
static void csi_dump_task(void *arg) {
vTaskDelay(pdMS_TO_TICKS(20000)); // Dump after 20 seconds
csi_log_dump_over_uart();
vTaskDelete(NULL);
static void wifi_disable_csi(void) {
if (!s_csi_enabled) return;
ESP_LOGI("CSI", "Disabling CSI...");
esp_wifi_set_csi(false);
s_csi_enabled = false;
ESP_LOGI("CSI", "CSI disabled");
}
static void csi_init_task(void *arg) {
wifi_enable_csi_once();
static void csi_dump_task(void *arg) {
vTaskDelay(pdMS_TO_TICKS(20000)); // Dump after 20 seconds
ESP_LOGI("CSI", "Dumping CSI data...");
csi_log_dump_over_uart();
ESP_LOGI("CSI", "CSI dump complete");
vTaskDelete(NULL);
}
// --- WiFi Monitor Mode Support -------------------------------------
static bool s_monitor_enabled = false;
static uint32_t s_monitor_frame_count = 0;
static TaskHandle_t s_monitor_stats_task_handle = NULL;
// This is the core analysis function
static void monitor_frame_callback(const wifi_frame_info_t *frame,
const uint8_t *payload,
uint16_t len) {
@ -171,13 +202,12 @@ static void monitor_frame_callback(const wifi_frame_info_t *frame,
// 1. Check for Collapse (High NAV + Retry)
if (frame->retry && frame->duration_id > 5000) {
// USE GPS LOGGING HERE
log_collapse_event((float)frame->duration_id, frame->rssi, frame->retry);
}
// 2. Also warn on extremely high NAV (blocking the channel)
// 2. Warn on extremely high NAV
if (frame->duration_id > 30000) {
ESP_LOGW("MONITOR", " VERY HIGH NAV: %u us", frame->duration_id);
ESP_LOGW("MONITOR", " VERY HIGH NAV: %u us", frame->duration_id);
}
}
@ -190,35 +220,458 @@ static void monitor_stats_task(void *arg) {
stats.total_frames, stats.retry_rate, stats.avg_nav);
if (wifi_monitor_is_collapsed()) {
ESP_LOGW("MONITOR", "⚠⚠ WiFi COLLAPSE DETECTED! ⚠⚠⚠");
ESP_LOGW("MONITOR", " WiFi COLLAPSE DETECTED! ⚠ ");
}
}
}
}
static void wifi_enable_monitor_mode(uint8_t channel) {
if (s_monitor_enabled) return;
// --- Mode Switching Functions --------------------------------------
ESP_LOGI("MONITOR", "Starting WiFi monitor mode on channel %d", channel);
if (wifi_monitor_init(channel, monitor_frame_callback) != ESP_OK) return;
if (wifi_monitor_start() != ESP_OK) return;
esp_err_t switch_to_monitor_mode(uint8_t channel, wifi_bandwidth_t bandwidth) {
if (current_wifi_mode == WIFI_MODE_MONITOR) {
ESP_LOGW(TAG, "Already in monitor mode");
return ESP_OK;
}
// CRITICAL: ESP-IDF monitor/promiscuous mode is typically restricted to 20MHz
// even though the hardware supports 40MHz. Force 20MHz for monitor mode.
if (bandwidth != WIFI_BW_HT20) {
ESP_LOGW(TAG, "Monitor mode typically restricted to 20MHz capture width");
ESP_LOGW(TAG, "Forcing bandwidth to 20MHz (driver limitation)");
bandwidth = WIFI_BW_HT20;
}
// Detect band for informational logging
const char* band_str = "2.4GHz";
if (channel >= 36 && channel <= 165) {
band_str = "5GHz";
}
const char* bw_str = "20MHz";
// Note: Monitor mode typically limited to 20MHz by ESP-IDF drivers
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "Switching to MONITOR MODE");
ESP_LOGI(TAG, " Channel: %d (%s)", channel, band_str);
ESP_LOGI(TAG, " Bandwidth: %s (monitor mode limitation)", bw_str);
ESP_LOGI(TAG, "========================================");
// 1. Stop iperf if running
ESP_LOGI(TAG, "Stopping iperf...");
iperf_stop();
vTaskDelay(pdMS_TO_TICKS(500));
// 2. Disable CSI
wifi_disable_csi();
vTaskDelay(pdMS_TO_TICKS(500));
// 3. Disconnect from AP
ESP_LOGI(TAG, "Disconnecting from AP...");
esp_wifi_disconnect();
vTaskDelay(pdMS_TO_TICKS(1000));
// 4. Stop WiFi
ESP_LOGI(TAG, "Stopping WiFi...");
esp_wifi_stop();
vTaskDelay(pdMS_TO_TICKS(500));
// 5. Set to NULL mode
ESP_LOGI(TAG, "Setting WiFi mode to NULL...");
esp_wifi_set_mode(WIFI_MODE_NULL);
vTaskDelay(pdMS_TO_TICKS(500));
// 6. Configure bandwidth before starting monitor mode
ESP_LOGI(TAG, "Configuring bandwidth to %s...", bw_str);
wifi_config_t wifi_config = {};
esp_wifi_get_config(WIFI_IF_STA, &wifi_config);
// Set bandwidth in promiscuous mode config
// Note: Bandwidth is set via wifi monitor init
// 7. Start monitor mode
ESP_LOGI(TAG, "Starting monitor mode...");
if (wifi_monitor_init(channel, monitor_frame_callback) != ESP_OK) {
ESP_LOGE(TAG, "Failed to init monitor mode");
return ESP_FAIL;
}
// Set bandwidth after init
esp_wifi_set_bandwidth(WIFI_IF_STA, bandwidth);
if (wifi_monitor_start() != ESP_OK) {
ESP_LOGE(TAG, "Failed to start monitor mode");
return ESP_FAIL;
}
s_monitor_enabled = true;
current_wifi_mode = WIFI_MODE_MONITOR;
current_led_state = LED_STATE_MONITORING;
monitor_channel = channel;
ESP_LOGI("MONITOR", "WiFi monitor started");
xTaskCreate(monitor_stats_task, "monitor_stats", 4096, NULL, 5, NULL);
// 8. Start stats task
if (s_monitor_stats_task_handle == NULL) {
xTaskCreate(monitor_stats_task, "monitor_stats", 4096, NULL, 5, &s_monitor_stats_task_handle);
}
ESP_LOGI(TAG, "✓ Monitor mode active");
ESP_LOGI(TAG, " - Channel: %d (%s)", channel, band_str);
ESP_LOGI(TAG, " - Bandwidth: %s", bw_str);
ESP_LOGI(TAG, " - Logging GPS-timestamped collapse events");
ESP_LOGI(TAG, " - LED: Blue solid");
ESP_LOGI(TAG, "========================================");
return ESP_OK;
}
static void monitor_init_task(void *arg) {
wifi_ap_record_t ap_info;
// Try to sniff the same channel our AP is using
if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
wifi_enable_monitor_mode(ap_info.primary);
} else {
wifi_enable_monitor_mode(6); // Default fallback
esp_err_t switch_to_sta_mode(wifi_band_mode_t band_mode) {
if (current_wifi_mode == WIFI_MODE_STA_CSI) {
ESP_LOGW(TAG, "Already in STA mode");
return ESP_OK;
}
vTaskDelete(NULL);
const char* band_str = "Auto (2.4GHz or 5GHz)";
if (band_mode == WIFI_BAND_MODE_2G_ONLY) {
band_str = "2.4GHz only";
} else if (band_mode == WIFI_BAND_MODE_5G_ONLY) {
band_str = "5GHz only";
}
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "Switching to STA MODE (CSI + iperf)");
ESP_LOGI(TAG, " Band preference: %s", band_str);
ESP_LOGI(TAG, "========================================");
preferred_band = band_mode;
// 1. Stop monitor stats task
if (s_monitor_stats_task_handle != NULL) {
vTaskDelete(s_monitor_stats_task_handle);
s_monitor_stats_task_handle = NULL;
}
// 2. Stop monitor mode
if (s_monitor_enabled) {
ESP_LOGI(TAG, "Stopping monitor mode...");
wifi_monitor_stop();
s_monitor_enabled = false;
vTaskDelay(pdMS_TO_TICKS(500));
}
// 3. Set mode back to STA
ESP_LOGI(TAG, "Setting WiFi mode to STA...");
esp_wifi_set_mode(WIFI_MODE_STA);
vTaskDelay(pdMS_TO_TICKS(500));
// 4. Configure band preference
wifi_config_t wifi_config;
esp_wifi_get_config(WIFI_IF_STA, &wifi_config);
if (band_mode == WIFI_BAND_MODE_2G_ONLY) {
wifi_config.sta.channel = 0; // Scan all channels, but prefer 2.4GHz
wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
// Note: ESP-IDF doesn't have direct band filtering, but we can set channel to force band
ESP_LOGI(TAG, "Configured for 2.4GHz band");
} else if (band_mode == WIFI_BAND_MODE_5G_ONLY) {
wifi_config.sta.channel = 0; // Scan all channels
wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
// The AP should be on 5GHz; connection will work if AP supports 5GHz
ESP_LOGI(TAG, "Configured for 5GHz band preference");
} else {
// Auto mode - let ESP-IDF choose best band
wifi_config.sta.channel = 0;
wifi_config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
ESP_LOGI(TAG, "Configured for auto band selection");
}
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
// 5. Start WiFi
ESP_LOGI(TAG, "Starting WiFi...");
esp_wifi_start();
vTaskDelay(pdMS_TO_TICKS(500));
// 6. Reconnect to AP
ESP_LOGI(TAG, "Connecting to AP...");
esp_wifi_connect();
current_wifi_mode = WIFI_MODE_STA_CSI;
current_led_state = LED_STATE_WAITING;
wifi_connected = false;
ESP_LOGI(TAG, "✓ Reconnecting to AP...");
ESP_LOGI(TAG, " - Band: %s", band_str);
ESP_LOGI(TAG, " - Waiting for IP address");
ESP_LOGI(TAG, " - CSI and iperf will start after connection");
ESP_LOGI(TAG, "========================================");
// Note: CSI and iperf will be started by event handler when IP is obtained
return ESP_OK;
}
// --- Console Commands ----------------------------------------------
static int cmd_mode_monitor(int argc, char **argv) {
int channel = monitor_channel; // Use last channel or default
wifi_bandwidth_t bandwidth = WIFI_BW_HT20; // Default to 20MHz
if (argc > 1) {
// Parse channel/bandwidth format: "6/20" or "36/40"
char *slash = strchr(argv[1], '/');
if (slash != NULL) {
*slash = '\0'; // Split string at '/'
channel = atoi(argv[1]);
int bw = atoi(slash + 1);
// Convert bandwidth to enum - ESP32-C5 only supports 20/40MHz
switch(bw) {
case 20:
bandwidth = WIFI_BW_HT20;
break;
case 40:
bandwidth = WIFI_BW_HT40;
printf("WARNING: Monitor mode typically restricted to 20MHz by ESP-IDF drivers\n");
printf(" 40MHz requested but will be forced to 20MHz\n");
break;
default:
printf("Error: Invalid bandwidth %d\n", bw);
printf("ESP32-C5 hardware: 20MHz and 40MHz\n");
printf("Monitor mode driver: 20MHz only (typical limitation)\n");
return 1;
}
} else {
channel = atoi(argv[1]);
// Monitor mode: always default to 20MHz (driver limitation)
bandwidth = WIFI_BW_HT20;
}
// Validate channel based on band
// ESP32-C5 supports WiFi 6 on 2.4GHz and 5GHz only (NO 6GHz support)
bool valid = false;
const char* band = "Unknown";
// 2.4GHz: channels 1-14
if (channel >= 1 && channel <= 14) {
valid = true;
band = "2.4GHz";
// Validate bandwidth for 2.4GHz
if (bandwidth != WIFI_BW_HT20 && bandwidth != WIFI_BW_HT40) {
printf("Error: 2.4GHz only supports 20MHz and 40MHz bandwidth\n");
return 1;
}
}
// 5GHz: specific valid channels only
else if (channel >= 36 && channel <= 165) {
// UNII-1 and UNII-2: 36-64 (every 4 channels)
if ((channel >= 36 && channel <= 64 && (channel % 4 == 0)) ||
// UNII-2 Extended: 100-144 (every 4 channels)
(channel >= 100 && channel <= 144 && (channel % 4 == 0)) ||
// UNII-3: 149,153,157,161,165
(channel >= 149 && channel <= 165 && (channel % 4 == 1))) {
valid = true;
band = "5GHz";
}
}
if (!valid) {
printf("Error: Invalid channel %d\n", channel);
printf("\nESP32-C5 supports WiFi 6 on 2.4GHz and 5GHz bands only:\n");
printf(" 2.4GHz: 1-14 (20MHz or 40MHz)\n");
printf(" 5GHz: 36,40,44,48,52,56,60,64,100,104,...,161,165 (20/40/80MHz)\n");
printf("\nExamples:\n");
printf(" mode_monitor 6/20 # 2.4GHz channel 6, 20MHz\n");
printf(" mode_monitor 6/40 # 2.4GHz channel 6, 40MHz\n");
printf(" mode_monitor 36/20 # 5GHz channel 36, 20MHz\n");
printf(" mode_monitor 36/40 # 5GHz channel 36, 40MHz\n");
printf(" mode_monitor 36/80 # 5GHz channel 36, 80MHz\n");
printf(" mode_monitor 149 # 5GHz channel 149, default 40MHz\n");
return 1;
}
const char* bw_str = (bandwidth == WIFI_BW_HT40) ? "40MHz" : "20MHz";
printf("Monitoring channel %d (%s band, %s)\n", channel, band, bw_str);
}
esp_err_t err = switch_to_monitor_mode(channel, bandwidth);
if (err != ESP_OK) {
printf("Failed to switch to monitor mode\n");
return 1;
}
return 0;
}
static int cmd_mode_sta(int argc, char **argv) {
wifi_band_mode_t band_mode = WIFI_BAND_MODE_AUTO; // Default to auto
if (argc > 1) {
if (strcmp(argv[1], "2.4") == 0 || strcmp(argv[1], "2") == 0) {
band_mode = WIFI_BAND_MODE_2G_ONLY;
printf("Forcing 2.4GHz band\n");
} else if (strcmp(argv[1], "5") == 0 || strcmp(argv[1], "5.0") == 0) {
band_mode = WIFI_BAND_MODE_5G_ONLY;
printf("Forcing 5GHz band\n");
} else if (strcmp(argv[1], "auto") == 0) {
band_mode = WIFI_BAND_MODE_AUTO;
printf("Auto band selection (2.4GHz or 5GHz)\n");
} else {
printf("Error: Invalid band '%s'\n", argv[1]);
printf("Valid options: 2.4, 5, auto\n");
printf("Examples:\n");
printf(" mode_sta 2.4 # Connect on 2.4GHz only\n");
printf(" mode_sta 5 # Connect on 5GHz only\n");
printf(" mode_sta auto # Auto select (default)\n");
return 1;
}
}
esp_err_t err = switch_to_sta_mode(band_mode);
if (err != ESP_OK) {
printf("Failed to switch to STA mode\n");
return 1;
}
printf("Switching to STA mode (reconnecting to AP...)\n");
return 0;
}
static int cmd_mode_status(int argc, char **argv) {
printf("\n=== WiFi Mode Status ===\n");
printf("Current mode: %s\n",
current_wifi_mode == WIFI_MODE_STA_CSI ? "STA (CSI + iperf)" : "MONITOR");
printf("LED state: ");
switch(current_led_state) {
case LED_STATE_NO_CONFIG: printf("Yellow (No config)\n"); break;
case LED_STATE_WAITING: printf("Blue blink (Connecting)\n"); break;
case LED_STATE_CONNECTED: printf("Green (Connected)\n"); break;
case LED_STATE_MONITORING: printf("Blue solid (Monitoring)\n"); break;
case LED_STATE_FAILED: printf("Red blink (Failed)\n"); break;
}
if (current_wifi_mode == WIFI_MODE_STA_CSI) {
printf("WiFi connected: %s\n", wifi_connected ? "Yes" : "No");
// Show band preference
const char* band_pref = "Auto";
if (preferred_band == WIFI_BAND_MODE_2G_ONLY) band_pref = "2.4GHz only";
else if (preferred_band == WIFI_BAND_MODE_5G_ONLY) band_pref = "5GHz only";
printf("Band preference: %s\n", band_pref);
// Show actual connected band/channel if connected
if (wifi_connected) {
wifi_ap_record_t ap_info;
if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
const char* band = (ap_info.primary >= 36) ? "5GHz" : "2.4GHz";
printf("Connected band: %s (channel %d)\n", band, ap_info.primary);
// Show bandwidth
wifi_bandwidth_t bw;
esp_wifi_get_bandwidth(WIFI_IF_STA, &bw);
const char* bw_str = "Unknown";
if (bw == WIFI_BW_HT20) bw_str = "20MHz";
else if (bw == WIFI_BW_HT40) bw_str = "40MHz";
printf("Bandwidth: %s\n", bw_str);
}
}
printf("CSI enabled: %s\n", s_csi_enabled ? "Yes" : "No");
if (s_csi_enabled) {
printf("CSI packets captured: %lu\n", (unsigned long)s_csi_packet_count);
}
} else {
const char* band = (monitor_channel >= 36) ? "5GHz" : "2.4GHz";
printf("Monitor channel: %d (%s)\n", monitor_channel, band);
// Show monitor bandwidth
wifi_bandwidth_t bw;
esp_wifi_get_bandwidth(WIFI_IF_STA, &bw);
const char* bw_str = "Unknown";
if (bw == WIFI_BW_HT20) bw_str = "20MHz";
else if (bw == WIFI_BW_HT40) bw_str = "40MHz";
printf("Monitor bandwidth: %s\n", bw_str);
printf("Monitor enabled: %s\n", s_monitor_enabled ? "Yes" : "No");
printf("Frames captured: %lu\n", (unsigned long)s_monitor_frame_count);
}
printf("GPS synced: %s\n", gps_is_synced() ? "Yes (+)" : "No (*)");
printf("\n");
return 0;
}
static int cmd_csi_dump(int argc, char **argv) {
if (current_wifi_mode != WIFI_MODE_STA_CSI) {
printf("Error: CSI only available in STA mode\n");
printf("Use 'mode_sta' to switch to STA mode first\n");
return 1;
}
if (!s_csi_enabled) {
printf("Error: CSI not enabled yet\n");
printf("Wait for WiFi connection, or reconnect with 'mode_sta'\n");
return 1;
}
printf("Dumping CSI data...\n");
csi_log_dump_over_uart();
printf("CSI dump complete\n");
return 0;
}
static void register_mode_commands(void) {
const esp_console_cmd_t mode_monitor = {
.command = "mode_monitor",
.help = "Switch to monitor mode (collapse detection)\n"
" ESP32-C5 Hardware: WiFi 6 on 2.4GHz/5GHz, 20/40MHz\n"
" Monitor Driver: Typically restricted to 20MHz capture\n"
" Usage: mode_monitor [channel[/bandwidth]]\n"
" Note: 40MHz will be forced to 20MHz (driver limitation)\n"
" Examples:\n"
" mode_monitor 6 # 2.4GHz ch 6, 20MHz\n"
" mode_monitor 6/20 # 2.4GHz ch 6, 20MHz (explicit)\n"
" mode_monitor 36 # 5GHz ch 36, 20MHz\n"
" mode_monitor 149/20 # 5GHz ch 149, 20MHz",
.func = &cmd_mode_monitor,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_monitor));
const esp_console_cmd_t mode_sta = {
.command = "mode_sta",
.help = "Switch to STA mode (CSI + iperf)\n"
" STA mode supports 20MHz and 40MHz (full hardware support)\n"
" Usage: mode_sta [band]\n"
" Band: 2.4, 5, auto (default)\n"
" Examples:\n"
" mode_sta # Auto band selection\n"
" mode_sta 2.4 # Connect on 2.4GHz only\n"
" mode_sta 5 # Connect on 5GHz only",
.func = &cmd_mode_sta,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_sta));
const esp_console_cmd_t mode_status = {
.command = "mode_status",
.help = "Show current WiFi mode and status",
.func = &cmd_mode_status,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&mode_status));
const esp_console_cmd_t csi_dump = {
.command = "csi_dump",
.help = "Dump CSI data to UART (STA mode only)",
.func = &cmd_csi_dump,
};
ESP_ERROR_CHECK(esp_console_cmd_register(&csi_dump));
ESP_LOGI(TAG, "Mode switch commands registered:");
ESP_LOGI(TAG, " mode_monitor [ch/bw] - Switch to monitor mode with bandwidth");
ESP_LOGI(TAG, " mode_sta [band] - Switch to STA mode with band preference");
ESP_LOGI(TAG, " mode_status - Show current mode");
ESP_LOGI(TAG, " csi_dump - Dump CSI data");
}
// --- Event Handler (Connection Logic) ------------------------------
@ -226,37 +679,62 @@ static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) {
if (event_base == WIFI_EVENT) {
if (event_id == WIFI_EVENT_STA_START) {
if (has_config) current_led_state = LED_STATE_WAITING;
if (has_config && current_wifi_mode == WIFI_MODE_STA_CSI) {
current_led_state = LED_STATE_WAITING;
}
}
else if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
ESP_LOGW(TAG, "WiFi Disconnected (Reason: %d)", event->reason);
if (!wifi_connected && has_config) current_led_state = LED_STATE_FAILED;
if (!wifi_connected && has_config && current_wifi_mode == WIFI_MODE_STA_CSI) {
current_led_state = LED_STATE_FAILED;
}
wifi_connected = false;
}
}
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
if (current_wifi_mode != WIFI_MODE_STA_CSI) {
ESP_LOGW(TAG, "Got IP but not in STA mode (mode changed during connection)");
return;
}
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
ESP_LOGI(TAG, "========================================");
wifi_connected = true;
current_led_state = LED_STATE_CONNECTED;
// Sequence: 1. Start CSI, 2. Start Monitor, 3. Start Iperf
xTaskCreate(csi_init_task, "csi_init", 4096, NULL, 5, NULL);
// DEFAULT MODE: Start CSI + iperf (STA mode)
ESP_LOGI(TAG, "Starting STA mode services...");
vTaskDelay(pdMS_TO_TICKS(2000));
xTaskCreate(monitor_init_task, "monitor_init", 4096, NULL, 5, NULL);
// 1. Enable CSI
ESP_LOGI(TAG, "Enabling CSI...");
wifi_enable_csi_once();
// 2. Start iperf server
vTaskDelay(pdMS_TO_TICKS(1000));
iperf_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.flag = IPERF_FLAG_SERVER | IPERF_FLAG_TCP;
cfg.sport = 5001;
iperf_start(&cfg);
ESP_LOGI(TAG, "iperf TCP server started on port 5001");
ESP_LOGI(TAG, "iperf TCP server started on port 5001");
// Optional: Dump CSI data later
// 3. Optional: Schedule CSI dump for later
xTaskCreate(csi_dump_task, "csi_dump_task", 4096, NULL, 5, NULL);
ESP_LOGI(TAG, "✓ STA mode active");
ESP_LOGI(TAG, " - CSI capture enabled");
ESP_LOGI(TAG, " - iperf server running");
ESP_LOGI(TAG, " - LED: Green");
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "Console commands available:");
ESP_LOGI(TAG, " mode_monitor [ch] - Switch to monitor mode");
ESP_LOGI(TAG, " mode_status - Show current status");
ESP_LOGI(TAG, " csi_dump - Dump CSI data now");
ESP_LOGI(TAG, "========================================");
}
}
@ -274,10 +752,14 @@ void app_main(void) {
rgb_led_init();
xTaskCreate(led_task, "led_task", 4096, NULL, 5, NULL);
// 4. Initialize GPS (The new addition!)
// We do this EARLY so timestamps are ready when WiFi events happen
ESP_LOGI(TAG, "Starting GPS Sync...");
gps_sync_init(true); // true = Use GPS for system log timestamps
// 4. Initialize GPS (Enable GPS-timestamped logs)
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "Initializing GPS sync...");
gps_sync_init(true); // true = GPS timestamps for ESP_LOG
ESP_LOGI(TAG, "GPS initialized");
ESP_LOGI(TAG, " - Waiting for GPS lock...");
ESP_LOGI(TAG, " - Timestamps: (*) = not synced, (+) = GPS synced");
ESP_LOGI(TAG, "========================================");
// 5. Register WiFi Events
ESP_ERROR_CHECK(esp_event_handler_instance_register(
@ -288,23 +770,105 @@ void app_main(void) {
// 6. Initialize WiFi Configuration
wifi_cfg_init();
// 7. Initialize Serial Console (CRITICAL for console commands)
ESP_LOGI(TAG, "Initializing console...");
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Initialize the console */
esp_console_config_t console_config = {
.max_cmdline_args = 8,
.max_cmdline_length = 256,
#if CONFIG_LOG_COLORS
.hint_color = atoi(LOG_COLOR_CYAN)
#endif
};
ESP_ERROR_CHECK(esp_console_init(&console_config));
/* Configure linenoise line completion library */
linenoiseSetMultiLine(1);
linenoiseSetCompletionCallback(NULL);
linenoiseSetHintsCallback(NULL);
linenoiseHistorySetMaxLen(100);
/* Register help command */
esp_console_register_help_command();
ESP_LOGI(TAG, "✓ Console initialized");
// 8. Register Console Commands for Mode Switching
register_mode_commands();
// 9. Apply WiFi config and connect
if (wifi_cfg_apply_from_nvs()) {
has_config = true;
current_led_state = LED_STATE_WAITING;
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "WiFi config loaded. Connecting...");
// Check if device is configured for MONITOR mode
char mode[16] = {0};
uint8_t mon_ch = 36;
if (wifi_cfg_get_mode(mode, &mon_ch)) {
if (strcmp(mode, "MONITOR") == 0) {
ESP_LOGI(TAG, "MODE: MONITOR (collapse detection)");
ESP_LOGI(TAG, "Monitor Channel: %d", mon_ch);
ESP_LOGI(TAG, "Will switch to monitor mode after WiFi connects...");
// Allocate channel parameter for task
uint8_t *ch_param = malloc(sizeof(uint8_t));
*ch_param = mon_ch;
// Create task to switch to monitor mode after connection
xTaskCreate(auto_monitor_task, "auto_monitor", 4096, ch_param, 5, NULL);
} else {
ESP_LOGI(TAG, "MODE: STA (CSI + iperf)");
}
} else {
ESP_LOGI(TAG, "DEFAULT MODE: STA (CSI + iperf)");
}
ESP_LOGI(TAG, "========================================");
} else {
has_config = false;
current_led_state = LED_STATE_NO_CONFIG;
ESP_LOGI(TAG, "No WiFi config found. Yellow LED.");
ESP_LOGI(TAG, "Use CLI 'wifi_config_set <ssid> <pass>' to configure.");
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "No WiFi config found.");
ESP_LOGI(TAG, "LED: Yellow");
ESP_LOGI(TAG, "Use CLI command: wifi_config_set <ssid> <pass>");
ESP_LOGI(TAG, "========================================");
}
// 7. Loop forever (Logic is handled by tasks and events)
while(1) {
vTaskDelay(pdMS_TO_TICKS(1000));
// Optional: Print GPS status occasionally
if (!gps_is_synced()) {
// ESP_LOGI(TAG, "Waiting for GPS lock...");
}
}
ESP_LOGI(TAG, "========================================");
ESP_LOGI(TAG, "Initialization complete");
ESP_LOGI(TAG, "Console commands available (no interactive prompt)");
ESP_LOGI(TAG, "========================================");
// app_main() returns - device runs autonomously
}
// --- Auto-Monitor Mode Task (switches to monitor mode after WiFi connects) ---
static void auto_monitor_task(void *arg) {
uint8_t channel = *(uint8_t*)arg;
free(arg); // Free the allocated channel parameter
// Wait for WiFi connection (LED will be green)
ESP_LOGI(TAG, "Waiting for WiFi connection before switching to monitor mode...");
while (current_led_state != LED_STATE_CONNECTED) {
vTaskDelay(pdMS_TO_TICKS(500));
}
// Wait additional 2 seconds for GPS sync
ESP_LOGI(TAG, "WiFi connected, waiting for GPS sync...");
vTaskDelay(pdMS_TO_TICKS(2000));
ESP_LOGI(TAG, "Auto-switching to MONITOR mode on channel %d...", channel);
esp_err_t err = switch_to_monitor_mode(channel, WIFI_BW_HT20);
if (err == ESP_OK) {
ESP_LOGI(TAG, "✓ Monitor mode activated");
} else {
ESP_LOGE(TAG, "✗ Failed to switch to monitor mode: %s", esp_err_to_name(err));
}
vTaskDelete(NULL);
}

View File

@ -1,6 +1,6 @@
# partitions_csi.csv
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xF000, 0x1000,
factory, app, factory, 0x10000, 0x100000,
csi_log, data, 0x40, 0x110000, 0x0F0000,
nvs, data, nvs, , 0x6000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 2M,
csi_log, data, 0x40, , 0x5F0000,

1 # partitions_csi.csv
2 # Name, Type, SubType, Offset, Size, Flags # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0x9000, 0x6000, nvs, data, nvs, , 0x6000,
4 phy_init, data, phy, 0xF000, 0x1000, phy_init, data, phy, , 0x1000,
5 factory, app, factory, 0x10000, 0x100000, factory, app, factory, , 2M,
6 csi_log, data, 0x40, 0x110000, 0x0F0000, csi_log, data, 0x40, , 0x5F0000,