Commit Graph

2 Commits

Author SHA1 Message Date
David Montero 8f148e836d fix(sim): a net is a set of pins, and a part's own line belongs to the part
Hardening pass on 57325aa, which fixed the reported HC-SR04 divider but did it
by returning the first answer any branch produced. Five topologies people
really draw break under that rule, and each one now has a test that fails on
57325aa and passes here:

  - a ground tie point almost always carries something else (a button's
    pull-down). Reaching a rail has to END the walk, or a grounded pin resolves
    to whatever GPIO that pull-down hangs off. Same through a breadboard rail;
  - two custom chips on one wire stopped sharing a chipbus net key, because a
    nested frame answered with its own neighbour's per-endpoint key before the
    root could mint the net-canonical one;
  - a chip one hop away ended the search before a real GPIO on the same node
    was ever looked at;
  - a node first reached deep, where the hop budget cut it short, was never
    re-walked when a shorter route arrived.

So the walk now models what a net IS. It collects the whole NODE (every pin
joined without crossing a component: the wires, and a breadboard strip's
holes), then judges the set: a driven pad wins outright; a supply pad means the
node IS the rail and the walk stops there; only then does it cross a passive to
the next node, where a rail is the weaker answer that lets a level-shifted
sensor resolve. Wires, components and breadboard groups are indexed per store
array, and a driven pad short-circuits collection — the common case is now
0.08 ms/pin on a 300-wire canvas, better than before this work started, with
the shared-rail worst case at ~2 ms.

Second half: a part that models its own line keeps it, on every board.
connectDigitalInputsToMcu thresholds the solved node into every input pin, and
its `sourcedNets` gate only ever protected part-driven lines by accident — it
holds while no component sits on the net, and stops the moment the user adds
the pull-up or the divider real hardware needs. Then the connector pins the
line an HC-SR04 or a DHT22 is answering on. simulation/partPinOwnership records
what each part drives (implicitly, through the simulator it is handed) and the
connector skips those pins; the ESP32 bridge answers the same question for
sensors the backend or an engine emulates, through a new optional `ownsPin`
seam. Parts SPICE can describe never claim anything, so a mis-wired button
still reads stuck — that property is why spiceDrivenInputs exists.

Also: setSensors merges per FIELD, so the coarser registration path can no
longer drop the finer one's echo_pin; the ESP32 bridge's guard is narrowed to
the single-wire sensor types, since an ePaper's DC pin or a keypad row must
stay drivable; and the Mega and Pico W pin maps get the supply-pad guard the
other boards have, where '5V' parsed as D5 and '3V3' as D3.

Verified in a browser against a local build of this tree, driving the real app:
HC-SR04 and DHT22, direct wiring and level-shifted, on Uno (avr8js), Pico
(rp2040js), ESP32 (esp32js and QEMU) and ESP32-S3 (esp32s3js) — see
scripts/sensor-wiring-matrix.mjs in velxio-prod.
2026-08-23 01:23:41 +02:00
David Montero 57325aa9a9 fix(sim): a resistor divider on a sensor line made the board pin invisible
An HC-SR04 on an ESP32-S3 answered "No echo" forever the moment its ECHO
went through the 1k/2k2 divider a real 5 V sensor needs, and worked again
when the divider came out (reported on Discord, project esp32-s3-distance).
Nothing about the divider is wrong: three separate resolvers could not see
past it.

1. The wire walk treated a net as a chain. Arriving at the divider's tap it
   hopped straight across the lower resistor, hit GND, and answered "tied to
   a rail" (-1) — never looking at the OTHER wire on that same tap, where
   GPIO41 was. A rail was also allowed to end the search, so a plain pull-up
   drawn before the signal wire hid the GPIO behind it the same way. The walk
   now explores the whole node (same depth, one shared visited set) and
   treats a supply pad as the weakest answer: remembered, returned only when
   no driven pin was found anywhere.

2. The walk moved to simulation/PinTrace so the store can ask the same
   question. It pre-registered backend sensors with its own single-wire
   lookup — one wire, far end must be a board — so ECHO (landing on a
   resistor) resolved to nothing. That entry REPLACES the part's, keyed by
   pin, so the echo pin was silently dropped and the QEMU worker fell back to
   TRIG+1: it pulsed GPIO22, which nobody was reading. Both the data pin and
   the extra pins now resolve through the shared walk, so a sensor behind a
   breadboard strip or a divider registers like any other.

3. Esp32Bridge.sendPinEvent now refuses a pad a registered sensor owns, the
   guard the in-browser engines already have. connectDigitalInputsToMcu
   thresholds the solved node, and `sourcedNets` does not hold it back once
   real components sit on the net — the divider makes ECHO exactly that, and
   it solves at ~0 V because nothing models the sensor's output.

Test covers the reported circuit end to end: the walk, and the echo_pin that
reaches the start_esp32 payload.
2026-08-22 23:31:23 +02:00