Compare commits

...

20 commits

Author SHA1 Message Date
Limor "Ladyada" Fried
abd7f18fc5
Merge pull request #55 from FoamyGuy/fix_active3_pinouts
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
Fix active3 pinouts swapped pins R and B
2025-08-19 15:04:30 -04:00
foamyguy
b057531ef1 standard pinout for active3 simpletest 2025-08-01 11:04:49 -05:00
foamyguy
d5a979df18 correct active3 pinouts 2025-08-01 11:03:38 -05:00
foamyguy
5d46945596
Merge pull request #49 from FoamyGuy/triple_matrix_stuff
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
active3 simpletest
2025-07-15 08:13:00 -05:00
foamyguy
263f530375 more spiral, more rainbow!! 2025-07-14 17:14:34 -05:00
foamyguy
e9a07d4942 active3 simpletest 2025-07-10 08:46:48 -05:00
foamyguy
792955cf1a
Merge pull request #39 from FoamyGuy/cli_examples_serpentine_fix
add serpentine arg to CLI examples
2025-03-18 13:28:12 -05:00
foamyguy
b35b3d35bb add serpentine arg to CLI examples 2025-03-18 12:20:42 -05:00
foamyguy
0225964f24
Merge pull request #36 from adafruit/large-xfer-workaround
Restore large xfer workaround & actually report errors in pio_sm_xfer_data
2025-03-17 13:47:18 -05:00
89dd515ae5 restore large xfer workaround
sadly, it's not possible to gracefully switch from large to blocked
xfers, further xfer ioctls fail after the first large xfer fails.
2025-03-17 11:29:28 -05:00
fc7295eb74 Actually report errors in pio_sm_xfer_data 2025-03-17 09:26:21 -05:00
b19b6c7cb0
Merge pull request #31 from FoamyGuy/resample_methods
add a way to specify resample method for xdisplay_mirror
2025-03-13 19:38:50 -05:00
foamyguy
fe7c44be88 Merge branch 'refs/heads/main' into resample_methods
# Conflicts:
#	examples/xdisplay_mirror.py
2025-03-13 16:22:30 -05:00
foamyguy
bf3409d92b
Merge pull request #32 from FoamyGuy/brightness_arg
add brightness argument to virtualdisplay and xdisplay_mirror
2025-03-13 16:08:05 -05:00
foamyguy
f80ae1e772
Merge pull request #33 from adafruit/reduce-post-addr-delay
Reduce post addr delay
2025-03-13 16:01:57 -05:00
foamyguy
9465e133b8 add brightness argument to virtualdisplay and xdisplay_mirror 2025-03-12 14:43:08 -05:00
foamyguy
270c8b854c use click.Choice 2025-03-12 11:47:21 -05:00
foamyguy
9a4ed78ca6 add a way to specify resample method for xdisplay_mirror 2025-03-12 10:55:21 -05:00
0a9e578944
Merge pull request #30 from adafruit/jepler-patch-1
Update virtualdisplay.py
2025-03-12 09:18:36 -05:00
499d5c56a7
Update virtualdisplay.py
remove a rogue comment
2025-03-12 09:02:43 -05:00
9 changed files with 158 additions and 36 deletions

View file

@ -44,7 +44,7 @@ def main(xoffset, yoffset, width, height, serpentine, rotation, pinout, n_planes
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_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) 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: 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) 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, serpentine=serpentine)
framebuffer = np.zeros(shape=(geometry.height, geometry.width), dtype=dtype) framebuffer = np.zeros(shape=(geometry.height, geometry.width), dtype=dtype)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB565, pinout=pinout, framebuffer=framebuffer, geometry=geometry) matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB565, pinout=pinout, framebuffer=framebuffer, geometry=geometry)

View file

@ -72,7 +72,7 @@ def main(xoffset, yoffset, scale, width, height, serpentine, rotation, pinout, n
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_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) 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: else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_temporal_planes=n_temporal_planes, n_addr_lines=n_addr_lines, rotation=rotation) geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_temporal_planes=n_temporal_planes, n_addr_lines=n_addr_lines, rotation=rotation, serpentine=serpentine)
matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8) matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=matrix_framebuffer, geometry=geometry) matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=matrix_framebuffer, geometry=geometry)

View file

@ -30,7 +30,7 @@ pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_addr_lines=n_addr_lines, n_planes=10, n_temporal_planes=4, map=pixelmap, n_lanes=n_lanes) geometry = piomatter.Geometry(width=width, height=height, n_addr_lines=n_addr_lines, n_planes=10, n_temporal_planes=4, map=pixelmap, n_lanes=n_lanes)
framebuffer = np.asarray(canvas) + 0 # Make a mutable copy framebuffer = np.asarray(canvas) + 0 # Make a mutable copy
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed,
pinout=piomatter.Pinout.Active3, pinout=piomatter.Pinout.Active3BGR,
framebuffer=framebuffer, framebuffer=framebuffer,
geometry=geometry) geometry=geometry)
@ -66,7 +66,7 @@ def darken_color(hex_color, darkness_factor):
return darkened_hex_color return darkened_hex_color
step_count = 4 step_count = 8
darkness_factor = 0.5 darkness_factor = 0.5
clearing = False clearing = False

View file

@ -0,0 +1,46 @@
#!/usr/bin/python3
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""
Display a simple test pattern of 3 shapes on three 64x64 matrix panels
using Active3 compatible connections.
Run like this:
$ python triple_matrix_active3_simpletest.py
"""
import numpy as np
from PIL import Image, ImageDraw
import adafruit_blinka_raspberry_pi5_piomatter as piomatter
from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
width = 64
n_lanes = 6
n_addr_lines = 5
height = n_lanes << n_addr_lines
pen_radius = 1
canvas = Image.new('RGB', (width, height), (0, 0, 0))
draw = ImageDraw.Draw(canvas)
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_lanes)
geometry = piomatter.Geometry(width=width, height=height, n_addr_lines=n_addr_lines, n_planes=10, n_temporal_planes=4, map=pixelmap, n_lanes=n_lanes)
framebuffer = np.asarray(canvas) + 0 # Make a mutable copy
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed,
pinout=piomatter.Pinout.Active3,
framebuffer=framebuffer,
geometry=geometry)
draw.rectangle((8, 8, width-8, width-8), fill=0x008800)
draw.circle((32, 64+32), 22, fill=0x880000)
draw.polygon([(32, 136), (54, 180), (10, 180)], fill=0x000088)
framebuffer[:] = np.asarray(canvas)
matrix.show()
input("Press enter to exit")

View file

@ -20,14 +20,12 @@ Here's an example for running an emulator using a rom stored in "/tmp/snesrom.sm
$ python virtualdisplay.py --pinout AdafruitMatrixHatBGR --scale 2 --backend xvfb --width 128 --height 128 --serpentine --num-address-lines 5 --num-planes 4 -- mednafen -snes.xscalefs 1 -snes.yscalefs 1 -snes.xres 128 -video.fs 1 -video.driver softfb /tmp/snesrom.smc $ python virtualdisplay.py --pinout AdafruitMatrixHatBGR --scale 2 --backend xvfb --width 128 --height 128 --serpentine --num-address-lines 5 --num-planes 4 -- mednafen -snes.xscalefs 1 -snes.yscalefs 1 -snes.xres 128 -video.fs 1 -video.driver softfb /tmp/snesrom.smc
""" """
# To run a nice emulator:
import shlex import shlex
from subprocess import Popen from subprocess import Popen
import click import click
import numpy as np import numpy as np
from PIL import ImageEnhance
from pyvirtualdisplay.smartdisplay import SmartDisplay from pyvirtualdisplay.smartdisplay import SmartDisplay
import adafruit_blinka_raspberry_pi5_piomatter as piomatter import adafruit_blinka_raspberry_pi5_piomatter as piomatter
@ -40,10 +38,12 @@ from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilan
@click.option("--backend", help="The pyvirtualdisplay backend to use", default="xvfb") @click.option("--backend", help="The pyvirtualdisplay backend to use", default="xvfb")
@click.option("--extra-args", help="Extra arguments to pass to the backend server", default="") @click.option("--extra-args", help="Extra arguments to pass to the backend server", default="")
@click.option("--rfbport", help="The port number for the --backend xvnc", default=None, type=int) @click.option("--rfbport", help="The port number for the --backend xvnc", default=None, type=int)
@click.option("--brightness", help="The brightness factor of the image output to the matrix",
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
@click.argument("command", nargs=-1) @click.argument("command", nargs=-1)
def main(scale, backend, use_xauth, extra_args, rfbport, width, height, serpentine, rotation, pinout, def main(scale, backend, use_xauth, extra_args, rfbport, brightness, width, height, serpentine, rotation, pinout,
n_planes, n_temporal_planes, n_addr_lines, n_lanes, command): n_planes, n_temporal_planes, n_addr_lines, n_lanes, command):
kwargs = {} kwargs = {}
if backend == "xvnc": if backend == "xvnc":
@ -57,15 +57,19 @@ def main(scale, backend, use_xauth, extra_args, rfbport, width, height, serpenti
n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap) n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else: else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, 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) n_temporal_planes=n_temporal_planes, rotation=rotation, serpentine=serpentine)
framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8) 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) 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:
img = disp.grab(autocrop=False) img = disp.grab(autocrop=False)
if img is None: if img is None:
continue continue
if brightness != 1.0:
darkener = ImageEnhance.Brightness(img)
img = darkener.enhance(brightness)
img = img.resize((width, height)) img = img.resize((width, height))
framebuffer[:, :] = np.array(img) framebuffer[:, :] = np.array(img)
matrix.show() matrix.show()

View file

@ -20,27 +20,39 @@ This example command will mirror a 128x128 pixel square from the top left of the
import click import click
import numpy as np import numpy as np
from PIL import ImageGrab from PIL import Image, ImageEnhance, ImageGrab
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 from adafruit_blinka_raspberry_pi5_piomatter.pixelmappers import simple_multilane_mapper
RESAMPLE_MAP = {
"nearest": Image.NEAREST,
"bilinear": Image.BILINEAR,
"lanczos": Image.LANCZOS,
"bicubic": Image.BICUBIC
}
@click.command @click.command
@click.option("--mirror-region", help="Region of X display to mirror. Comma seperated x,y,w,h. " @click.option("--mirror-region", help="Region of X display to mirror. Comma seperated x,y,w,h. "
"Default will mirror entire display.", default="") "Default will mirror entire display.", default="")
@click.option("--x-display", help="The X display to mirror. Default is :0", default=":0") @click.option("--x-display", help="The X display to mirror. Default is :0", default=":0")
@click.option("--brightness", help="The brightness factor of the image output to the matrix",
default=1.0, type=click.FloatRange(min=0.1, max=1.0))
@click.option("--resample-method", type=click.Choice(RESAMPLE_MAP), default="nearest",
help="The resample method for PIL to use when resizing the screen image. Default is nearest")
@piomatter_click.standard_options(n_lanes=2, n_temporal_planes=0) @piomatter_click.standard_options(n_lanes=2, n_temporal_planes=0)
def main(width, height, serpentine, rotation, pinout, n_planes, def main(width, height, serpentine, rotation, pinout, n_planes,
n_temporal_planes, n_addr_lines, n_lanes, mirror_region, x_display): n_temporal_planes, n_addr_lines, n_lanes, mirror_region, x_display, resample_method, brightness):
if n_lanes != 2: if n_lanes != 2:
pixelmap = simple_multilane_mapper(width, height, n_addr_lines, n_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, 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) n_temporal_planes=n_temporal_planes, n_lanes=n_lanes, map=pixelmap)
else: else:
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, 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) n_temporal_planes=n_temporal_planes, rotation=rotation, serpentine=serpentine)
framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8) framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=np.uint8)
matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=framebuffer, matrix = piomatter.PioMatter(colorspace=piomatter.Colorspace.RGB888Packed, pinout=pinout, framebuffer=framebuffer,
@ -59,7 +71,10 @@ def main(width, height, serpentine, rotation, pinout, n_planes,
img = img.crop((mirror_region[0], mirror_region[1], # left,top img = img.crop((mirror_region[0], mirror_region[1], # left,top
mirror_region[0] + mirror_region[2], # right mirror_region[0] + mirror_region[2], # right
mirror_region[1] + mirror_region[3])) # bottom mirror_region[1] + mirror_region[3])) # bottom
img = img.resize((width, height)) if brightness != 1.0:
darkener = ImageEnhance.Brightness(img)
img = darkener.enhance(brightness)
img = img.resize((width, height), RESAMPLE_MAP[resample_method])
framebuffer[:, :] = np.array(img) framebuffer[:, :] = np.array(img)
matrix.show() matrix.show()

View file

@ -41,25 +41,6 @@ struct adafruit_matrix_bonnet_pinout_bgr {
}; };
struct active3_pinout { struct active3_pinout {
static constexpr pin_t PIN_RGB[] = {7, 27, 11, 10, 9, 8, 6, 5, 12,
20, 13, 19, 3, 2, 14, 21, 16, 26};
static constexpr pin_t PIN_ADDR[] = {22, 23, 24, 25, 15};
static constexpr pin_t PIN_OE = 18; // /OE: output enable when LOW
static constexpr pin_t PIN_CLK = 17; // SRCLK: clocks on RISING edge
static constexpr pin_t PIN_LAT = 4; // RCLK: latches on RISING edge
static constexpr uint32_t clk_bit = 1u << PIN_CLK;
static constexpr uint32_t lat_bit = 1u << PIN_LAT;
static constexpr uint32_t oe_bit = 1u << PIN_OE;
static constexpr uint32_t oe_active = 0;
static constexpr uint32_t oe_inactive = oe_bit;
static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 5;
};
struct active3_pinout_bgr {
static constexpr pin_t PIN_RGB[] = {11, 27, 7, 8, 9, 10, 12, 5, 6, static constexpr pin_t PIN_RGB[] = {11, 27, 7, 8, 9, 10, 12, 5, 6,
19, 13, 20, 14, 2, 3, 26, 16, 21}; 19, 13, 20, 14, 2, 3, 26, 16, 21};
static constexpr pin_t PIN_ADDR[] = {22, 23, 24, 25, 15}; static constexpr pin_t PIN_ADDR[] = {22, 23, 24, 25, 15};
@ -78,4 +59,23 @@ struct active3_pinout_bgr {
static constexpr uint32_t post_addr_delay = 5; static constexpr uint32_t post_addr_delay = 5;
}; };
struct active3_pinout_bgr {
static constexpr pin_t PIN_RGB[] = {7, 27, 11, 10, 9, 8, 6, 5, 12,
20, 13, 19, 3, 2, 14, 21, 16, 26};
static constexpr pin_t PIN_ADDR[] = {22, 23, 24, 25, 15};
static constexpr pin_t PIN_OE = 18; // /OE: output enable when LOW
static constexpr pin_t PIN_CLK = 17; // SRCLK: clocks on RISING edge
static constexpr pin_t PIN_LAT = 4; // RCLK: latches on RISING edge
static constexpr uint32_t clk_bit = 1u << PIN_CLK;
static constexpr uint32_t lat_bit = 1u << PIN_LAT;
static constexpr uint32_t oe_bit = 1u << PIN_OE;
static constexpr uint32_t oe_active = 0;
static constexpr uint32_t oe_inactive = oe_bit;
static constexpr uint32_t post_oe_delay = 0;
static constexpr uint32_t post_latch_delay = 0;
static constexpr uint32_t post_addr_delay = 5;
};
} // namespace piomatter } // namespace piomatter

View file

@ -12,6 +12,42 @@
namespace piomatter { namespace piomatter {
static int pio_sm_xfer_data_large(PIO pio, int sm, int direction, size_t size,
uint32_t *databuf) {
#if 0
// it would be NICE to gracefully fall back to blocked transfer, but sadly
// once the large xfer ioctl fails, future small xfers fail too.
static enum { UNKNOWN, OK, BAD } large_xfer_status = UNKNOWN;
printf("large_xfer_status=%d\n", large_xfer_status);
if (large_xfer_status != BAD) {
int r = pio_sm_xfer_data(pio, sm, direction, size, databuf);
if (large_xfer_status == UNKNOWN && r != 0) {
large_xfer_status = BAD;
fprintf(stderr,
"Transmission limit workaround engaged. May reduce quality of "
"output.\nSee https://github.com/raspberrypi/utils/issues/123 "
"for details.\n");
} else {
if (large_xfer_status == UNKNOWN && r == 0) {
large_xfer_status = OK;
}
return r;
}
}
#endif
constexpr size_t MAX_XFER = 65532;
while (size) {
size_t xfersize = std::min(size_t{MAX_XFER}, size);
int r = pio_sm_xfer_data(pio, sm, direction, xfersize, databuf);
if (r != 0) {
return r;
}
size -= xfersize;
databuf += xfersize / sizeof(*databuf);
}
return 0;
}
static uint64_t monotonicns64() { static uint64_t monotonicns64() {
struct timespec tp; struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp); clock_gettime(CLOCK_MONOTONIC, &tp);
@ -26,7 +62,7 @@ struct piomatter_base {
piomatter_base &operator=(const piomatter_base &) = delete; piomatter_base &operator=(const piomatter_base &) = delete;
virtual ~piomatter_base() {} virtual ~piomatter_base() {}
virtual void show() = 0; virtual int show() = 0;
double fps; double fps;
}; };
@ -48,7 +84,11 @@ struct piomatter : piomatter_base {
show(); show();
} }
void show() override { int show() override {
int err = pending_error_errno.exchange(0); // we're handling this error
if (err != 0) {
return err;
}
int buffer_idx = manager.get_free_buffer(); int buffer_idx = manager.get_free_buffer();
auto &bufseq = buffers[buffer_idx]; auto &bufseq = buffers[buffer_idx];
bufseq.resize(geometry.schedules.size()); bufseq.resize(geometry.schedules.size());
@ -61,6 +101,7 @@ struct piomatter : piomatter_base {
old_active_time = geometry.schedules[i].back().active_time; old_active_time = geometry.schedules[i].back().active_time;
} }
manager.put_filled_buffer(buffer_idx); manager.put_filled_buffer(buffer_idx);
return 0;
} }
~piomatter() { ~piomatter() {
@ -174,7 +215,15 @@ struct piomatter : piomatter_base {
const auto &data = cur_buf[seq_idx]; const auto &data = cur_buf[seq_idx];
auto datasize = sizeof(uint32_t) * data.size(); auto datasize = sizeof(uint32_t) * data.size();
auto dataptr = const_cast<uint32_t *>(&data[0]); auto dataptr = const_cast<uint32_t *>(&data[0]);
pio_sm_xfer_data(pio, sm, PIO_DIR_TO_SM, datasize, dataptr); // returns err = rp1_ioctl.... which seems to be a negative
// errno value
int r = pio_sm_xfer_data_large(pio, sm, PIO_DIR_TO_SM, datasize,
dataptr);
if (r != 0) {
pending_error_errno.store(errno);
printf("xfer_data() returned error %d (errno=%s)\n", r,
strerror(errno));
}
t1 = monotonicns64(); t1 = monotonicns64();
if (t0 != t1) { if (t0 != t1) {
fps = 1e9 / (t1 - t0); fps = 1e9 / (t1 - t0);
@ -194,6 +243,7 @@ struct piomatter : piomatter_base {
matrix_geometry geometry; matrix_geometry geometry;
colorspace converter; colorspace converter;
std::thread blitter_thread; std::thread blitter_thread;
std::atomic<int> pending_error_errno;
}; };
} // namespace piomatter } // namespace piomatter

View file

@ -18,7 +18,14 @@ struct PyPiomatter {
py::buffer buffer; py::buffer buffer;
std::unique_ptr<piomatter::piomatter_base> matter; std::unique_ptr<piomatter::piomatter_base> matter;
void show() { matter->show(); } void show() {
int err = matter->show();
if (err != 0) {
errno = err;
PyErr_SetFromErrno(PyExc_OSError);
throw py::error_already_set();
}
}
double fps() const { return matter->fps; } double fps() const { return matter->fps; }
}; };