Skip to content

Latest commit

 

History

History
94 lines (68 loc) · 3.7 KB

File metadata and controls

94 lines (68 loc) · 3.7 KB

Porting notes: PyWiSim → ESP-NOW

API mapping

PyWiSim (Python) espnow-protocols (C)
class Node: on_receive(msg, sender) void on_recv(char sender, const uint8_t *data, size_t)
self.broadcast(msg) wisim_broadcast(buf, len)
self.unicast(dest, msg) wisim_unicast(dest_nid, buf, len)
self.schedule(delay, fn, *args) wisim_schedule(delay_ms, cb, arg)
self.net.log(...) wisim_log("...")
WirelessNetwork(tx_range=..., loss=..) real radio; rssi_threshold to restrict reach
loop.run(until=...) firmware runs forever

Message representation

Python tuples like ('RREQ', orig, dest, seq, rid, hops) become packed C structs with a leading type byte:

typedef struct __attribute__((packed)) {
    uint8_t  type;
    char     orig;
    char     dest;
    uint16_t seq;
    uint16_t rid;
    uint8_t  hops;
} rreq_t;

on_recv switches on data[0] (the type byte) and casts to the right struct. Keep all message types under 240 bytes (ESP-NOW limits frames to 250 with some header overhead).

Node IDs

Python uses arbitrary strings ('A', 'P1', etc.). We use a single char to keep code terse and let us index state arrays directly by NID. Conventions:

  • 'A'..'F' for line / mesh topologies.
  • 'C' = coordinator, 'P','Q','R' = participants in two-phase commit (renamed from PyWiSim's P1/P2/P3).

Per-example notes

01_flooding

Direct port. seen set → bool g_seen[256]. The Python version increments the seen set on first receipt to suppress re-broadcast; same here.

02_echo

Neighbor enumeration differs: PyWiSim asks the simulator for nodes in range. In our port, "neighbors" = every NID in node_table.c that has a non-zero MAC. To get a real multi-hop tree on a single desk, set cfg.rssi_threshold to drop weak peers.

03_aodv

The seen_rreqs set is a fixed-size ring (SEEN_CAP=32). For longer runs or larger networks, increase it. Routing table is an array indexed by NID — wastes memory but is trivially fast and bounded.

Sequence-number rollover is not handled (would matter for a multi-hour run with many discoveries).

04_consensus, 05_leader_election

randomesp_random(). Stagger first broadcast by (self - 'A') * 200ms so the serial console isn't a wall of simultaneous output.

06_two_phase_commit

Renamed participants P1/P2/P3P/Q/R (single-char NIDs). 'R' is the NO-voter to force ABORT, matching the Python example's third participant.

Things not ported

  • Mobility (mobility.py) — would need physically moving boards.
  • Encounters / DTN (encounter.py) — same.
  • Distance-based loss model — replaced by RSSI threshold (a coarser knob; configurable per-example via wisim_config_t.rssi_threshold).
  • Carrier-sense backoff — the ESP-NOW stack does its own MAC-layer arbitration; the PyWiSim CSMA simulation isn't relevant here.

Threading model

ESP-NOW recv callbacks fire in a restricted context (cannot call esp_now_send from inside). We funnel every recv and timer event through a FreeRTOS queue drained by a dedicated dispatcher task, so example code can freely call wisim_broadcast / wisim_unicast / wisim_schedule from inside on_recv.

This matches the PyWiSim convention where on_receive can immediately call broadcast etc. — same mental model.