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
from os.path import exists, join, dirname
from sys import version_info, argv
import sys, os
def can_import(module_name):
try:
__import__(module_name)
except ImportError:
return False
else:
return True
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)
def is_python_3():
return version_info[0] >= 3
# 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]))
def is_current_version(file_name):
version = map(int, file_name.replace("python", "").split("."))
return version == list(version_info)[:2]
# Use the KMS video driver. This works for newer versions of Raspberry Pi with the KMS overlay
# enabled, SDL 2, and Pygame 2.
if "--kms" in sys.argv:
os.putenv("SDL_VIDEODRIVER", "kmsdrm")
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)
# Use the framebuffer display. This only works with Pygame 1.9.6 (and SDL 1.2).
if "--fb" in sys.argv:
os.putenv("SDL_VIDEODRIVER", "fbcon")
os.putenv("SDL_FBDEV", "/dev/fb0")
def move_to_executable():
chdir(dirname(argv[0]))
# Ignore hangup signal. This may be necessary when launching from systemd.
if "--ignore-hangup" in sys.argv:
ignore_sighup()
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()
# Import GPIO library if requested
if "--gpio" in sys.argv:
import RPi.GPIO as GPIO
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
==============
Avoid touching the triangles with the rods. Chain successes to send acid deeper into the Earth.
Avoid touching the triangles with the rods
Controls
--------
* L/R - Scroll sieve
* Left/Right - Scroll sieve
* Down - Increase fall speed
* F11 - Full screen
@ -20,4 +20,17 @@ Running
-------
* 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 -*-
import sys
from random import randint, randrange, choice
from time import time
from operator import itemgetter
import RPi.GPIO as GPIO
from pygame import Surface, PixelArray, Rect
from pygame.draw import aalines, polygon
@ -25,12 +25,19 @@ class ElectricSieve(Game):
PIN_LED_DOWN = 23
def __init__(self):
self.initialize_gpio()
if self.gpio_enabled():
self.initialize_gpio()
Game.__init__(self)
self.background = Surface(self.display.screen.get_size())
self.background.fill((255, 80, 190))
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):
"""
Set pin numbering mode to GPIO, initialize all buttons to input pullup.
@ -38,9 +45,25 @@ class ElectricSieve(Game):
# Use GPIO numbering
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:
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):
Game.set_children(self)
@ -131,8 +154,6 @@ class Strip(Sprite):
def __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.display_surface = self.get_display_surface()
self.delegate = self.get_game().delegate
@ -151,30 +172,17 @@ class Strip(Sprite):
pass
def respond(self, event):
if type(event) == int:
pressed = "pressed" if GPIO.input(event) == GPIO.LOW else "released"
print(f"pin {event} {pressed}")
"""
Translate input events into movement of the sieve object. This function is usually set as a callback, but it can be called directly.
@param event `pygame.event.Event` with input
"""
if self.active:
move = False
if type(event) == int:
if event == ElectricSieve.PIN_BUTTON_UP:
direction = self.LEFT
move = True
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
compare = self.delegate.compare
if compare(event, "left") or compare(event, "left", True):
self.hshifts[self.LEFT].active = not event.cancel
elif compare(event, "right") or compare(event, "right", True):
self.hshifts[self.RIGHT].active = not event.cancel
def activate(self):
self.active = True