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

93 lines
4.6 KiB
GDScript

@tool
class_name CabinetPCBConfig
extends Resource
# This resource describes wiring. It never configures or writes GPIO.
@export var connections: Array[PCBConnection] = []
const TYPES := {
"rfid": "RFID reader", "button": "Button / switch", "sensor": "Digital sensor",
"led": "LED / lighting driver", "motor": "Motorized switch / motor driver",
"relay": "Relay / MOSFET module", "i2c": "I2C peripheral", "other": "Other (document wiring)"
}
static func ports() -> Array[Dictionary]:
var result: Array[Dictionary] = []
for index in range(8):
result.append({"id": "J%d" % (index + 1), "family": "reader", "label": "%d%d%d" % [(index >> 2) & 1, (index >> 1) & 1, index & 1], "pins": "Selector: BCM22=%d, BCM27=%d, BCM17=%d\nShared reset: BCM20. Reader connector contact pinout is not documented." % [(index >> 2) & 1, (index >> 1) & 1, index & 1], "types": ["rfid", "other"], "bcm": -1})
result.append({"id": "J9", "family": "host", "label": "Pi ribbon", "pins": "Host GPIO ribbon connector. Confirm pin-1 orientation against the physical board.", "types": [], "bcm": -1})
var signals := [5, 6, 13, 19, 26, 21]
for index in range(6):
result.append({"id": "J%d" % (10 + index), "family": "powered", "label": "BCM%d" % signals[index], "pins": "1 GND (black) | 2 3V3 (red) | 3 signal (yellow)\nBCM%d" % signals[index], "types": ["button", "sensor", "led", "motor", "relay", "other"], "bcm": signals[index]})
result.append({"id": "J16", "family": "i2c", "label": "I2C1", "pins": "1 GND (black) | 2 3V3 (red) | 3 SCL (white) | 4 SDA (yellow)", "types": ["i2c", "other"], "bcm": -1})
signals = [16, 12, 24, 23, 18, 25]
for index in range(6):
result.append({"id": "J%d" % (17 + index), "family": "signal", "label": "BCM%d" % signals[index], "pins": "1 GND (black) | 2 signal (red)\nBCM%d - red is signal, not a power supply." % signals[index], "types": ["button", "sensor", "led", "motor", "relay", "other"], "bcm": signals[index]})
return result
static func port(id: String) -> Dictionary:
for definition in ports():
if definition.id == id:
return definition
return {}
func connection(id: String) -> PCBConnection:
for item in connections:
if item != null and item.port_id == id:
return item
return null
func set_connection(item: PCBConnection) -> void:
for index in range(connections.size() - 1, -1, -1):
if connections[index] != null and connections[index].port_id == item.port_id:
connections.remove_at(index)
if not item.device_type.is_empty():
connections.append(item)
emit_changed()
func issues(hardware: HardwareConfig = null) -> PackedStringArray:
var messages := PackedStringArray()
var used_ports: Dictionary = {}
var used_ids: Dictionary = {}
for item in connections:
if item == null:
messages.append("Empty connection resource.")
continue
var definition := port(item.port_id)
if definition.is_empty() or not definition.types.has(item.device_type):
messages.append("%s: unsupported connector/device combination." % item.port_id)
if used_ports.has(item.port_id):
messages.append("%s: connector is assigned more than once." % item.port_id)
used_ports[item.port_id] = true
if item.device_id.strip_edges().is_empty():
messages.append("%s: enter a device ID." % item.port_id)
elif used_ids.has(item.device_id):
messages.append("Duplicate device ID: %s." % item.device_id)
used_ids[item.device_id] = true
if item.device_type in ["led", "motor", "relay"] and not item.binding_id.is_empty():
var action: HardwareAction = hardware.get_action(StringName(item.binding_id)) if hardware else null
if action == null:
messages.append("%s: hardware action '%s' does not exist." % [item.port_id, item.binding_id])
elif not definition.is_empty() and action.gpio_pin != definition.bcm:
messages.append("%s: action uses BCM%d, but connector uses BCM%d." % [item.port_id, action.gpio_pin, definition.bcm])
if hardware:
for action in hardware.actions:
if action != null and action.gpio_pin in [17, 27, 22, 20]:
messages.append("Action '%s' uses reserved PCB selector/reset BCM%d." % [action.action_id, action.gpio_pin])
return messages
func feedback_devices() -> Array[Dictionary]:
var result: Array[Dictionary] = []
for item in connections:
if item == null:
continue
var kind := ""
if item.device_type == "rfid": kind = "rfid"
elif item.device_type in ["button", "sensor"]: kind = "input"
elif item.device_type in ["led", "motor", "relay"]: kind = "output"
else:
push_warning("Feedback driver not implemented for %s (%s)" % [item.device_id, item.device_type])
continue
result.append({"id": item.device_id, "name": item.display_name, "port": item.port_id, "kind": kind, "pull_up": item.input_pull_up})
return result