wip applying GPIO to the game
This commit is contained in:
parent
f68fb897c5
commit
d122f66af4
65
NS.py
65
NS.py
|
@ -32,6 +32,7 @@ from pygame.draw import aalines, lines
|
|||
from pygame.gfxdraw import aapolygon, arc, polygon, aaellipse, ellipse, filled_ellipse, filled_circle
|
||||
from pygame.locals import *
|
||||
|
||||
import gpio
|
||||
from lib.pgfw.pgfw.Game import Game
|
||||
from lib.pgfw.pgfw.GameChild import GameChild
|
||||
from lib.pgfw.pgfw.Sprite import Sprite, RainbowSprite, BlinkingSprite
|
||||
|
@ -146,11 +147,14 @@ class NS(Game, Animation):
|
|||
# Specify possible arguments and parse the command line. If the -h flag is passed, the argparse library will print a
|
||||
# help message and end the program.
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--minimize-load-time", action="store_true")
|
||||
parser.add_argument("--minimize-load-time", action="store_true", help="Disable some graphics loading and effects generation")
|
||||
parser.add_argument("--serial-port")
|
||||
parser.add_argument("--audio-buffer-size", type=int, default=1024)
|
||||
parser.add_argument("--list-serial-ports", action="store_true")
|
||||
parser.add_argument("--no-serial", action="store_true")
|
||||
parser.add_argument("--no-serial", action="store_true", help="Force serial (Arduino) mode off.")
|
||||
parser.add_argument(
|
||||
"--pi", action="store_true",
|
||||
help="Force to read input from the GPIO pins of a Raspberry Pi. Must be running on Raspberry Pi. Forces --no-serial.")
|
||||
parser.add_argument("--show-config", action="store_true")
|
||||
arguments = parser.parse_known_args()[0]
|
||||
|
||||
|
@ -221,19 +225,37 @@ class NS(Game, Animation):
|
|||
if arguments.no_serial:
|
||||
self.get_configuration().set("input", "serial", False)
|
||||
|
||||
# Apply the pi flag from the command line if requested. This takes precedence over Arduino, so even if serial is enabled,
|
||||
# force to no serial mode.
|
||||
if arguments.pi:
|
||||
self.get_configuration().set("input", "pi", True)
|
||||
if get_configuration("input", "serial"):
|
||||
print("Pi mode was requested, so forcing serial (Arduino) mode to off")
|
||||
self.get_configuration().set("input", "serial", False)
|
||||
|
||||
# Print the configuration if requested on the command line
|
||||
if arguments.show_config:
|
||||
print(self.get_configuration())
|
||||
|
||||
# Initialize the serial reader and launch a thread for reading from the serial port
|
||||
if self.serial_enabled():
|
||||
# init Pi
|
||||
if self.pi_enabled():
|
||||
|
||||
# Initialize GPIO interface
|
||||
gpio.initialize_gpio()
|
||||
|
||||
# init Arduino
|
||||
elif self.serial_enabled():
|
||||
|
||||
# Initialize the serial reader and launch a thread for reading from the serial port
|
||||
from serial import Serial, SerialException
|
||||
from serial.tools import list_ports
|
||||
|
||||
# If a list of serial ports was requested, print detected ports and exit.
|
||||
if arguments.list_serial_ports:
|
||||
for port in list_ports.comports():
|
||||
print(f"Detected serial port: {port.device}")
|
||||
exit()
|
||||
|
||||
# Open the port specified by the configuration or command line if it is found. If the specified port is not
|
||||
# found, open the first found serial port. If no serial ports are found, raise an exception.
|
||||
requested_port = self.get_configuration("input", "arduino-port")
|
||||
|
@ -247,6 +269,8 @@ class NS(Game, Animation):
|
|||
self.serial_kill = False
|
||||
self.serial_data = 0
|
||||
self.reset_arduino()
|
||||
|
||||
# Launch a separate thread for reading serial data
|
||||
self.serial_thread = Thread(target=self.read_serial)
|
||||
self.serial_thread.start()
|
||||
|
||||
|
@ -299,6 +323,9 @@ class NS(Game, Animation):
|
|||
|
||||
clear()
|
||||
|
||||
def pi_enabled(self):
|
||||
return self.get_configuration("input", "pi")
|
||||
|
||||
def serial_enabled(self):
|
||||
return self.get_configuration("input", "serial")
|
||||
|
||||
|
@ -351,6 +378,21 @@ class NS(Game, Animation):
|
|||
if light.pressed:
|
||||
self.idle_elapsed = 0
|
||||
|
||||
def apply_gpio(self):
|
||||
"""
|
||||
Check the connection status of the GPIO pins and turn on the appropriate light objects (the pads).
|
||||
"""
|
||||
# Get the active (a.k.a. pressed) state of each GPIO pin (a.k.a. pad)
|
||||
activity = gpio.activity()
|
||||
|
||||
for light_id in activity.keys():
|
||||
# The pressed state is set to the activity state
|
||||
self.platform.lights[light_id].pressed = activity[light_id]
|
||||
|
||||
# Reset idle timer if a light is detected as pressed
|
||||
if activity[light_id]:
|
||||
self.idle_elapsed = 0
|
||||
|
||||
def reset(self, leave_wipe_running=False):
|
||||
self.idle_elapsed = 0
|
||||
self.suppressing_input = False
|
||||
|
@ -450,10 +492,22 @@ class NS(Game, Animation):
|
|||
def update(self):
|
||||
Animation.update(self)
|
||||
last_frame_duration = self.time_filter.get_last_frame_duration()
|
||||
if self.serial_enabled():
|
||||
|
||||
# Apply controller input to light (pad) states from either Pi or Arduino if applicable
|
||||
if self.pi_enabled():
|
||||
|
||||
# Translate Raspberry Pi GPIO state into pad states
|
||||
self.apply_gpio()
|
||||
|
||||
elif self.serial_enabled():
|
||||
|
||||
# Translate the most recent serial data, being provided by serial/serial2/serial2.ino, into pad states
|
||||
self.apply_serial()
|
||||
|
||||
# Handle auto reset of the Arduino for stablizing serial data
|
||||
if self.title.active or self.ending.active or self.dialogue.active:
|
||||
self.no_reset_elapsed += last_frame_duration
|
||||
|
||||
# If we received good input, reset the auto reset timer
|
||||
if 0b11 <= self.serial_data <= 0b1100:
|
||||
self.no_reset_elapsed = 0
|
||||
|
@ -461,6 +515,7 @@ class NS(Game, Animation):
|
|||
print("auto arduino reset triggered")
|
||||
self.reset_arduino()
|
||||
self.no_reset_elapsed = 0
|
||||
|
||||
self.title.update()
|
||||
self.level_select.update()
|
||||
self.ending.update()
|
||||
|
|
3
config
3
config
|
@ -60,7 +60,8 @@ volume = 1.0
|
|||
[input]
|
||||
buffer = 0
|
||||
arduino-port = /dev/ttyACM0
|
||||
serial = True
|
||||
serial = False
|
||||
pi = True
|
||||
confirm-quit = False
|
||||
|
||||
[time]
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
#
|
||||
# Full open source code is available at <https://git.nugget.fun/scrape/scrapeboard>.
|
||||
#
|
||||
# This is a utility script for testing if the GPIO interface of a Raspberry Pi is working
|
||||
# with the four input wires, which correspond to the four metal floor pads in the standard
|
||||
# Scrapeboard build.
|
||||
# This module can be imported and used to check on the status of connections between four GPIO
|
||||
# inputs on the Raspberry Pi for detecting the pads in Scrapeboard.
|
||||
#
|
||||
# When run as a script, it prints connections detected between the input GPIO pins.
|
||||
|
||||
import time, itertools
|
||||
import RPi.GPIO as GPIO
|
||||
|
@ -22,6 +23,17 @@ pins = {
|
|||
LSW: 23
|
||||
}
|
||||
|
||||
def initialize_gpio():
|
||||
"""
|
||||
Set pin numbering mode to GPIO and initialize all pins to input pullup.
|
||||
"""
|
||||
# Use GPIO numbering
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
|
||||
# Set all pins to pullup
|
||||
for pin_id, pin in pins.items():
|
||||
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||
|
||||
def connection2(pin_a, pin_b):
|
||||
"""
|
||||
Set `pin_a` to output a low signal, and set every other pin to pullup. If `pin_b` reads a low signal even though
|
||||
|
@ -55,21 +67,46 @@ def connection(pin_a, pin_b):
|
|||
|
||||
def connections():
|
||||
"""
|
||||
Look at all six possible connections between the four pins and print a message if one is found connected.
|
||||
Look at all six possible connections between the four pins and return the state of each as a single dict.
|
||||
|
||||
@return A dict with one entry per combination of pins, the key is a tuple of pin IDs, and the value is the state of connection
|
||||
"""
|
||||
state = {}
|
||||
for pin_id_a, pin_id_b in itertools.combinations(pins, 2):
|
||||
if connection(pins[pin_id_a], pins[pin_id_b]):
|
||||
print(f"{pin_id_a} ({pins[pin_id_a]}) <-> {pin_id_b} ({pins[pin_id_b]})")
|
||||
state[(pin_id_a, pin_id_b)] = True
|
||||
else:
|
||||
state[(pin_id_a, pin_id_b)] = False
|
||||
return state
|
||||
|
||||
def activity():
|
||||
"""
|
||||
Look at all six possible connections between the four pins, and if a pin appears in any active connection, consider it active.
|
||||
Return the active state of all four pins as a dict.
|
||||
|
||||
@return A dict with one entry per pin. The key is the pin ID, and the value is the state of whether it's active (a.k.a. pressed)
|
||||
"""
|
||||
# Create a dict of pins all at False
|
||||
state = pins.copy()
|
||||
for pin in state.keys():
|
||||
state[pin] = False
|
||||
|
||||
# Check all six combinations. If a pin appears in a connection, update its state to True.
|
||||
for pin_id_a, pin_id_b in itertools.combinations(pins, 2):
|
||||
if connection(pins[pin_id_a], pins[pin_id_b]):
|
||||
state[pin_id_a] = True
|
||||
state[pin_id_b] = True
|
||||
|
||||
return state
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Use GPIO numbering
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
|
||||
# Set all pins to pullup
|
||||
for pin_id, pin in pins.items():
|
||||
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||
|
||||
initialize_gpio()
|
||||
|
||||
while True:
|
||||
# Try all connections once each frame
|
||||
connections()
|
||||
for connection_ids, connection_state in connections():
|
||||
# Only print connected combinations of pins
|
||||
if connection_state:
|
||||
pin_id_a, pin_id_b = connection_ids
|
||||
print(f"{pin_id_a} ({pins[pin_id_a]}) <-> {pin_id_b} ({pins[pin_id_b]})")
|
||||
time.sleep(0.1)
|
Loading…
Reference in New Issue