examples: Add common argument parsing code, use it in fbmirror
Some checks failed
Pip / build (ubuntu-24.04-arm, 3.11) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.12) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.13) (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Wheels / Build SDist (push) Has been cancelled
Wheels / Wheels on ubuntu-24.04-arm (push) Has been cancelled
Wheels / Upload release (push) Has been cancelled
Some checks failed
Pip / build (ubuntu-24.04-arm, 3.11) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.12) (push) Has been cancelled
Pip / build (ubuntu-24.04-arm, 3.13) (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Wheels / Build SDist (push) Has been cancelled
Wheels / Wheels on ubuntu-24.04-arm (push) Has been cancelled
Wheels / Upload release (push) Has been cancelled
Now you can set most anything you'd want from the commandline:
```
Usage: fbmirror.py [OPTIONS]
Options:
--x-offset INTEGER The x offset of top left corner of the
region to mirror
--y-offset INTEGER The y offset of top left corner of the
region to mirror
--num-address-lines INTEGER The number of address lines used by the
panels
--num-planes INTEGER The number of bit planes (color depth. Lower
values can improve refresh rate in frames
per second
--orientation [Normal|R180|CCW|CW]
The overall orientation (rotation) of the
panels
--pinout [AdafruitMatrixBonnet|AdafruitMatrixBonnetBGR|AdafruitMatrixHat|AdafruitMatrixHatBGR]
The details of the electrical connection to
the panels
--colorspace [RGB888Packed|RGB888|RGB565]
The memory organization of the framebuffer
--serpentine / --no-serpentine The organization of multiple panels
--height INTEGER The panel height in pixels
--width INTEGER The panel width in pixels
--help Show this message and exit.
```
It might would be good to apply this generally across the examples.
This commit is contained in:
parent
d27897fd18
commit
1a3f5d4ebe
2 changed files with 110 additions and 51 deletions
|
|
@ -1,59 +1,21 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Mirror a scaled copy of the framebuffer to a 64x32 matrix
|
||||
Mirror a scaled copy of the framebuffer to a matrix
|
||||
|
||||
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.
|
||||
A portion of the framebuffer is displayed until the user hits ctrl-c.
|
||||
|
||||
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`.
|
||||
|
||||
For help with commandline arguments, run `python fbmirror.py --help`
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import adafruit_raspberry_pi5_piomatter
|
||||
import adafruit_raspberry_pi5_piomatter as piomatter
|
||||
import click
|
||||
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
|
||||
import piomatter_click
|
||||
|
||||
with open("/sys/class/graphics/fb0/virtual_size") as f:
|
||||
screenx, screeny = [int(word) for word in f.read().split(",")]
|
||||
|
|
@ -71,11 +33,18 @@ with open("/sys/class/graphics/fb0/stride") as f:
|
|||
|
||||
linux_framebuffer = np.memmap('/dev/fb0',mode='r', shape=(screeny, stride // bytes_per_pixel), dtype=dtype)
|
||||
|
||||
@click.command
|
||||
@click.option("--x-offset", "xoffset", type=int, help="The x offset of top left corner of the region to mirror")
|
||||
@click.option("--y-offset", "yoffset", type=int, help="The y offset of top left corner of the region to mirror")
|
||||
@piomatter_click.standard_options
|
||||
def main(xoffset, yoffset, width, height, serpentine, rotation, colorspace, pinout, n_planes, n_addr_lines):
|
||||
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, rotation=rotation)
|
||||
framebuffer = np.zeros(shape=(geometry.height, geometry.width), dtype=dtype)
|
||||
matrix = piomatter.PioMatter(colorspace=colorspace, pinout=pinout, framebuffer=framebuffer, geometry=geometry)
|
||||
|
||||
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)
|
||||
|
||||
while True:
|
||||
matrix_framebuffer[:,:] = linux_framebuffer[yoffset:yoffset+height, xoffset:xoffset+width]
|
||||
while True:
|
||||
framebuffer[:,:] = linux_framebuffer[yoffset:yoffset+height, xoffset:xoffset+width]
|
||||
matrix.show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
90
examples/piomatter_click.py
Normal file
90
examples/piomatter_click.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# SPDX-FileCopyrightText: 2025 Jeff Epler for Adafruit Industries
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
"""A helper for parsing piomatter settings on the commandline"""
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
import adafruit_raspberry_pi5_piomatter as piomatter
|
||||
import click
|
||||
|
||||
|
||||
class PybindEnumChoice(click.Choice):
|
||||
def __init__(self, enum, case_sensitive=False):
|
||||
self.enum = enum
|
||||
choices = [k for k, v in enum.__dict__.items() if isinstance(v, enum)]
|
||||
super().__init__(choices, case_sensitive)
|
||||
|
||||
def convert(
|
||||
self, value: Any, param: click.Parameter | None, ctx: click.Context | None
|
||||
) -> Any:
|
||||
if isinstance(value, self.enum):
|
||||
return value
|
||||
|
||||
value = super().convert(value, param, ctx)
|
||||
r = getattr(self.enum, value)
|
||||
return r
|
||||
|
||||
def standard_options(
|
||||
f: click.decorators.FC | None = None,
|
||||
*,
|
||||
width=64,
|
||||
height=32,
|
||||
serpentine=True,
|
||||
rotation=piomatter.Orientation.Normal,
|
||||
colorspace=piomatter.Colorspace.RGB888,
|
||||
pinout=piomatter.Pinout.AdafruitMatrixBonnet,
|
||||
n_planes=10,
|
||||
n_addr_lines=4,
|
||||
) -> Callable[[], None]:
|
||||
"""Add standard commandline flags, with the defaults given
|
||||
|
||||
Use like a click decorator:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@click.command
|
||||
@piomatter_click.standard_options()
|
||||
def my_awesome_code(width, height, ...):
|
||||
...
|
||||
|
||||
If a kwarg to this function is None, then the corresponding commandline
|
||||
option is not added at all. For example, if you don't want to offer the
|
||||
``--colorspace`` argument, write ``piomatter_click(..., colorspace=None)``."""
|
||||
def wrapper(f: click.decorators.FC):
|
||||
if width is not None:
|
||||
f = click.option("--width", default=width, help="The panel width in pixels")(f)
|
||||
if height is not None:
|
||||
f = click.option("--height", default=height, help="The panel height in pixels")(f)
|
||||
if serpentine is not None:
|
||||
f = click.option("--serpentine/--no-serpentine", default=serpentine, help="The organization of multiple panels")(f)
|
||||
if colorspace is not None:
|
||||
f = click.option(
|
||||
"--colorspace",
|
||||
default=colorspace,
|
||||
type=PybindEnumChoice(piomatter.Colorspace),
|
||||
help="The memory organization of the framebuffer"
|
||||
)(f)
|
||||
if pinout is not None:
|
||||
f = click.option(
|
||||
"--pinout",
|
||||
default=pinout,
|
||||
type=PybindEnumChoice(piomatter.Pinout),
|
||||
help="The details of the electrical connection to the panels"
|
||||
)(f)
|
||||
if rotation is not None:
|
||||
f = click.option(
|
||||
"--orientation",
|
||||
"rotation",
|
||||
default=rotation,
|
||||
type=PybindEnumChoice(piomatter.Orientation),
|
||||
help="The overall orientation (rotation) of the panels"
|
||||
)(f)
|
||||
if n_planes is not None:
|
||||
f = click.option("--num-planes", "n_planes", default=n_planes, help="The number of bit planes (color depth. Lower values can improve refresh rate in frames per second")(f)
|
||||
if n_addr_lines is not None:
|
||||
f = click.option("--num-address-lines", "n_addr_lines", default=n_addr_lines, help="The number of address lines used by the panels")(f)
|
||||
return f
|
||||
if f is None:
|
||||
return wrapper
|
||||
return wrapper(f)
|
||||
Loading…
Reference in a new issue