fix(esp32): el boton activo a nivel bajo — que lo decida el circuito, no una constante

El canvas reenviaba la pulsacion de un pulsador cableado como
sendPinEvent(gpio, true), o sea "pulsado = ALTO". Para el idiom canonico de
Arduino — pin -> pulsador -> GND con INPUT_PULLUP, activo a nivel BAJO, que usan
13 de los 18 ejemplos con entrada de usuario — eso esta al reves: pulsar conducia
el pin a su nivel de REPOSO y soltarlo al ACTIVO. Ademas escribia directamente en
el latch de entrada del emulador por detras de connectDigitalInputsToMcu,
desincronizando la cache lastLevel de la que ese fichero se declara unico
escritor. La victima visible era esp32-doom: cuatro botones que hacian lo
contrario de lo que pulsabas.

No lo sustituyo por la polaridad opuesta, que seria la misma adivinanza al reves:
cuando el simulador resuelve entradas por el circuito (spiceDrivenInputs), el
nivel sale del propio cableado. El INPUT_PULLUP del guest se reporta ahora como
gpio_pull, estampa una resistencia de 45k al riel de 3V3, y cerrar el pulsador
cortocircuita el nodo contra la pata que tenga al otro lado. Sale bien tanto para
un boton a GND como para uno a 3V3, sin que nadie asuma nada. El atajo se queda
solo para simuladores que se salgan del modelo electrico.

Aparte, dos arreglos de cableado:

  - boardPinToNumber devuelve -1 (no null) para pines de alimentacion y masa, y
    la guarda comprobaba `=== null`. Asi que la pata de GND de cada boton colaba
    y registraba un SEGUNDO par de listeners apuntando al pin -1.

  - c3-button y pico-button-led cableaban sus pulsadores a los pines '1a' y '1b',
    que NO EXISTEN: el wokwi-pushbutton expone 1.l, 2.l, 1.r y 2.r. Esos dos
    cables llevaban colgando desde siempre, asi que esos botones no han
    funcionado nunca. Pasan a 1.l / 2.l, como el resto de ejemplos.
This commit is contained in:
David Montero Crespo 2026-07-26 23:31:47 +02:00
parent a698534b7b
commit 715e93c610
2 changed files with 27 additions and 7 deletions

View File

@ -1298,7 +1298,10 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => {
const boardInstance = boards.find((b) => b.id === boardId);
const lookupKey = boardInstance ? boardInstance.boardKind : boardId;
const gpioPin = boardPinToNumber(lookupKey, otherEndpoint.pinName);
if (gpioPin === null) return;
// boardPinToNumber returns -1 (not null) for power/ground pins, so a `=== null`
// guard let every button's GND leg through and registered a SECOND listener pair
// aimed at pin -1.
if (gpioPin === null || gpioPin < 0) return;
// Delay lookup so the web component has time to render
const timeout = setTimeout(() => {
@ -1306,8 +1309,25 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => {
if (!el) return;
const tag = el.tagName.toLowerCase();
// Push-button: forward press/release as GPIO level changes
if (tag === 'wokwi-pushbutton') {
// Push-button: forward press/release as GPIO level changes.
//
// ONLY for simulators that opt out of the electrical solve. This shortcut
// hardcodes "pressed = HIGH", which is backwards for the canonical Arduino
// button (pin -> switch -> GND with INPUT_PULLUP, active-LOW) — pressing drove
// the pin to its IDLE level and releasing drove it to the ACTIVE one. It also
// wrote straight into the emulator's input latch behind connectDigitalInputsToMcu's
// back, desyncing the lastLevel cache that file documents itself as the sole
// writer of. esp32-doom was the visible casualty: four active-low buttons that
// did the opposite of what you pressed.
//
// When spiceDrivenInputs is set, the button's level comes from the circuit
// instead: the guest's own INPUT_PULLUP (reported as a gpio_pull) stamps a 45k
// pull-up to the 3V3 rail, and closing the switch shorts the net to whatever its
// other leg is wired to. That gets the polarity right from the wiring rather
// than assuming it, and works the same for a button wired to 3V3.
const spiceDriven = (getBoardSimulator(boardId) as { spiceDrivenInputs?: boolean } | null)
?.spiceDrivenInputs;
if (tag === 'wokwi-pushbutton' && !spiceDriven) {
const onPress = () => bridge.sendPinEvent(gpioPin, true);
const onRelease = () => bridge.sendPinEvent(gpioPin, false);
el.addEventListener('button-press', onPress);

View File

@ -5981,7 +5981,7 @@ void loop() {
{
id: 'c3-bw1',
start: { componentId: 'arduino-uno', pinName: '9' },
end: { componentId: 'c3-btn1', pinName: '1a' },
end: { componentId: 'c3-btn1', pinName: '1.l' },
color: '#00aaff',
},
{
@ -5998,7 +5998,7 @@ void loop() {
},
{
id: 'c3-bw4',
start: { componentId: 'c3-btn1', pinName: '1b' },
start: { componentId: 'c3-btn1', pinName: '2.l' },
end: { componentId: 'arduino-uno', pinName: 'GND.9' },
color: '#000000',
},
@ -6509,7 +6509,7 @@ void loop() {
{
id: 'pb-btn',
start: { componentId: 'arduino-uno', pinName: 'GP2' },
end: { componentId: 'pico-btn1', pinName: '1a' },
end: { componentId: 'pico-btn1', pinName: '1.l' },
color: '#00aaff',
},
{
@ -6526,7 +6526,7 @@ void loop() {
},
{
id: 'pb-btn-gnd',
start: { componentId: 'pico-btn1', pinName: '1b' },
start: { componentId: 'pico-btn1', pinName: '2.l' },
end: { componentId: 'arduino-uno', pinName: 'GND.1' },
color: '#000000',
},