A C/ESP-IDF port of the PyWiSim minimalist wireless protocol API to ESP32-C3 boards using ESP-NOW.
PyWiSim is a sub-50-line Python simulator for teaching distributed wireless
protocols. This repo brings that same tiny broadcast / unicast / schedule
API to real radios so the same six teaching examples run on a handful of
ESP32-C3 boards on your desk.
// the entire API surface
int wisim_begin(const wisim_config_t *cfg);
int wisim_broadcast(const uint8_t *data, size_t len);
int wisim_unicast(char dest_nid, const uint8_t *data, size_t len);
int wisim_schedule(uint32_t delay_ms, void (*cb)(void *), void *arg);
char wisim_self(void);
void wisim_log(const char *fmt, ...);Single-character node IDs ('A'..'Z') keep example code readable. The same
firmware image is flashed to every board — each board figures out which NID
it is at boot from its MAC.
| folder | protocol | boards | source |
|---|---|---|---|
00_hello |
broadcast smoke test | 2+ | (this repo) |
01_flooding |
reliable broadcast via flood + dedup | 2–5 | PyWiSim flooding.py |
02_echo |
spanning-tree construction | 3+ | PyWiSim echo.py |
03_aodv |
reactive route discovery | 3+ | PyWiSim aodv.py |
04_consensus |
flood-and-majority binary consensus | 3+ | PyWiSim consensus.py |
05_leader_election |
flood-based extrema election | 3+ | PyWiSim leader_election.py |
06_two_phase_commit |
classic 2PC with one NO-voter | 4 | PyWiSim two_phase_commit.py |
- 2–6 ESP32-C3 boards (more for
02_echo,03_aodv,06_two_phase_commit). - USB cables, one host machine.
# 1. Install ESP-IDF v5.1+ (https://docs.espressif.com/projects/esp-idf/en/v5.1/esp32c3/get-started/)
. $HOME/esp/esp-idf/export.sh
# 2. Read each board's MAC. Plug board, then:
cd tools/print_mac
idf.py set-target esp32c3
idf.py -p <PORT> flash monitor # look for "BOARD_MAC=xx:xx:xx:xx:xx:xx"
# 3. Edit components/wisim/node_table.c — fill in the real MACs you collected,
# one NID per board. Keep zeros for slots you don't have hardware for.cd examples/01_flooding
idf.py set-target esp32c3
idf.py build
idf.py -p <PORT_FOR_BOARD_A> flash # flash same binary to every board
idf.py -p <PORT_FOR_BOARD_A> monitor # watch its serialOpen one terminal per board for parallel monitoring. The firmware reads the MAC at boot and runs the role for that NID — no per-board source forks.
ESP-NOW range is many meters indoors, so all your boards on one table form a
fully-connected mesh — which makes multi-hop demos (echo, AODV) trivial in a
boring way. Set cfg.rssi_threshold = -50 (or similar) in an example's
app_main to drop weak peers and force the topology you want. Move boards
closer/farther to shape it.
| PyWiSim | This port |
|---|---|
| Distance-based packet loss model | Real radio + optional RSSI threshold |
tx_range sets neighbor set |
All peers in node_table.c are reachable; use RSSI threshold to constrain |
Tuple messages ('RREQ', ...) |
Packed C structs with a leading type byte |
| Seeded determinism | Non-deterministic radio; examples don't rely on exact ordering |
MobilityManager, EncounterManager |
Not ported (would need physically moving boards) |
See docs/porting_notes.md for per-example details.
cd host_sim && make checkCompiles every example with stub wisim/esp APIs. Catches C errors without needing the ESP-IDF toolchain. Behavior is verified on real boards, not here.
Bhaskar Krishnamachari (USC) — primary contributor.
Built on the API design of ANRGUSC/PyWiSim. Ported with Claude Code.
PolyForm Noncommercial 1.0.0 — same as the upstream PyWiSim.