Files

78 lines
3.1 KiB
GDScript

extends Node
signal action_activated(cabinet_id: StringName, action_id: StringName, context: Dictionary)
signal action_deactivated(cabinet_id: StringName, action_id: StringName, context: Dictionary)
signal status_changed(message: String)
var active_cabinet: CabinetProfile
var real_gpio := false
var status := "GPIO simulation (use --gpio=real on the Pi)"
var client: Node
var generations: Dictionary = {}
func _ready() -> void:
real_gpio = "--gpio=real" in OS.get_cmdline_user_args()
if real_gpio:
client = preload("res://core/runtime/pi_gpio_client.gd").new()
client.status_changed.connect(_status)
add_child(client)
_status("GPIO real mode — local Pi bridge required")
if "--gpio-test" in OS.get_cmdline_user_args():
test_led.call_deferred()
func _status(message: String) -> void:
status = message
print("[GPIO] ", message)
status_changed.emit(message)
func configure(cabinet: CabinetProfile) -> void:
active_cabinet = cabinet
func trigger(action_id: StringName, context: Dictionary = {}) -> void:
if active_cabinet == null:
_status("No active cabinet for GPIO action")
return
trigger_for_cabinet(active_cabinet, action_id, context)
func trigger_for_cabinet(cabinet: CabinetProfile, action_id: StringName, context: Dictionary = {}) -> void:
if cabinet == null or cabinet.hardware_config == null:
_status("Missing cabinet hardware configuration")
return
var action := cabinet.hardware_config.get_action(action_id)
if action == null:
_status("Unknown hardware action: %s" % action_id)
return
_send_action(cabinet, action, context)
func _send_action(cabinet: CabinetProfile, action: HardwareAction, context: Dictionary) -> void:
var key := "%s:%s" % [cabinet.hardware_config.controller_id, action.gpio_pin]
var generation := int(generations.get(key, 0)) + 1
generations[key] = generation
var pulse := action.action_type == HardwareAction.ActionType.PULSE_OUTPUT
var active := true if pulse else bool(context.get("active", true))
if real_gpio:
var ok: bool = await client.send({
"controller": str(cabinet.hardware_config.controller_id),
"pin": action.gpio_pin,
"active_high": action.active_high,
"mode": "pulse" if pulse else "set",
"duration_ms": action.pulse_duration_ms,
"active": active,
})
if not ok: return
else:
print("[MOCK GPIO] %s cabinet=%s action=%s BCM=%d" % ["PULSE" if pulse else "SET", cabinet.cabinet_id, action.action_id, action.gpio_pin])
if active:
action_activated.emit(cabinet.cabinet_id, action.action_id, context)
else:
action_deactivated.emit(cabinet.cabinet_id, action.action_id, context)
if pulse:
await get_tree().create_timer(action.pulse_duration_ms / 1000.0).timeout
if int(generations.get(key, 0)) == generation:
# Physical timing belongs to the bridge, even if the game exits mid-pulse.
action_deactivated.emit(cabinet.cabinet_id, action.action_id, context)
func test_led() -> void:
var cabinet = load("res://data/cabinets/cabinet_01.tres").duplicate(true)
var action: HardwareAction = cabinet.hardware_config.get_action(&"coin_release")
action.pulse_duration_ms = 2000
_send_action(cabinet, action, {"source": "gpio_led_test"})