Files
Jeff Luke c1b2195834 Expand Glitch operations hub, cabinet authoring, deployment, and RFID support
Operator hub
- Introduce Escape Gallery branding and Glitch: the Dark Machine room views
- Add cabinet illustrations, Pac-Man marquee/gameplay artwork, and waiting states
- Add device feedback panels with RFID readings, input/output states, and stale status
- Add logged operator hardware interventions with request deduplication

Room and cabinet authoring
- Add a visual custom-PCB connection editor with per-cabinet device inventory
- Support device IDs, bindings, wiring notes, input polarity, and validation
- Add physical-room label/dimension toggles and editable doorway annotations
- Preserve doorway changes through undo, save, and revert
- Expand cabinet profiles, room layout, and Glitch scenario resources

Scenarios and gameplay
- Add per-assignment game configuration and runtime feature validation
- Add timed test wins and Frogger individual-home objectives
- Add the three-cabinet timed/score/Frogger test scenario
- Add Cabinet 1 Pac-Man RFID credits, credit sound, and CREDIT 0/1 display
- Require physical Start after an accepted scan and prevent duplicate credits

Pi hardware and deployment
- Add GPIO feedback sampling and a separate multiplexed RFID helper
- Validate reader pin ownership and input/output conflicts
- Add SSH cabinet startup and Pi desktop-session service support
- Add master packaging, site setup, SSH enrollment, and staged cabinet releases
- Verify deployment manifests and support explicit activation/status/log commands

Documentation and verification
- Consolidate the root README around the current architecture and setup workflow
- Add the complete master/Pi/RFID export and deployment walkthrough
- Document network isolation, credentials, card identification, and rollback
- Add PCB, room-editor, feedback, credit, deployment, and controller tests
- Isolate protocol tests from designer-edited cabinet configurations

Known limitations
- RFID helper compilation and physical Pi commissioning remain unverified
- Fleet provisioning does not yet configure RFID-only installations completely
- Broader Pac-Man tests retain a ghost-capture assertion failure
- Staged exports must be rebuilt and checked before deploying runtime 2.3
2026-10-17 14:53:54 -07:00

9.2 KiB
Raw Permalink Blame History

Real GPIO on the Raspberry Pi

After completing the hardware setup below, the stack launch scripts can start the bridge and managed cabinet together.

The former HardwareManager only logged [MOCK GPIO]; it could not light an LED. The standalone launcher also did not forward game events to hardware. Both paths are now connected. GPIO numbers in HardwareAction resources are BCM numbers, not physical header positions.

1. Wire the LED (Pi powered off)

For a typical small red LED:

physical pin 11 (BCM GPIO17) -> 330–470 ohm resistor -> LED anode (long leg)
LED cathode (short leg / flat side) -> physical pin 6 (GND)

Keep the LED's legs in different breadboard rows. The resistor must be in series, not bypassed by another wire. Physical pin 17 is 3.3V power, not GPIO17. Do not use the 5V rail for this test. GPIO is 3.3V logic; coin dispensers, relay coils and other powered loads require an appropriate driver, not a direct GPIO connection.

Pinout and LED reference: GPIO Zero recipes.

2. Install dependencies on the Pi

Use a current Raspberry Pi OS installation and its packaged GPIO Zero/lgpio support (Pi 4 or Pi 5):

sudo apt update
sudo apt install python3-gpiozero python3-lgpio

The account running the helper needs access to /dev/gpiochip*. Raspberry Pi OS normally provides this via the gpio group. If you get a permission error, inspect ls -l /dev/gpiochip* and groups; if needed, run sudo usermod -aG gpio "$USER", then log out and back in. The game itself does not need to run as root.

3. Test the wiring independently

Before running the bridge, run this on the Pi. The LED should remain lit for two seconds, then turn off:

GPIOZERO_PIN_FACTORY=lgpio python3 -c 'from gpiozero import LED; from time import sleep; led=LED(17); led.on(); sleep(2); led.off(); led.close()'

If this fails, fix the reported GPIO permissions/package error or check the resistor, LED orientation, breadboard connections and pin numbering before testing the game. A successful command without light does not prove the wiring is correct.

4. Start the GPIO helper

Copy pi_gpio_bridge.py and device_feedback.py from this folder alongside the exported game on the Pi. It is a separate Python program, not an embedded Godot resource. Keep it running in a terminal:

GPIOZERO_PIN_FACTORY=lgpio python3 pi_gpio_bridge.py --controller cabinet_01_gpio --pins 17

It listens only on 127.0.0.1:8765 and owns the allowed pins. Do not run another LED script at the same time. It accepts only the configured controller ID and listed BCM pins. Add ,20 to the pin list later if you wire the configured Start Light as well. Do not enable other pins without checking their wiring.

5. Run the exported game with real outputs

In another terminal, replacing ArcadeEscape.arm64 with your actual executable filename:

./ArcadeEscape.arm64 -- --gpio=real --gpio-test

--gpio-test sends a two-second pulse on cabinet 01's coin-release output (BCM17) at startup. No game win is required. The launcher shows GPIO status and the helper terminal logs each accepted command. Once that works, omit the test flag:

./ArcadeEscape.arm64 -- --gpio=real

Choose Pac-Man and win its configured objective. The launcher's Hardware Scenario defaults to proof_of_concept.tres: game_won -> cabinet 01 coin_release -> BCM17, active-high, 600 milliseconds. This is only a short flash. Other launcher games only send hardware events if they have a matching assignment in the selected Hardware Scenario. Add their event mappings in your resources as needed.

Without --gpio=real, runtime outputs remain simulated, including on Windows. Real mode does not silently fall back to simulation if the helper fails. Connection failures, wrong-controller requests and rejected pins appear in the launcher status/log. The editor's room simulation should be run without real mode. This bridge controls the Pi running the game, not GPIO on a different Pi across the network.

Timing and stopping

Managed room rewards include a unique request_id. The updated helper records these in ~/.local/state/arcade_gpio/requests.sqlite3 (override with --ledger). Repeated IDs return the earlier result without driving the pin again. An interrupted request with no recorded outcome is marked uncertain and will not be replayed. Keep this ledger across restarts; standalone requests without an ID retain the original retrigger behavior.

The helper controls pulse timing; repeated pulses restart that pin's duration. Digital outputs accept context.active=false to switch off. Active-low polarity is supported by GPIO Zero. Conflicting polarity on the same pin is rejected until the helper restarts.

The game sends a heartbeat every second. If it exits or disconnects, outputs become inactive within roughly three seconds; short pulses still finish at their own deadline. Ctrl+C/SIGTERM shuts down the helper and deactivates its outputs. This is a software watchdog, not a hardware safety circuit; power loss or forcibly killing the helper cannot guarantee pin state. Test with the LED before attaching real actuators.

Keep the helper running while restarting games with Escape. For unattended boot, launch the helper under your Pi's service manager using the same account/environment and start the game with --gpio=real.

Validation performed off-Pi

Bridge tests cover pulse timing/retriggering, active-low configuration, digital off, watchdog expiry, rejected pins/controllers, and shutdown. The Godot integration test sends a real HTTP request from a Pac-Man win to a test bridge with fake GPIO devices. Physical voltage and your wiring must still be verified on the Pi.

References: GPIO Zero installation, output device API.

PCB live feedback

This optional integration requires the updated controller, launcher, bridge plus device_feedback.py, and a new Godot cabinet export (arcade-cabinet-2.2). No installation is performed by editing the PCB diagram. Odin remains separate.

  1. Save each cabinet's PCB connections in the Godot editor. Give every device a unique ID. For buttons/sensors, check Input pull-up when the switch activates by connecting the signal to GND; verify the actual circuit first.
  2. Export the catalog from the project root:
    godot --headless --path . --script res://tools/room_controller/export_catalog.gd
    
  3. Extract that cabinet's inventory (the destination must not already exist):
    python3 tools/pi_gpio/device_feedback.py --catalog tools/room_controller/catalog.json --cabinet cabinet_01 --output devices.json
    
  4. Copy the inventory and updated software to that cabinet Pi. For RFID, enable SPI using Raspberry Pi configuration and build the separate helper on a Pi with a Rust toolchain:
    cargo build --release --manifest-path tools/pi_gpio/rfid_helper/Cargo.toml
    
    The binary is tools/pi_gpio/rfid_helper/target/release/arcade-rfid. The source follows Odin's MFRC522 library and selector sequence, but this new helper has not yet been compiled or tested on the tester Pi. It requires access to GPIO and SPI. Do not run Odin's reader service simultaneously.
  5. Add these optional settings to the existing launcher's [gpio] section, with paths relative to the launcher INI (or absolute paths):
    devices = /home/YOUR_USER/arcade/devices.json
    rfid_helper = /home/YOUR_USER/arcade/tools/pi_gpio/rfid_helper/target/release/arcade-rfid
    pins =
    
    An empty pins list is valid for input/RFID-only testing. If outputs are configured, list only their actual BCM pins and keep the corresponding HardwareActions aligned. Omit rfid_helper if no RFID readers are configured. Keep the existing real-GPIO launcher setting enabled.

Pin ownership: RFID uses BCM17/27/22 for selection, BCM20 for reset, and SPI0 (BCM8/9/10/11). These cannot also be general outputs. The earlier standalone LED example on BCM17 and start-light example on BCM20 must not be used with this RFID setup. Inputs cannot also be in the output allowlist. The bridge rejects these conflicts before starting.

The operator's cabinet detail and Hardware views display per-device readings. Activity records changes. Disconnected or old samples become stale. J1/J2 are scanned as selector slots 0/1; additional configured readers are scanned in sequence. RFID values currently use Odin's 32-bit UID representation and are not a promise of a complete UID for every card type. A failed tag read is shown as absent or unreadable, rather than proof that a card was removed.

Outputs report the GPIO device's logical electrical state after initialization, not proof that a lock or motor moved. Physical confirmation needs a separate sensor. I2C/Other devices are not sampled yet. Feedback is monitoring only; automatic scenario rules for these events are not enabled by this change.

Start with a button and the two readers, then test an appropriately driven output. Confirm real readings and stale/disconnected behavior on the Pi before relying on this for room operation. Windows tests use fake devices; no physical pins were exercised during development.