fix(micropython): sleepy isconnected()/status() — busy-waits starved idleSkip

The canonical MicroPython connect idiom is `while not wlan.isconnected():
pass` — a pure Python busy-wait, and most gallery WiFi examples use it.
The emulated CPU only fast-forwards through WAITI idles, so a busy-wait
pins the sim at real execution speed (~2% of the chip in a browser tab).
Measured on the classic-ESP32 engine with a marker-bracketed harness: the
connect+DHCP phase costs ~1.5M busy instructions under a sleepy poll loop
and ~194M under the busy-wait — same firmware, same radio, 130x apart.
At browser speed that is close to a minute of wall clock for the connect
alone, which reads as "WiFi hangs" and got diagnosed as exactly that.

The proxy now sleeps 20ms per unanswered isconnected()/status() poll,
turning the user's busy loop into an idle loop without touching their
code. Re-measured end-to-end with the real prelude: 226.8M -> 64.3M busy
steps, and the made-up-SSID example connects with a 10.13.37.x lease on
the in-browser engine.
This commit is contained in:
David Montero Crespo 2026-08-10 22:58:30 +02:00
parent d527b1839c
commit f03f80d1b3
1 changed files with 18 additions and 0 deletions

View File

@ -2042,6 +2042,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
// debugs a connection they didn't make.
const networkStub = wifiOn ? [
'import network as _vlx_net',
'import time as _vlx_time',
'_VLX_SSIDS = ("Velxio-GUEST", "PICSimLabWifi", "Espressif", "MasseyWifi")',
'class _VlxWLAN:',
' def __init__(self, *a, **k):',
@ -2053,6 +2054,23 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
' if ssid is None:',
' return self._w.connect()',
' return self._w.connect(ssid, key, **kw)',
// The sleepy poll pair. The canonical connect idiom is
// `while not wlan.isconnected(): pass` — a pure Python busy-wait.
// The emulated CPU only fast-forwards through WAITI idles, so a
// busy-wait pins the sim at real execution speed (~2% of the
// chip) and the handshake that costs ~1.5M instructions under a
// sleepy loop costs ~194M under a busy one — measured; it reads
// as "WiFi hangs". Sleeping 20ms per unanswered poll turns the
// user's busy loop into an idle loop without touching their code.
' def isconnected(self):',
' ok = self._w.isconnected()',
' if not ok:',
' _vlx_time.sleep_ms(20)',
' return ok',
' def status(self, *a):',
' st = self._w.status(*a)',
' _vlx_time.sleep_ms(20)',
' return st',
' def __getattr__(self, n):',
' return getattr(self._w, n)',
'class _VlxNetwork:',