Skip to content

Commit

Permalink
Begin port to gpiod.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gadgetoid committed Nov 21, 2023
1 parent 532e306 commit 41909ed
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 146 deletions.
55 changes: 31 additions & 24 deletions examples/7color/buttons.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
#!/usr/bin/env python3

import signal

import RPi.GPIO as GPIO
import gpiod
import gpiodevice
from gpiod.line import Bias, Direction, Edge, Value

print("""buttons.py - Detect which button has been pressed
This example should demonstrate how to:
1. set up RPi.GPIO to read buttons,
1. set up gpiod to read buttons,
2. determine which button has been pressed
Press Ctrl+C to exit!
""")

# Gpio pins for each button (from top to bottom)
BUTTONS = [5, 6, 16, 24]
# GPIO pins for each button (from top to bottom)
# These will vary depending on platform and the ones
# below should be correct for Raspberry Pi 5.
# Run "gpioinfo" to find out what yours might be
BUTTONS = ["PIN29", "PIN31", "PIN36", "PIN18"]

# These correspond to buttons A, B, C and D respectively
LABELS = ["A", "B", "C", "D"]

# Set up RPi.GPIO with the "BCM" numbering scheme
GPIO.setmode(GPIO.BCM)
# Create settings for all the input pins, we want them to be inputs
# with a pull-up and a falling edge detection.
INPUT = gpiod.LineSettings(direction=Direction.INPUT, bias=Bias.PULL_UP, edge_detection=Edge.FALLING)

# Buttons connect to ground when pressed, so we should set them up
# with a "PULL UP", which weakly pulls the input signal to 3.3V.
GPIO.setup(BUTTONS, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Find the gpiochip device we need, we'll use
# gpiodevice for this, since it knows the right device
# for its supported platforms.
chip = gpiodevice.find_chip_by_platform()

# Build our config for each pin/line we want to use
OFFSETS = [chip.line_offset_from_id(id) for id in BUTTONS]
line_config = dict.fromkeys(OFFSETS, INPUT)

# "handle_button" will be called every time a button is pressed
# It receives one argument: the associated input pin.
def handle_button(pin):
label = LABELS[BUTTONS.index(pin)]
print("Button press detected on pin: {} label: {}".format(pin, label))
# Request the lines, *whew*
request = chip.request_lines(consumer="inky7-buttons", config=line_config)

# "handle_button" will be called every time a button is pressed
# It receives one argument: the associated gpiod event object.
def handle_button(event):
index = OFFSETS.index(event.line_offset)
pin = BUTTONS[index]
label = LABELS[index]
print(f"Button press detected on pin: {pin} label: {label}")

# Loop through out buttons and attach the "handle_button" function to each
# We're watching the "FALLING" edge (transition from 3.3V to Ground) and
# picking a generous bouncetime of 250ms to smooth out button presses.
for pin in BUTTONS:
GPIO.add_event_detect(pin, GPIO.FALLING, handle_button, bouncetime=250)

# Finally, since button handlers don't require a "while True" loop,
# we pause the script to prevent it exiting immediately.
signal.pause()
while True:
for event in request.read_edge_events():
handle_button(event)
59 changes: 33 additions & 26 deletions inky/inky.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""Inky e-Ink Display Driver."""
import struct
import time
from datetime import timedelta

from . import eeprom
import gpiod
import gpiodevice
import numpy
from gpiod.line import Bias, Direction, Edge, Value

try:
import numpy
except ImportError:
raise ImportError("This library requires the numpy module\nInstall with: sudo apt install python-numpy")
from . import eeprom

__version__ = "1.5.0"

Expand All @@ -17,9 +18,9 @@
RED = YELLOW = 2

# GPIO pins required by BCM number
RESET_PIN = 27
BUSY_PIN = 17
DC_PIN = 22
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22

# In addition the following pins are used for SPI
# CS_PIN = 8
Expand Down Expand Up @@ -71,8 +72,7 @@ def __init__(self, resolution=(400, 300), colour="black", cs_channel=CS0, dc_pin
:type spi_bus: :class:`spidev.SpiDev`
:param i2c_bus: SMB object. If `None` then :class:`smbus2.SMBus(1)` is used.
:type i2c_bus: :class:`smbus2.SMBus`
:param gpio: GPIO module. If `None` then `RPi.GPIO` is imported. Default: `None`.
:type gpio: :class:`RPi.GPIO`
:param gpio: deprecated
"""
self._spi_bus = spi_bus
self._i2c_bus = i2c_bus
Expand Down Expand Up @@ -222,16 +222,22 @@ def setup(self):
"""Set up Inky GPIO and reset display."""
if not self._gpio_setup:
if self._gpio is None:
try:
import RPi.GPIO as GPIO
self._gpio = GPIO
except ImportError:
raise ImportError("This library requires the RPi.GPIO module\nInstall with: sudo apt install python-rpi.gpio")
self._gpio.setmode(self._gpio.BCM)
self._gpio.setwarnings(False)
self._gpio.setup(self.dc_pin, self._gpio.OUT, initial=self._gpio.LOW, pull_up_down=self._gpio.PUD_OFF)
self._gpio.setup(self.reset_pin, self._gpio.OUT, initial=self._gpio.HIGH, pull_up_down=self._gpio.PUD_OFF)
self._gpio.setup(self.busy_pin, self._gpio.IN, pull_up_down=self._gpio.PUD_OFF)
gpiochip = gpiodevice.find_chip_by_platform()

if gpiodevice.check_pins_available(self._gpio, {
"Data/Command": self.dc_pin,
"Reset": self.reset_pin,
"Busy": self.busy_pin
}):
self.dc_pin = self._gpio.line_offset_from_id(self.dc_pin)
self.reset_pin = self._gpio.line_offset_from_id(self.reset_pin)
self.busy_pin = self._gpio.line_offset_from_id(self.busy_pin)

self._gpio = self._gpio.request_lines(consumer="inky", config={
self.dc_pin: gpiod.LineSettings(direction=Direction.OUTPUT),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.FALLING)
})

if self._spi_bus is None:
import spidev
Expand All @@ -242,18 +248,19 @@ def setup(self):

self._gpio_setup = True

self._gpio.output(self.reset_pin, self._gpio.LOW)
self._gpio_request.set_value(self.reset_pin, Value.INACTIVE)
time.sleep(0.1)
self._gpio.output(self.reset_pin, self._gpio.HIGH)
self._gpio_request.set_value(self.reset_pin, Value.ACTIVE)
time.sleep(0.1)

self._send_command(0x12) # Soft Reset
self._busy_wait()

def _busy_wait(self):
def _busy_wait(self, timeout=30.0):
"""Wait for busy/wait pin."""
while self._gpio.input(self.busy_pin) != self._gpio.LOW:
time.sleep(0.01)
event = self._gpio.wait_edge_events(timedelta(seconds=timeout))
if not event:
raise RuntimeError("Timeout waiting for busy signal to clear.")

def _update(self, buf_a, buf_b, busy_wait=True):
"""Update display.
Expand Down Expand Up @@ -376,7 +383,7 @@ def _spi_write(self, dc, values):
:param dc: whether to write as data or command
:param values: list of values to write
"""
self._gpio.output(self.dc_pin, dc)
self._gpio_request.set_value(self.dc_pin, Value.ACTIVE if dc else Value.INACTIVE)
try:
self._spi_bus.xfer3(values)
except AttributeError:
Expand Down
57 changes: 30 additions & 27 deletions inky/inky_ssd1608.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
"""Inky e-Ink Display Driver."""
import time
from datetime import timedelta

import gpiod
import gpiodevice
import numpy
from gpiod.line import Bias, Direction, Edge, Value
from PIL import Image

from . import eeprom, ssd1608

try:
import numpy
except ImportError:
raise ImportError("This library requires the numpy module\nInstall with: sudo apt install python-numpy")

WHITE = 0
BLACK = 1
RED = YELLOW = 2

RESET_PIN = 27
BUSY_PIN = 17
DC_PIN = 22
RESET_PIN = "PIN13" # GPIO 27
BUSY_PIN = "PIN11" # GPIO 17
DC_PIN = "PIN15" # GPIO 22

MOSI_PIN = 10
SCLK_PIN = 11
Expand Down Expand Up @@ -126,17 +126,22 @@ def setup(self):
"""Set up Inky GPIO and reset display."""
if not self._gpio_setup:
if self._gpio is None:
try:
import RPi.GPIO as GPIO

self._gpio = GPIO
except ImportError:
raise ImportError("This library requires the RPi.GPIO module\nInstall with: sudo apt install python-rpi.gpio")
self._gpio.setmode(self._gpio.BCM)
self._gpio.setwarnings(False)
self._gpio.setup(self.dc_pin, self._gpio.OUT, initial=self._gpio.LOW, pull_up_down=self._gpio.PUD_OFF)
self._gpio.setup(self.reset_pin, self._gpio.OUT, initial=self._gpio.HIGH, pull_up_down=self._gpio.PUD_OFF)
self._gpio.setup(self.busy_pin, self._gpio.IN, pull_up_down=self._gpio.PUD_OFF)
gpiochip = gpiodevice.find_chip_by_platform()
gpiodevice.friendly_errors = True
if gpiodevice.check_pins_available(gpiochip, {
"Data/Command": self.dc_pin,
"Reset": self.reset_pin,
"Busy": self.busy_pin
}):
self.dc_pin = gpiochip.line_offset_from_id(self.dc_pin)
self.reset_pin = gpiochip.line_offset_from_id(self.reset_pin)
self.busy_pin = gpiochip.line_offset_from_id(self.busy_pin)

self._gpio = gpiochip.request_lines(consumer="inky", config={
self.dc_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.INACTIVE),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.ACTIVE),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.FALLING, debounce_period=timedelta(milliseconds=10))
})

if self._spi_bus is None:
import spidev
Expand All @@ -148,9 +153,9 @@ def setup(self):

self._gpio_setup = True

self._gpio.output(self.reset_pin, self._gpio.LOW)
self._gpio.set_value(self.reset_pin, Value.INACTIVE)
time.sleep(0.5)
self._gpio.output(self.reset_pin, self._gpio.HIGH)
self._gpio.set_value(self.reset_pin, Value.ACTIVE)
time.sleep(0.5)

self._send_command(0x12) # Soft Reset
Expand All @@ -159,11 +164,9 @@ def setup(self):

def _busy_wait(self, timeout=5.0):
"""Wait for busy/wait pin."""
t_start = time.time()
while self._gpio.input(self.busy_pin):
time.sleep(0.01)
if time.time() - t_start >= timeout:
raise RuntimeError("Timeout waiting for busy signal to clear.")
event = self._gpio.wait_edge_events(timedelta(seconds=timeout))
if not event:
raise RuntimeError("Timeout waiting for busy signal to clear.")

def _update(self, buf_a, buf_b, busy_wait=True):
"""Update display.
Expand Down Expand Up @@ -269,7 +272,7 @@ def _spi_write(self, dc, values):
:param values: list of values to write
"""
self._gpio.output(self.dc_pin, dc)
self._gpio.set_value(self.dc_pin, Value.ACTIVE if dc else Value.INACTIVE)
try:
self._spi_bus.xfer3(values)
except AttributeError:
Expand Down
51 changes: 27 additions & 24 deletions inky/inky_ssd1683.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
"""Inky e-Ink Display Driver."""
import time
from datetime import timedelta

import gpiod
import gpiodevice
import numpy
from gpiod.line import Bias, Direction, Edge, Value
from PIL import Image

from . import eeprom, ssd1683

try:
import numpy
except ImportError:
raise ImportError("This library requires the numpy module\nInstall with: sudo apt install python-numpy")

WHITE = 0
BLACK = 1
RED = YELLOW = 2
Expand Down Expand Up @@ -114,17 +114,22 @@ def setup(self):
"""Set up Inky GPIO and reset display."""
if not self._gpio_setup:
if self._gpio is None:
try:
import RPi.GPIO as GPIO

self._gpio = GPIO
except ImportError:
raise ImportError("This library requires the RPi.GPIO module\nInstall with: sudo apt install python-rpi.gpio")
self._gpio.setmode(self._gpio.BCM)
self._gpio.setwarnings(False)
self._gpio.setup(self.dc_pin, self._gpio.OUT, initial=self._gpio.LOW, pull_up_down=self._gpio.PUD_OFF)
self._gpio.setup(self.reset_pin, self._gpio.OUT, initial=self._gpio.HIGH, pull_up_down=self._gpio.PUD_OFF)
self._gpio.setup(self.busy_pin, self._gpio.IN, pull_up_down=self._gpio.PUD_OFF)
gpiochip = gpiodevice.find_chip_by_platform()
gpiodevice.friendly_errors = True
if gpiodevice.check_pins_available(gpiochip, {
"Data/Command": self.dc_pin,
"Reset": self.reset_pin,
"Busy": self.busy_pin
}):
self.dc_pin = gpiochip.line_offset_from_id(self.dc_pin)
self.reset_pin = gpiochip.line_offset_from_id(self.reset_pin)
self.busy_pin = gpiochip.line_offset_from_id(self.busy_pin)

self._gpio = gpiochip.request_lines(consumer="inky", config={
self.dc_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.INACTIVE),
self.reset_pin: gpiod.LineSettings(direction=Direction.OUTPUT, output_value=Value.ACTIVE),
self.busy_pin: gpiod.LineSettings(direction=Direction.INPUT, edge_detection=Edge.FALLING, debounce_period=timedelta(milliseconds=10))
})

if self._spi_bus is None:
import spidev
Expand All @@ -136,9 +141,9 @@ def setup(self):

self._gpio_setup = True

self._gpio.output(self.reset_pin, self._gpio.LOW)
self._gpio.set_value(self.reset_pin, Value.INACTIVE)
time.sleep(0.5)
self._gpio.output(self.reset_pin, self._gpio.HIGH)
self._gpio.set_value(self.reset_pin, Value.ACTIVE)
time.sleep(0.5)

self._send_command(0x12) # Soft Reset
Expand All @@ -147,11 +152,9 @@ def setup(self):

def _busy_wait(self, timeout=5.0):
"""Wait for busy/wait pin."""
t_start = time.time()
while self._gpio.input(self.busy_pin):
time.sleep(0.01)
if time.time() - t_start >= timeout:
raise RuntimeError("Timeout waiting for busy signal to clear.")
event = self._gpio.wait_edge_events(timedelta(seconds=timeout))
if not event:
raise RuntimeError("Timeout waiting for busy signal to clear.")

def _update(self, buf_a, buf_b, busy_wait=True):
"""Update display.
Expand Down Expand Up @@ -257,7 +260,7 @@ def _spi_write(self, dc, values):
:param values: list of values to write
"""
self._gpio.output(self.dc_pin, dc)
self._gpio.set_value(self.dc_pin, Value.ACTIVE if dc else Value.INACTIVE)
try:
self._spi_bus.xfer3(values)
except AttributeError:
Expand Down
Loading

0 comments on commit 41909ed

Please sign in to comment.