WIP move matrix creation into click

This commit is contained in:
Jeff Epler 2025-03-18 11:23:26 -05:00
parent 0225964f24
commit 182529a41b
9 changed files with 55 additions and 30 deletions

View file

@ -19,7 +19,7 @@ jobs:
- name: Set up repository - name: Set up repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: false submodules: true
show-progress: false show-progress: false
fetch-depth: 1 fetch-depth: 1
persist-credentials: false persist-credentials: false

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
/*.pio.h /*.pio.h
/build /build
/dist
/docs/api
*.egg-info *.egg-info

View file

@ -0,0 +1 @@
../build/lib.linux-x86_64-cpython-311/adafruit_blinka_raspberry_pi5_piomatter/

View file

@ -17,7 +17,6 @@ import numpy as np
import adafruit_blinka_raspberry_pi5_piomatter as piomatter import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click
from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
with open("/sys/class/graphics/fb0/virtual_size") as f: with open("/sys/class/graphics/fb0/virtual_size") as f:
screenx, screeny = [int(word) for word in f.read().split(",")] screenx, screeny = [int(word) for word in f.read().split(",")]
@ -39,15 +38,10 @@ linux_framebuffer = np.memmap('/dev/fb0',mode='r', shape=(screeny, stride // byt
@click.option("--x-offset", "xoffset", type=int, help="The x offset of top left corner of the region to mirror", default=0) @click.option("--x-offset", "xoffset", type=int, help="The x offset of top left corner of the region to mirror", default=0)
@click.option("--y-offset", "yoffset", type=int, help="The y offset of top left corner of the region to mirror", default=0) @click.option("--y-offset", "yoffset", type=int, help="The y offset of top left corner of the region to mirror", default=0)
@piomatter_click.standard_options @piomatter_click.standard_options
def main(xoffset, yoffset, width, height, serpentine, rotation, pinout, n_planes, n_temporal_planes, n_addr_lines, n_lanes): @piomatter_click.make_matrix(colorspace=piomatter.Colorspace.RGB565)
if n_lanes != 2: def main(xoffset, yoffset, matrix, framebuffer):
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes) width = matrix.width
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap) height = matrix.height
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, rotation=rotation)
framebuffer = np.zeros(shape=(geometry.height, geometry.width), dtype=dtype)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB565, pinout=pinout, framebuffer=framebuffer, geometry=geometry)
while True: while True:
framebuffer[:,:] = linux_framebuffer[yoffset:yoffset+height, xoffset:xoffset+width] framebuffer[:,:] = linux_framebuffer[yoffset:yoffset+height, xoffset:xoffset+width]
matrix.show() matrix.show()

View file

@ -30,7 +30,6 @@ from pyvirtualdisplay.smartdisplay import SmartDisplay
import adafruit_blinka_raspberry_pi5_piomatter as piomatter import adafruit_blinka_raspberry_pi5_piomatter as piomatter
import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click import adafruit_blinka_raspberry_pi5_piomatter.click as piomatter_click
from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
@click.command @click.command
@ -42,24 +41,18 @@ from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilan
default=1.0, type=click.FloatRange(min=0.1, max=1.0)) default=1.0, type=click.FloatRange(min=0.1, max=1.0))
@click.option("--use-xauth/--no-use-xauth", help="If a Xauthority file should be created", default=False) @click.option("--use-xauth/--no-use-xauth", help="If a Xauthority file should be created", default=False)
@piomatter_click.standard_options @piomatter_click.standard_options
@piomatter_click.make_matrix(colorspace=piomatter.Colorspace.RGB888Packed)
@click.argument("command", nargs=-1) @click.argument("command", nargs=-1)
def main(scale, backend, use_xauth, extra_args, rfbport, brightness, width, height, serpentine, rotation, pinout, def main(matrix, framebuffer, scale, backend, use_xauth, extra_args, rfbport, brightness, command):
n_planes, n_temporal_planes, n_addr_lines, n_lanes, command):
kwargs = {} kwargs = {}
if backend == "xvnc": if backend == "xvnc":
kwargs['rfbport'] = rfbport kwargs['rfbport'] = rfbport
if extra_args: if extra_args:
kwargs['extra_args'] = shlex.split(extra_args) kwargs['extra_args'] = shlex.split(extra_args)
print("xauth", use_xauth) print("xauth", use_xauth)
if n_lanes != 2:
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes) width = matrix.width
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, height = matrix.height
n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines,
n_temporal_planes=n_temporal_planes, rotation=rotation)
framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=framebuffer, geometry=geometry)
with SmartDisplay(backend=backend, use_xauth=use_xauth, size=(round(width*scale),round(height*scale)), manage_global_env=False, **kwargs) as disp, Popen(command, env=disp.env()) as proc: with SmartDisplay(backend=backend, use_xauth=use_xauth, size=(round(width*scale),round(height*scale)), manage_global_env=False, **kwargs) as disp, Popen(command, env=disp.env()) as proc:
while proc.poll() is None: while proc.poll() is None:

View file

@ -1,8 +1,9 @@
# Available at setup time due to pyproject.toml # Available at setup time due to pyproject.toml
from pybind11.setup_helpers import Pybind11Extension, build_ext
from setuptools import setup from setuptools import setup
from setuptools_scm import get_version from setuptools_scm import get_version
from pybind11.setup_helpers import Pybind11Extension, build_ext
__version__ = get_version() __version__ = get_version()
# The main interface is through Pybind11Extension. # The main interface is through Pybind11Extension.

View file

@ -6,9 +6,39 @@ from collections.abc import Callable
from typing import Any from typing import Any
import click import click
import numpy as np
import adafruit_blinka_raspberry_pi5_piomatter as piomatter import adafruit_blinka_raspberry_pi5_piomatter as piomatter
from .pixelmappers import simple_multilane_mapper
def make_matrix(*, colorspace):
print("make_matrix", colorspace)
def do_make_matrix(f):
print("do_make_matrix", f)
def wrapper(width, height, serpentine, rotation, pinout, n_planes, n_temporal_planes, n_addr_lines, n_lanes, **click_args):
if colorspace == piomatter.Colorspace.RGB565:
framebuffer = np.zeros((height, width), dtype=np.uint16)
elif colorspace == piomatter.Colorspace.RGB888:
framebuffer = np.zeros((height, width), dtype=np.uint32)
elif colorspace == piomatter.Colorspace.RGB888Packed:
framebuffer = np.zeros((height, width, 3), dtype=np.uint8)
else:
raise ValueError(f"Unsupported colorspace {colorspace!r}")
if n_lanes != 2:
if serpentine:
raise ValueError("Serpentine is only avaialble with 2 lanes")
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, n_temporal_planes=n_temporal_planes, rotation=rotation)
matrix = piomatter.PioMatter(colorspace=colorspace, pinout=pinout, framebuffer=framebuffer, geometry=geometry)
return f(matrix=matrix, framebuffer=framebuffer, **click_args)
return wrapper
return do_make_matrix
class _PybindEnumChoice(click.Choice): class _PybindEnumChoice(click.Choice):
def __init__(self, enum, case_sensitive=False): def __init__(self, enum, case_sensitive=False):

View file

@ -57,7 +57,7 @@ static uint64_t monotonicns64() {
constexpr size_t MAX_XFER = 65532; constexpr size_t MAX_XFER = 65532;
struct piomatter_base { struct piomatter_base {
piomatter_base() {} piomatter_base(const matrix_geometry &geometry) : geometry{geometry} {}
piomatter_base(const piomatter_base &) = delete; piomatter_base(const piomatter_base &) = delete;
piomatter_base &operator=(const piomatter_base &) = delete; piomatter_base &operator=(const piomatter_base &) = delete;
@ -65,17 +65,18 @@ struct piomatter_base {
virtual int show() = 0; virtual int show() = 0;
double fps; double fps;
matrix_geometry geometry;
}; };
template <class pinout = adafruit_matrix_bonnet_pinout, template <class pinout = adafruit_matrix_bonnet_pinout,
class colorspace = colorspace_rgb888> class colorspace = colorspace_rgb888>
struct piomatter : piomatter_base { struct piomatter : public piomatter_base {
using buffer_type = std::vector<uint32_t>; using buffer_type = std::vector<uint32_t>;
using bufseq_type = std::vector<buffer_type>; using bufseq_type = std::vector<buffer_type>;
piomatter(std::span<typename colorspace::data_type const> framebuffer, piomatter(std::span<typename colorspace::data_type const> framebuffer,
const matrix_geometry &geometry) const matrix_geometry &geometry)
: framebuffer(framebuffer), geometry{geometry}, converter{}, : piomatter_base{geometry},
blitter_thread{} { framebuffer(framebuffer), converter{}, blitter_thread{} {
if (geometry.n_addr_lines > std::size(pinout::PIN_ADDR)) { if (geometry.n_addr_lines > std::size(pinout::PIN_ADDR)) {
throw std::runtime_error("too many address lines requested"); throw std::runtime_error("too many address lines requested");
} }
@ -240,7 +241,6 @@ struct piomatter : piomatter_base {
std::span<typename colorspace::data_type const> framebuffer; std::span<typename colorspace::data_type const> framebuffer;
bufseq_type buffers[3]; bufseq_type buffers[3];
buffer_manager manager{}; buffer_manager manager{};
matrix_geometry geometry;
colorspace converter; colorspace converter;
std::thread blitter_thread; std::thread blitter_thread;
std::atomic<int> pending_error_errno; std::atomic<int> pending_error_errno;

View file

@ -27,6 +27,8 @@ struct PyPiomatter {
} }
} }
double fps() const { return matter->fps; } double fps() const { return matter->fps; }
int width() const { return matter->geometry.width; }
int height() const { return matter->geometry.height; }
}; };
template <typename pinout, typename colorspace> template <typename pinout, typename colorspace>
@ -288,5 +290,7 @@ data is triple-buffered to prevent tearing.
)pbdoc") )pbdoc")
.def_property_readonly("fps", &PyPiomatter::fps, R"pbdoc( .def_property_readonly("fps", &PyPiomatter::fps, R"pbdoc(
The approximate number of matrix refreshes per second. The approximate number of matrix refreshes per second.
)pbdoc"); )pbdoc")
.def_property_readonly("width", &PyPiomatter::width)
.def_property_readonly("height", &PyPiomatter::height);
} }