gpio input translated to command events

This commit is contained in:
ohsqueezy 2022-12-13 18:28:46 -05:00
parent ac9c5cdf4c
commit f0b77551b6
5 changed files with 80 additions and 136 deletions

View File

@ -1,42 +1,38 @@
#!/usr/bin/env python #!/usr/bin/env python3
from os import environ, execvp, chdir, getcwd import sys, os
from os.path import exists, join, dirname
from sys import version_info, argv
def can_import(module_name): def ignore_sighup():
try: """
__import__(module_name) Ignore hangup signal (that is thrown when launching from systemd?).
except ImportError: Taken from https://stackoverflow.com/questions/57205271/how-to-display-pygame-framebuffer-using-systemd-service
return False """
else: import signal
return True def handler(signum, frame):
pass
signal.signal(signal.SIGHUP, handler)
def is_python_3(): # Change directory to the directory of the program launching the script (usually this script "OPEN-GAME").
return version_info[0] >= 3 if "--go-to-dir" in sys.argv:
os.chdir(os.path.dirname(sys.argv[0]))
def is_current_version(file_name): # Use the KMS video driver. This works for newer versions of Raspberry Pi with the KMS overlay
version = map(int, file_name.replace("python", "").split(".")) # enabled, SDL 2, and Pygame 2.
return version == list(version_info)[:2] if "--kms" in sys.argv:
os.putenv("SDL_VIDEODRIVER", "kmsdrm")
def launch_alternative(alternatives): # Use the framebuffer display. This only works with Pygame 1.9.6 (and SDL 1.2).
for alternative in alternatives: if "--fb" in sys.argv:
if not is_current_version(alternative): os.putenv("SDL_VIDEODRIVER", "fbcon")
for root in environ["PATH"].split(":"): os.putenv("SDL_FBDEV", "/dev/fb0")
if exists(join(root, alternative)):
execvp(alternative, [alternative] + argv)
def move_to_executable(): # Ignore hangup signal. This may be necessary when launching from systemd.
chdir(dirname(argv[0])) if "--ignore-hangup" in sys.argv:
ignore_sighup()
if is_python_3(): # Import GPIO library if requested
launch_alternative(["python2", "python2.7", "python2.6"]) if "--gpio" in sys.argv:
import RPi.GPIO as GPIO
if not can_import("pygame"):
launch_alternative(["python2.7", "python2.6"])
if "--go-to-dir" in argv:
move_to_executable()
from electric_sieve.ElectricSieve import ElectricSieve from electric_sieve.ElectricSieve import ElectricSieve

View File

@ -1,47 +0,0 @@
#!/usr/bin/env python
import os
from os import environ, execvp, chdir, getcwd
from os.path import exists, join, dirname
from sys import version_info, argv
def can_import(module_name):
try:
__import__(module_name)
except ImportError:
return False
else:
return True
def is_python_3():
return version_info[0] >= 3
def is_current_version(file_name):
version = map(int, file_name.replace("python", "").split("."))
return version == list(version_info)[:2]
def launch_alternative(alternatives):
for alternative in alternatives:
if not is_current_version(alternative):
for root in environ["PATH"].split(":"):
if exists(join(root, alternative)):
execvp(alternative, [alternative] + argv)
def move_to_executable():
chdir(dirname(argv[0]))
if is_python_3():
launch_alternative(["python2", "python2.7", "python2.6"])
if not can_import("pygame"):
launch_alternative(["python2.7", "python2.6"])
if "--go-to-dir" in argv:
move_to_executable()
from electric_sieve.ElectricSieve import ElectricSieve
os.putenv("SDL_FBDEV", "/dev/fb0")
os.putenv("SDL_VIDEODRIVER", "fbcon")
os.putenv("SDL_NOMOUSE", "1")
ElectricSieve().run()

View File

@ -1,26 +0,0 @@
#!/usr/bin/env python3
import sys, os
def ignore_sighup():
"""
Ignore hangup signal (that is thrown when launching from systemd?).
Taken from https://stackoverflow.com/questions/57205271/how-to-display-pygame-framebuffer-using-systemd-service
"""
import signal
def handler(signum, frame):
pass
signal.signal(signal.SIGHUP, handler)
# Change directory to the directory of the program launching the script (usually this script "OPEN-GAME").
if "--go-to-dir" in sys.argv:
os.chdir(os.path.dirname(sys.argv[0]))
# Use the KMS video driver. This works for newer versions of Raspberry Pi with the KMS overlay
# enabled, SDL 2, and Pygame 2.
os.putenv("SDL_VIDEODRIVER", "kmsdrm")
# ignore_sighup()
from electric_sieve.ElectricSieve import ElectricSieve
ElectricSieve().run()

View File

@ -1,12 +1,12 @@
Electric Sieve Electric Sieve
============== ==============
Avoid touching the triangles with the rods. Chain successes to send acid deeper into the Earth. Avoid touching the triangles with the rods
Controls Controls
-------- --------
* L/R - Scroll sieve * Left/Right - Scroll sieve
* Down - Increase fall speed * Down - Increase fall speed
* F11 - Full screen * F11 - Full screen
@ -20,4 +20,17 @@ Running
------- -------
* Windows - double-click "scale-sieve" EXE * Windows - double-click "scale-sieve" EXE
* Linux/Mac - run "./scale-sieve" on the command line * Linux/Mac - run `./OPEN-GAME` on the command line
Raspberry Pi
------------
Add `--gpio` to the command line to read input from buttons wired to the Raspberry Pi (the buttons should be wired to GPIO 17 and 27).
Headless
--------
If running on Linux without X-Windows (for example, Raspberry Pi Lite OS), there are two options for launching
* add `--kms` to the command line if the newer KMS driver and Pygame 2 are being used
* add `--fb` to use the framebuffer if using Pygame 1

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys
from random import randint, randrange, choice from random import randint, randrange, choice
from time import time from time import time
from operator import itemgetter from operator import itemgetter
import RPi.GPIO as GPIO
from pygame import Surface, PixelArray, Rect from pygame import Surface, PixelArray, Rect
from pygame.draw import aalines, polygon from pygame.draw import aalines, polygon
@ -25,12 +25,19 @@ class ElectricSieve(Game):
PIN_LED_DOWN = 23 PIN_LED_DOWN = 23
def __init__(self): def __init__(self):
self.initialize_gpio() if self.gpio_enabled():
self.initialize_gpio()
Game.__init__(self) Game.__init__(self)
self.background = Surface(self.display.screen.get_size()) self.background = Surface(self.display.screen.get_size())
self.background.fill((255, 80, 190)) self.background.fill((255, 80, 190))
self.title.activate() self.title.activate()
def gpio_enabled(self):
"""
@return True if GPIO mode was requested at launch, False otherwise
"""
return "--gpio" in sys.argv
def initialize_gpio(self): def initialize_gpio(self):
""" """
Set pin numbering mode to GPIO, initialize all buttons to input pullup. Set pin numbering mode to GPIO, initialize all buttons to input pullup.
@ -38,9 +45,25 @@ class ElectricSieve(Game):
# Use GPIO numbering # Use GPIO numbering
GPIO.setmode(GPIO.BCM) GPIO.setmode(GPIO.BCM)
# Set all button pins to pullup # Set button pins to pullup and attach to each a callback that runs on press or release
for pin in self.PIN_BUTTON_UP, self.PIN_BUTTON_DOWN: for pin in self.PIN_BUTTON_UP, self.PIN_BUTTON_DOWN:
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(pin, GPIO.BOTH, self.gpio_input)
def gpio_input(self, pin):
"""
Translate GPIO input into PGFW commands, so Raspberry Pi wired controllers be used for input. The pin will be checked for a low
signal, meaning the pin has been connected to ground, which is translated to a button press. If the low signal is not detected, it
is translated to a button release. Usually called as a callback by `GPIO.add_event_detect` but can be called directly.
@param pin Raspberry Pi pin number as read by the RPi.GPIO library
"""
cancel = not (GPIO.input(pin) == GPIO.LOW)
if pin == ElectricSieve.PIN_BUTTON_UP:
self.input.post_command("left", cancel=cancel)
elif pin == ElectricSieve.PIN_BUTTON_DOWN:
self.input.post_command("right", cancel=cancel)
self.input.post_any_command(id=pin, cancel=cancel)
def set_children(self): def set_children(self):
Game.set_children(self) Game.set_children(self)
@ -131,8 +154,6 @@ class Strip(Sprite):
def __init__(self, parent): def __init__(self, parent):
Sprite.__init__(self, parent) Sprite.__init__(self, parent)
GPIO.add_event_detect(ElectricSieve.PIN_BUTTON_UP, GPIO.BOTH, self.respond)
GPIO.add_event_detect(ElectricSieve.PIN_BUTTON_DOWN, GPIO.BOTH, self.respond)
self.deactivate() self.deactivate()
self.display_surface = self.get_display_surface() self.display_surface = self.get_display_surface()
self.delegate = self.get_game().delegate self.delegate = self.get_game().delegate
@ -151,30 +172,17 @@ class Strip(Sprite):
pass pass
def respond(self, event): def respond(self, event):
if type(event) == int: """
pressed = "pressed" if GPIO.input(event) == GPIO.LOW else "released" Translate input events into movement of the sieve object. This function is usually set as a callback, but it can be called directly.
print(f"pin {event} {pressed}")
@param event `pygame.event.Event` with input
"""
if self.active: if self.active:
move = False compare = self.delegate.compare
if type(event) == int: if compare(event, "left") or compare(event, "left", True):
if event == ElectricSieve.PIN_BUTTON_UP: self.hshifts[self.LEFT].active = not event.cancel
direction = self.LEFT elif compare(event, "right") or compare(event, "right", True):
move = True self.hshifts[self.RIGHT].active = not event.cancel
elif event == ElectricSieve.PIN_BUTTON_DOWN:
direction = self.RIGHT
move = True
active = GPIO.input(event) == GPIO.LOW
else:
compare = self.delegate.compare
if compare(event, "left") or compare(event, "left", True):
direction = self.LEFT
move = True
elif compare(event, "right") or compare(event, "right", True):
direction = self.RIGHT
move = True
active = not event.cancel
if move:
self.hshifts[direction].active = active
def activate(self): def activate(self):
self.active = True self.active = True