diff --git a/components/wifi_cfg/wifi_cfg.c b/components/wifi_cfg/wifi_cfg.c index 1a3ad96..a957d8f 100644 --- a/components/wifi_cfg/wifi_cfg.c +++ b/components/wifi_cfg/wifi_cfg.c @@ -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 Wi‑Fi 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); } } diff --git a/components/wifi_cfg/wifi_cfg.h b/components/wifi_cfg/wifi_cfg.h index af649a8..6bc4f35 100644 --- a/components/wifi_cfg/wifi_cfg.h +++ b/components/wifi_cfg/wifi_cfg.h @@ -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) * diff --git a/config_device.py b/config_device.py index afb1f63..f5584de 100755 --- a/config_device.py +++ b/config_device.py @@ -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 ) diff --git a/doc/BANDWIDTH_BAND_SELECTION_GUIDE.md b/doc/BANDWIDTH_BAND_SELECTION_GUIDE.md new file mode 100644 index 0000000..1cefdb6 --- /dev/null +++ b/doc/BANDWIDTH_BAND_SELECTION_GUIDE.md @@ -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 / +``` + +### 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 / # 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! diff --git a/doc/CONFIG_DEVICE_MANUAL.txt b/doc/CONFIG_DEVICE_MANUAL.txt new file mode 100644 index 0000000..37aeb8a --- /dev/null +++ b/doc/CONFIG_DEVICE_MANUAL.txt @@ -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 diff --git a/doc/QUICK_REFERENCE.md b/doc/QUICK_REFERENCE.md new file mode 100644 index 0000000..98b4e3e --- /dev/null +++ b/doc/QUICK_REFERENCE.md @@ -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! diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 3f524ad..6e0d920 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -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 ) diff --git a/main/main.c b/main/main.c index b240ca9..e4a9a0a 100644 --- a/main/main.c +++ b/main/main.c @@ -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 ' 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 "); + 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); } diff --git a/partitions.csv b/partitions.csv index 5b549c5..97cd7ef 100644 --- a/partitions.csv +++ b/partitions.csv @@ -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, +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 2M, +csi_log, data, 0x40, , 0x5F0000,