Dual-board wardriving setup based on XIAO ESP32-C5 + XIAO ESP32-C6 + GPS + SD.
xiao_c6/- firmware for XIAO ESP32-C6 (GPS bridge)xiao_c5/- firmware for XIAO ESP32-C5 (Wi-Fi scanner + SD logger, WiGLE CSV)
| C6 | C5 | Description |
|---|---|---|
D0 (TX, GPIO0) |
D1 (RX, GPIO0) |
GPS data from C6 -> C5 |
D1 (RX, GPIO1) |
D0 (TX, GPIO1) |
optional (2-way communication) |
GND |
GND |
required |
Do not connect 5V <-> 5V if both boards are powered separately via USB.
| GPS | C6 |
|---|---|
TX |
D7 (RX) |
RX |
D6 (TX) (optional) |
GND |
GND |
VCC |
3V3 (if your GPS module supports it) |
| SD | C5 |
|---|---|
SCK |
D8 (GPIO8) |
MISO |
D9 (GPIO9) |
MOSI |
D10 (GPIO10) |
CS |
D2 (GPIO25) |
GND |
GND |
VCC |
3V3 or according to your SD module specs |
40x60 proto pcb
MakerWorld project - dedicated WarMachine enclosure
- parses GPS NMEA (
RMC/GGA), - sends GPS to C5 once per second:
GPS,msgMs,lat,lon,alt,sats,hdop,date,time,valid - scans 2.4 GHz in promiscuous mode,
- sends discovered 2.4 GHz APs to C5:
AP24,msgMs,bssid,channel,rssi,authmode,ssidHex
- waits for SD mount (with retries),
- waits for valid GPS fix from C6,
- starts wardrive engine (
promiscmode by default, C5 scans 5 GHz only), - receives 2.4 GHz AP records from C6 and attaches the current GPS fix,
- deduplicates APs by BSSID in RAM,
- writes WiGLE-compatible data to
/sdcard/wardrive.csvin periodic batches, - pauses logging when GPS fix is lost and auto-resumes after fix recovery.
- C6 handles 2.4 GHz only:
- primary channels
1/6/11:160 msdwell, - secondary channels
2/3/4/5/7/8/9/10/12/13:100 msdwell, - first full 2.4 GHz sweep: about
1.48 s.
- primary channels
- C5 handles 5 GHz only:
- non-DFS channels
36/40/44/48/149/153/157/161/165:120 msdwell, - DFS/extended channels
52-144/169/173/177:90 msdwell, - first full 5 GHz sweep: about
2.79 s.
- non-DFS channels
- Both scanners use discounted UCB channel selection after the first sweep, so busy channels get revisited more often while quiet channels still get sampled.
- C5 re-logs already-known APs after a
5 dBmRSSI change or about25 mmovement, which keeps WiGLE trilateration useful without flooding the CSV.
Use commands in ESP-IDF monitor (idf.py monitor):
helpstatusmode readmode set promiscmode set scanchannel_time read min|maxchannel_time set min|max <ms>
Notes:
mode promiscuses fast 5 GHz channel hopping + dedup on C5; 2.4 GHz arrives from C6.mode scanuses classic active scan (esp_wifi_scan_start) over 5 GHz channels only with configurablechannel_time.channel_timevalues are persisted in NVS.
- ESP-IDF
v5.x - VS Code + Espressif IDF extension (recommended)
- Two USB data cables
Repeat separately for xiao_c6 and xiao_c5.
- Open the board folder in VS Code (
File -> Open Folder):- for C6:
xiao_c6 - for C5:
xiao_c5
- for C6:
- In ESP-IDF extension:
Set Espressif Device Target- choose
esp32c6for C6 oresp32c5for C5
- Run:
BuildFlashMonitor
Expected monitor logs:
- C6:
C6 GPS bridge started - C5:
Stage 1/4: waiting for SD card mountStage 2/4: waiting for valid GPS fix from C6Stage 3/4: init NVS + Wi-FiStage 4/4: starting wardrive engine (C5=5GHz promisc, C6=2.4GHz AP24 ingest)
cd xiao_c6
idf.py set-target esp32c6
idf.py build
idf.py -p /dev/cu.usbmodemXXXX flash monitorcd xiao_c5
idf.py set-target esp32c5
idf.py build
idf.py -p /dev/cu.usbmodemYYYY flash monitor- Power both boards.
- Place GPS outdoors and wait for fix.
- Verify
wardrive.csvappears on SD card and grows over time.