Skip to content

Commit

Permalink
Merge pull request #9 from FoamyGuy/various_touchups
Browse files Browse the repository at this point in the history
Various touchups
  • Loading branch information
FoamyGuy authored Feb 4, 2025
2 parents 1727669 + 5452337 commit 00101f6
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 10 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Installing from pip:
System setup
------------

If `ls -l /dev/pio0` reports that the file is not found, you may need to update your Pi 5 firmware to one with PIO support and make sure that you are running a suitably recent kernel. If `ls -l /dev/pio0` reports that the file is owned by root and group root, you should add the following to /etc/udev/rules/99-com.rules:
If `ls -l /dev/pio0` reports that the file is not found, you may need to update your Pi 5 firmware to one with PIO support and make sure that you are running a suitably recent kernel. If `ls -l /dev/pio0` reports that the file is owned by root and group root, you should add the following to /etc/udev/rules.d/99-com.rules:

```
SUBSYSTEM=="*-pio", GROUP="gpio", MODE="0660"
Expand Down
Binary file added examples/LindenHill-webfont.ttf
Binary file not shown.
3 changes: 3 additions & 0 deletions examples/LindenHill-webfont.ttf.license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: Copyright (c) 2010, Barry Schwartz <[email protected]>, with Reserved Font Name OFL "Linden Hill"

# SPDX-License-Identifier: OFL-1.1-RFN
44 changes: 41 additions & 3 deletions examples/fbmirror.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,57 @@
The upper left corner of the framebuffer is displayed until the user hits ctrl-c.
Control matrix size, and orientation with command line arguments.
python fbmirror_scaled.py [width] [height] [orientation]
width int: Total width of matrices in pixels. Default is 64.
height int: Total height of matrices in pixels. Default is 32.
orientation int: Orientation in degrees, must be 0, 90, 180, or 270.
Default is 0 or Normal orientation.
The `/dev/fb0` special file will exist if a monitor is plugged in at boot time,
or if `/boot/firmware/cmdline.txt` specifies a resolution such as
`... video=HDMI-A-1:640x480M@60D`.
"""

import sys

import adafruit_raspberry_pi5_piomatter
import numpy as np

width = 64
height = 32

yoffset = 0
xoffset = 0


if len(sys.argv) >= 2:
width = int(sys.argv[1])
else:
width = 64

if len(sys.argv) >= 3:
height = int(sys.argv[2])
else:
height = 32

if len(sys.argv) >= 4:
rotation = int(sys.argv[3])
if rotation == 90:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.CW
elif rotation == 180:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.R180
elif rotation == 270:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.CCW
elif rotation == 0:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.Normal
else:
raise ValueError("Invalid rotation. Must be 0, 90, 180, or 270.")
else:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.Normal

with open("/sys/class/graphics/fb0/virtual_size") as f:
screenx, screeny = [int(word) for word in f.read().split(",")]

Expand All @@ -32,9 +71,8 @@

linux_framebuffer = np.memmap('/dev/fb0',mode='r', shape=(screeny, stride // bytes_per_pixel), dtype=dtype)

width = 64
height = 32
geometry = adafruit_raspberry_pi5_piomatter.Geometry(width=width, height=height, n_addr_lines=4, rotation=adafruit_raspberry_pi5_piomatter.Orientation.Normal)

geometry = adafruit_raspberry_pi5_piomatter.Geometry(width=width, height=height, n_addr_lines=4, rotation=rotation)
matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width), dtype=dtype)
matrix = adafruit_raspberry_pi5_piomatter.AdafruitMatrixBonnetRGB565(matrix_framebuffer, geometry)

Expand Down
49 changes: 43 additions & 6 deletions examples/fbmirror_scaled.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,59 @@
#!/usr/bin/python3
"""
Mirror a scaled copy of the framebuffer to a 64x32 matrix
Mirror a scaled copy of the framebuffer to 64x32 matrices,
The upper left corner of the framebuffer is displayed until the user hits ctrl-c.
Control scale, matrix size, and orientation with command line arguments.
python fbmirror_scaled.py [scale] [width] [height] [orientation]
scale int: How many times to scale down the display framebuffer. Default is 3.
width int: Total width of matrices in pixels. Default is 64.
height int: Total height of matrices in pixels. Default is 32.
orientation int: Orientation in degrees, must be 0, 90, 180, or 270.
Default is 0 or Normal orientation.
The `/dev/fb0` special file will exist if a monitor is plugged in at boot time,
or if `/boot/firmware/cmdline.txt` specifies a resolution such as
`... video=HDMI-A-1:640x480M@60D`.
"""

import sys

import adafruit_raspberry_pi5_piomatter
import numpy as np
import PIL.Image as Image

if len(sys.argv) >= 2:
scale = int(sys.argv[1])
else:
scale = 3

if len(sys.argv) >= 3:
width = int(sys.argv[2])
else:
width = 64

if len(sys.argv) >= 4:
height = int(sys.argv[3])
else:
height = 32

if len(sys.argv) >= 5:
rotation = int(sys.argv[4])
if rotation == 90:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.CW
elif rotation == 180:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.R180
elif rotation == 270:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.CCW
elif rotation == 0:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.Normal
else:
raise ValueError("Invalid rotation. Must be 0, 90, 180, or 270.")
else:
rotation = adafruit_raspberry_pi5_piomatter.Orientation.Normal

with open("/sys/class/graphics/fb0/virtual_size") as f:
screenx, screeny = [int(word) for word in f.read().split(",")]

Expand All @@ -32,11 +72,8 @@

xoffset = 0
yoffset = 0
width = 64
height = 32
scale = 3

geometry = adafruit_raspberry_pi5_piomatter.Geometry(width=width, height=height, n_addr_lines=4, rotation=adafruit_raspberry_pi5_piomatter.Orientation.Normal)
geometry = adafruit_raspberry_pi5_piomatter.Geometry(width=width, height=height, n_addr_lines=4, rotation=rotation)
matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = adafruit_raspberry_pi5_piomatter.AdafruitMatrixBonnetRGB888Packed(matrix_framebuffer, geometry)

Expand Down
Binary file added examples/nyan.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions examples/play_gif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/python3
"""
Display an animated gif
Run like this:
$ python play_gif.py
The animated gif is played repeatedly until interrupted with ctrl-c.
"""

import time

import adafruit_raspberry_pi5_piomatter
import numpy as np
import PIL.Image as Image

width = 64
height = 32

gif_file = "nyan.gif"

canvas = Image.new('RGB', (width, height), (0, 0, 0))
geometry = adafruit_raspberry_pi5_piomatter.Geometry(width=width, height=height, n_addr_lines=4, rotation=adafruit_raspberry_pi5_piomatter.Orientation.Normal)
framebuffer = np.asarray(canvas) + 0 # Make a mutable copy
matrix = adafruit_raspberry_pi5_piomatter.AdafruitMatrixBonnetRGB888Packed(framebuffer, geometry)

with Image.open(gif_file) as img:
print(f"frames: {img.n_frames}")
while True:
for i in range(img.n_frames):
img.seek(i)
canvas.paste(img, (0,0))
framebuffer[:] = np.asarray(canvas)
matrix.show()
time.sleep(0.1)
66 changes: 66 additions & 0 deletions examples/quote_scroller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/python3
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Display quote from the Adafruit quotes API as text scrolling across the
matrices.
Requires the requests library to be installed.
Run like this:
$ python quote_scroller.py
"""

import adafruit_raspberry_pi5_piomatter
import numpy as np
import requests
from PIL import Image, ImageDraw, ImageFont

# 128px for 2x1 matrices. Change to 64 if you're using a single matrix.
total_width = 128
total_height = 32

bottom_half_shift_compensation = 1

font_color = (0, 128, 128)

# Load the font
font = ImageFont.truetype("LindenHill-webfont.ttf", 26)

quote_resp = requests.get("https://www.adafruit.com/api/quotes.php").json()

text = f'{quote_resp[0]["text"]} - {quote_resp[0]["author"]}'
#text = "Sometimes you just want to use hardcoded strings. - Unknown"

x, y, text_width, text_height = font.getbbox(text)

full_txt_img = Image.new("RGB", (int(text_width) + 6, int(text_height) + 6), (0, 0, 0))
draw = ImageDraw.Draw(full_txt_img)
draw.text((3, 3), text, font=font, fill=font_color)
full_txt_img.save("quote.png")

single_frame_img = Image.new("RGB", (total_width, total_height), (0, 0, 0))

geometry = adafruit_raspberry_pi5_piomatter.Geometry(width=total_width, height=total_height, n_addr_lines=4, rotation=adafruit_raspberry_pi5_piomatter.Orientation.Normal)
framebuffer = np.asarray(single_frame_img) + 0 # Make a mutable copy

matrix = adafruit_raspberry_pi5_piomatter.AdafruitMatrixBonnetRGB888Packed(framebuffer, geometry)

print("Ctrl-C to exit")
while True:
for x_pixel in range(-total_width-1,full_txt_img.width):
if bottom_half_shift_compensation == 0:
# full paste
single_frame_img.paste(full_txt_img.crop((x_pixel, 0, x_pixel + total_width, total_height)), (0, 0))

else:
# top half
single_frame_img.paste(full_txt_img.crop((x_pixel, 0, x_pixel + total_width, total_height//2)), (0, 0))
# bottom half shift compensation
single_frame_img.paste(full_txt_img.crop((x_pixel, total_height//2, x_pixel + total_width, total_height)), (bottom_half_shift_compensation, total_height//2))

framebuffer[:] = np.asarray(single_frame_img)
matrix.show()
102 changes: 102 additions & 0 deletions examples/rainbow_spiral.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/python3
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Display a simple test pattern of 3 shapes on a single 64x32 matrix panel.
Run like this:
$ python simpletest.py
"""
import adafruit_raspberry_pi5_piomatter
import numpy as np
import rainbowio
from PIL import Image, ImageDraw

width = 64
height = 32
pen_radius = 1


canvas = Image.new('RGB', (width, height), (0, 0, 0))
draw = ImageDraw.Draw(canvas)

geometry = adafruit_raspberry_pi5_piomatter.Geometry(width=width, height=height, n_addr_lines=4,
rotation=adafruit_raspberry_pi5_piomatter.Orientation.Normal)
framebuffer = np.asarray(canvas) + 0 # Make a mutable copy
matrix = adafruit_raspberry_pi5_piomatter.AdafruitMatrixBonnetRGB888Packed(framebuffer, geometry)

color_index = 0

def update_matrix():
framebuffer[:] = np.asarray(canvas)
matrix.show()

def darken_color(hex_color, darkness_factor):
# Convert hex color number to RGB
r = (hex_color >> 16) & 0xFF
g = (hex_color >> 8) & 0xFF
b = hex_color & 0xFF

# Apply darkness factor
r = int(r * (1 - darkness_factor))
g = int(g * (1 - darkness_factor))
b = int(b * (1 - darkness_factor))

# Ensure values are within the valid range
r = max(0, min(255, r))
g = max(0, min(255, g))
b = max(0, min(255, b))

# Convert RGB back to hex number
darkened_hex_color = (r << 16) + (g << 8) + b

return darkened_hex_color

step_count = 4
darkness_factor = 0.5

clearing = False

try:
# step_down_size = pen_radius * 2 + 2

while True:
for step in range(step_count):
step_down_size = step * (pen_radius* 2) + (2 * step)
for x in range(pen_radius + step_down_size, width - pen_radius - step_down_size - 1):
color_index = (color_index + 2) % 256
color = darken_color(rainbowio.colorwheel(color_index), darkness_factor) if not clearing else 0x000000
draw.circle((x, pen_radius + step_down_size), pen_radius, color)
update_matrix()
for y in range(pen_radius + step_down_size, height - pen_radius - step_down_size - 1):
color_index = (color_index + 2) % 256
color = darken_color(rainbowio.colorwheel(color_index), darkness_factor) if not clearing else 0x000000
draw.circle((width - pen_radius - step_down_size -1, y), pen_radius, color)
update_matrix()
for x in range(width - pen_radius - step_down_size - 1, pen_radius + step_down_size, -1):
color_index = (color_index + 2) % 256
color = darken_color(rainbowio.colorwheel(color_index), darkness_factor) if not clearing else 0x000000
draw.circle((x, height - pen_radius - step_down_size - 1), pen_radius, color)
update_matrix()
for y in range(height - pen_radius - step_down_size - 1, pen_radius + ((step+1) * (pen_radius* 2) + (2 * (step+1))) -1, -1):
color_index = (color_index + 2) % 256
color = darken_color(rainbowio.colorwheel(color_index), darkness_factor) if not clearing else 0x000000
draw.circle((pen_radius + step_down_size, y), pen_radius, color)
update_matrix()

if step != step_count-1:
# connect to next iter
for x in range(pen_radius + step_down_size, pen_radius + ((step+1) * (pen_radius* 2) + (2 * (step+1)))):
color_index = (color_index + 2) % 256
color = darken_color(rainbowio.colorwheel(color_index),
darkness_factor) if not clearing else 0x000000
draw.circle((x, pen_radius + ((step+1) * (pen_radius* 2) + (2 * (step+1)))), pen_radius, color)
update_matrix()

clearing = not clearing

except KeyboardInterrupt:
print("Exiting")
7 changes: 7 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
Adafruit-Blinka
adafruit-circuitpython-pioasm
numpy
pillow

0 comments on commit 00101f6

Please sign in to comment.