This commit is contained in:
3
depends/rpi-rgb-led-matrix/bindings/README.md
Normal file
3
depends/rpi-rgb-led-matrix/bindings/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Various bindings to other programming languages.
|
||||
Typically these are wrapping the [C-binding](../include/led-matrix-c.h) that
|
||||
comes with rpi-rgb-led-matrix
|
||||
5
depends/rpi-rgb-led-matrix/bindings/c#/.gitignore
vendored
Normal file
5
depends/rpi-rgb-led-matrix/bindings/c#/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
**/.vs
|
||||
**/bin
|
||||
**/obj
|
||||
**/*.sln
|
||||
**/*.csproj.user
|
||||
85
depends/rpi-rgb-led-matrix/bindings/c#/Bindings.cs
Normal file
85
depends/rpi-rgb-led-matrix/bindings/c#/Bindings.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
global using static RPiRgbLEDMatrix.Bindings;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/*
|
||||
Some of the extern methods listed below are marked with [SuppressGCTransition].
|
||||
This disables some GC checks that may take a long time. But such methods should
|
||||
be fast and trivial, otherwise the managed code may become unstable (see docs).
|
||||
Keep this in mind when changing the C/C++ side.
|
||||
|
||||
https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.suppressgctransitionattribute
|
||||
*/
|
||||
internal static class Bindings
|
||||
{
|
||||
private const string Lib = "librgbmatrix.so.1";
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern IntPtr led_matrix_create(int rows, int chained, int parallel);
|
||||
|
||||
[DllImport(Lib, CharSet = CharSet.Ansi)]
|
||||
public static extern IntPtr led_matrix_create_from_options_const_argv(
|
||||
ref InternalRGBLedMatrixOptions options,
|
||||
int argc,
|
||||
string[] argv);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern void led_matrix_delete(IntPtr matrix);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern IntPtr led_matrix_create_offscreen_canvas(IntPtr matrix);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern IntPtr led_matrix_swap_on_vsync(IntPtr matrix, IntPtr canvas);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern IntPtr led_matrix_get_canvas(IntPtr matrix);
|
||||
|
||||
[DllImport(Lib)]
|
||||
[SuppressGCTransition]
|
||||
public static extern byte led_matrix_get_brightness(IntPtr matrix);
|
||||
|
||||
[DllImport(Lib)]
|
||||
[SuppressGCTransition]
|
||||
public static extern void led_matrix_set_brightness(IntPtr matrix, byte brightness);
|
||||
|
||||
[DllImport(Lib, CharSet = CharSet.Ansi)]
|
||||
public static extern IntPtr load_font(string bdf_font_file);
|
||||
|
||||
[DllImport(Lib, CharSet = CharSet.Ansi)]
|
||||
public static extern int draw_text(IntPtr canvas, IntPtr font, int x, int y, byte r, byte g, byte b,
|
||||
string utf8_text, int extra_spacing);
|
||||
|
||||
[DllImport(Lib, CharSet = CharSet.Ansi)]
|
||||
public static extern int vertical_draw_text(IntPtr canvas, IntPtr font, int x, int y, byte r, byte g, byte b,
|
||||
string utf8_text, int kerning_offset);
|
||||
|
||||
[DllImport(Lib, CharSet = CharSet.Ansi)]
|
||||
public static extern void delete_font(IntPtr font);
|
||||
|
||||
[DllImport(Lib)]
|
||||
[SuppressGCTransition]
|
||||
public static extern void led_canvas_get_size(IntPtr canvas, out int width, out int height);
|
||||
|
||||
[DllImport(Lib)]
|
||||
[SuppressGCTransition]
|
||||
public static extern void led_canvas_set_pixel(IntPtr canvas, int x, int y, byte r, byte g, byte b);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern void led_canvas_set_pixels(IntPtr canvas, int x, int y, int width, int height,
|
||||
ref Color colors);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern void led_canvas_clear(IntPtr canvas);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern void led_canvas_fill(IntPtr canvas, byte r, byte g, byte b);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern void draw_circle(IntPtr canvas, int xx, int y, int radius, byte r, byte g, byte b);
|
||||
|
||||
[DllImport(Lib)]
|
||||
public static extern void draw_line(IntPtr canvas, int x0, int y0, int x1, int y1, byte r, byte g, byte b);
|
||||
}
|
||||
38
depends/rpi-rgb-led-matrix/bindings/c#/Color.cs
Normal file
38
depends/rpi-rgb-led-matrix/bindings/c#/Color.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an RGB (red, green, blue) color
|
||||
/// </summary>
|
||||
public struct Color
|
||||
{
|
||||
/// <summary>
|
||||
/// The red component value of this instance.
|
||||
/// </summary>
|
||||
public byte R;
|
||||
|
||||
/// <summary>
|
||||
/// The green component value of this instance.
|
||||
/// </summary>
|
||||
public byte G;
|
||||
|
||||
/// <summary>
|
||||
/// The blue component value of this instance.
|
||||
/// </summary>
|
||||
public byte B;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new color from the specified color values (red, green, and blue).
|
||||
/// </summary>
|
||||
/// <param name="r">The red component value.</param>
|
||||
/// <param name="g">The green component value.</param>
|
||||
/// <param name="b">The blue component value.</param>
|
||||
public Color(int r, int g, int b) : this((byte)r, (byte)g, (byte)b) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new color from the specified color values (red, green, and blue).
|
||||
/// </summary>
|
||||
/// <param name="r">The red component value.</param>
|
||||
/// <param name="g">The green component value.</param>
|
||||
/// <param name="b">The blue component value.</param>
|
||||
public Color(byte r, byte g, byte b) => (R, G, B) = (r, g, b);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
internal struct InternalRGBLedMatrixOptions
|
||||
{
|
||||
public IntPtr hardware_mapping;
|
||||
public int rows;
|
||||
public int cols;
|
||||
public int chain_length;
|
||||
public int parallel;
|
||||
public int pwm_bits;
|
||||
public int pwm_lsb_nanoseconds;
|
||||
public int pwm_dither_bits;
|
||||
public int brightness;
|
||||
public int scan_mode;
|
||||
public int row_address_type;
|
||||
public int multiplexing;
|
||||
public IntPtr led_rgb_sequence;
|
||||
public IntPtr pixel_mapper_config;
|
||||
public IntPtr panel_type;
|
||||
public byte disable_hardware_pulsing;
|
||||
public byte show_refresh_rate;
|
||||
public byte inverse_colors;
|
||||
public int limit_refresh_rate_hz;
|
||||
|
||||
public InternalRGBLedMatrixOptions(RGBLedMatrixOptions opt)
|
||||
{
|
||||
chain_length = opt.ChainLength;
|
||||
rows = opt.Rows;
|
||||
cols = opt.Cols;
|
||||
hardware_mapping = Marshal.StringToHGlobalAnsi(opt.HardwareMapping);
|
||||
inverse_colors = (byte)(opt.InverseColors ? 1 : 0);
|
||||
led_rgb_sequence = Marshal.StringToHGlobalAnsi(opt.LedRgbSequence);
|
||||
pixel_mapper_config = Marshal.StringToHGlobalAnsi(opt.PixelMapperConfig);
|
||||
panel_type = Marshal.StringToHGlobalAnsi(opt.PanelType);
|
||||
parallel = opt.Parallel;
|
||||
multiplexing = (int)opt.Multiplexing;
|
||||
pwm_bits = opt.PwmBits;
|
||||
pwm_lsb_nanoseconds = opt.PwmLsbNanoseconds;
|
||||
pwm_dither_bits = opt.PwmDitherBits;
|
||||
scan_mode = (int)opt.ScanMode;
|
||||
show_refresh_rate = (byte)(opt.ShowRefreshRate ? 1 : 0);
|
||||
limit_refresh_rate_hz = opt.LimitRefreshRateHz;
|
||||
brightness = opt.Brightness;
|
||||
disable_hardware_pulsing = (byte)(opt.DisableHardwarePulsing ? 1 : 0);
|
||||
row_address_type = opt.RowAddressType;
|
||||
}
|
||||
};
|
||||
34
depends/rpi-rgb-led-matrix/bindings/c#/Makefile
Normal file
34
depends/rpi-rgb-led-matrix/bindings/c#/Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
# This Makefile is intended to be used only by the toplevel Makefile.
|
||||
# For any other purposes, use .NET SDK build tools directly
|
||||
|
||||
# Don't forget to synchronize these variables with the 'RPiRgbLEDMatrix.csproj' file
|
||||
RGB_LIBDIR=../../lib
|
||||
RGB_LIBRARY_NAME=rgbmatrix
|
||||
RGB_LIBRARY=$(RGB_LIBDIR)/lib$(RGB_LIBRARY_NAME).so.1
|
||||
|
||||
NUGET_VERSION = 1.0.0
|
||||
NUGET_ID = HZeller.RPiRgbLEDMatrix
|
||||
NUGET_CONFIG = Release
|
||||
|
||||
NUGET_PACKAGE = /bin/$(NUGET_CONFIG)/$(NUGET_ID).$(NUGET_VERSION).nupkg
|
||||
|
||||
$(NUGET_PACKAGE): $(RGB_LIBRARY)
|
||||
dotnet pack -c $(NUGET_CONFIG) -p:SkipNative=false -p:PackageId=$(NUGET_ID) -p:Version=$(NUGET_VERSION)
|
||||
|
||||
# The examples also depend on the 'RPiRgbLEDMatrix.csproj', but this will be handled by 'dotnet'
|
||||
build: $(RGB_LIBRARY)
|
||||
dotnet build examples/FontExample/FontExample.csproj -p:SkipNative=false
|
||||
dotnet build examples/MatrixRain/MatrixRain.csproj -p:SkipNative=false
|
||||
dotnet build examples/MinimalExample/MinimalExample.csproj -p:SkipNative=false
|
||||
dotnet build examples/PulsingBrightness/PulsingBrightness.csproj -p:SkipNative=false
|
||||
dotnet build examples/Rotating3DCube/Rotating3DCube.csproj -p:SkipNative=false
|
||||
dotnet build examples/PlayGIF/PlayGIF.csproj -p:SkipNative=false
|
||||
|
||||
$(RGB_LIBRARY):
|
||||
$(MAKE) -C $(RGB_LIBDIR)
|
||||
|
||||
# Used by toplevel Makefile
|
||||
nuget: $(NUGET_PACKAGE)
|
||||
|
||||
# Used in 'RPiRgbLEDMatrix.csproj'
|
||||
library: $(RGB_LIBRARY)
|
||||
11
depends/rpi-rgb-led-matrix/bindings/c#/Multiplexing.cs
Normal file
11
depends/rpi-rgb-led-matrix/bindings/c#/Multiplexing.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Type of multiplexing.
|
||||
/// </summary>
|
||||
public enum Multiplexing : int
|
||||
{
|
||||
Direct = 0,
|
||||
Stripe = 1,
|
||||
Checker = 2
|
||||
}
|
||||
16
depends/rpi-rgb-led-matrix/bindings/c#/README.md
Normal file
16
depends/rpi-rgb-led-matrix/bindings/c#/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
C# bindings for RGB Matrix library
|
||||
======================================
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
To build the C# wrapper for the RGB Matrix C library you need to first have __.NET SDK__ installed.
|
||||
|
||||
### Install .NET SDK
|
||||
|
||||
`sudo apt install dotnet6` should work in most cases.
|
||||
For some old distributions, read [docs](https://learn.microsoft.com/dotnet/core/install/linux)
|
||||
|
||||
Then, in the `bindings/c#` directory type: `dotnet build`
|
||||
|
||||
To run the example applications in the c#\examples\EXAMPLE folder: `sudo dotnet run`
|
||||
100
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedCanvas.cs
Normal file
100
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedCanvas.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a canvas whose pixels can be manipulated.
|
||||
/// </summary>
|
||||
public class RGBLedCanvas
|
||||
{
|
||||
// This is a wrapper for canvas no need to implement IDisposable here
|
||||
// because RGBLedMatrix has ownership and takes care of disposing canvases
|
||||
internal IntPtr _canvas;
|
||||
|
||||
// this is not called directly by the consumer code,
|
||||
// consumer uses factory methods in RGBLedMatrix
|
||||
internal RGBLedCanvas(IntPtr canvas)
|
||||
{
|
||||
_canvas = canvas;
|
||||
led_canvas_get_size(_canvas, out var width, out var height);
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The width of the canvas in pixels.
|
||||
/// </summary>
|
||||
public int Width { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The height of the canvas in pixels.
|
||||
/// </summary>
|
||||
public int Height { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color of a specific pixel.
|
||||
/// </summary>
|
||||
/// <param name="x">The X coordinate of the pixel.</param>
|
||||
/// <param name="y">The Y coordinate of the pixel.</param>
|
||||
/// <param name="color">New pixel color.</param>
|
||||
public void SetPixel(int x, int y, Color color) => led_canvas_set_pixel(_canvas, x, y, color.R, color.G, color.B);
|
||||
|
||||
/// <summary>
|
||||
/// Copies the colors from the specified buffer to a rectangle on the canvas.
|
||||
/// </summary>
|
||||
/// <param name="x">The X coordinate of the top-left pixel of the rectangle.</param>
|
||||
/// <param name="y">The Y coordinate of the top-left pixel of the rectangle.</param>
|
||||
/// <param name="width">Width of the rectangle.</param>
|
||||
/// <param name="height">Height of the rectangle.</param>
|
||||
/// <param name="colors">Buffer containing the colors to copy.</param>
|
||||
public void SetPixels(int x, int y, int width, int height, Span<Color> colors)
|
||||
{
|
||||
if (colors.Length < width * height)
|
||||
throw new ArgumentOutOfRangeException(nameof(colors));
|
||||
led_canvas_set_pixels(_canvas, x, y, width, height, ref colors[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color of the entire canvas.
|
||||
/// </summary>
|
||||
/// <param name="color">New canvas color.</param>
|
||||
public void Fill(Color color) => led_canvas_fill(_canvas, color.R, color.G, color.B);
|
||||
|
||||
/// <summary>
|
||||
/// Cleans the entire canvas.
|
||||
/// </summary>
|
||||
public void Clear() => led_canvas_clear(_canvas);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a circle of the specified color.
|
||||
/// </summary>
|
||||
/// <param name="x">The X coordinate of the center.</param>
|
||||
/// <param name="y">The Y coordinate of the center.</param>
|
||||
/// <param name="radius">The radius of the circle, in pixels.</param>
|
||||
/// <param name="color">The color of the circle.</param>
|
||||
public void DrawCircle(int x, int y, int radius, Color color) =>
|
||||
draw_circle(_canvas, x, y, radius, color.R, color.G, color.B);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a line of the specified color.
|
||||
/// </summary>
|
||||
/// <param name="x0">The X coordinate of the first point.</param>
|
||||
/// <param name="y0">The Y coordinate of the first point.</param>
|
||||
/// <param name="x1">The X coordinate of the second point.</param>
|
||||
/// <param name="y1">The Y coordinate of the second point.</param>
|
||||
/// <param name="color">The color of the line.</param>
|
||||
public void DrawLine(int x0, int y0, int x1, int y1, Color color) =>
|
||||
draw_line(_canvas, x0, y0, x1, y1, color.R, color.G, color.B);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the text with the specified color.
|
||||
/// </summary>
|
||||
/// <param name="font">Font to draw text with.</param>
|
||||
/// <param name="x">The X coordinate of the starting point.</param>
|
||||
/// <param name="y">The Y coordinate of the starting point.</param>
|
||||
/// <param name="color">The color of the text.</param>
|
||||
/// <param name="text">Text to draw.</param>
|
||||
/// <param name="spacing">Additional spacing between characters.</param>
|
||||
/// <param name="vertical">Whether to draw the text vertically.</param>
|
||||
/// <returns>How many pixels was advanced on the screen.</returns>
|
||||
public int DrawText(RGBLedFont font, int x, int y, Color color, string text, int spacing = 0, bool vertical = false) =>
|
||||
font.DrawText(_canvas, x, y, color, text, spacing, vertical);
|
||||
}
|
||||
40
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedFont.cs
Normal file
40
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedFont.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a <c>.BDF</c> font.
|
||||
/// </summary>
|
||||
public class RGBLedFont : IDisposable
|
||||
{
|
||||
internal IntPtr _font;
|
||||
private bool disposedValue = false;
|
||||
|
||||
/// <summary>
|
||||
/// Loads the BDF font from the specified file.
|
||||
/// </summary>
|
||||
/// <param name="bdfFontPath">The path to the BDF file to load.</param>
|
||||
public RGBLedFont(string bdfFontPath) => _font = load_font(bdfFontPath);
|
||||
|
||||
internal int DrawText(IntPtr canvas, int x, int y, Color color, string text, int spacing = 0, bool vertical = false)
|
||||
{
|
||||
if (!vertical)
|
||||
return draw_text(canvas, _font, x, y, color.R, color.G, color.B, text, spacing);
|
||||
else
|
||||
return vertical_draw_text(canvas, _font, x, y, color.R, color.G, color.B, text, spacing);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposedValue) return;
|
||||
delete_font(_font);
|
||||
disposedValue = true;
|
||||
}
|
||||
|
||||
~RGBLedFont() => Dispose(false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
112
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedMatrix.cs
Normal file
112
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedMatrix.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System.Buffers;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a RGB matrix.
|
||||
/// </summary>
|
||||
public class RGBLedMatrix : IDisposable
|
||||
{
|
||||
private IntPtr matrix;
|
||||
private bool disposedValue = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new matrix.
|
||||
/// </summary>
|
||||
/// <param name="rows">Size of a single module. Can be 32, 16 or 8.</param>
|
||||
/// <param name="chained">How many modules are connected in a chain.</param>
|
||||
/// <param name="parallel">How many modules are connected in a parallel.</param>
|
||||
public RGBLedMatrix(int rows, int chained, int parallel)
|
||||
{
|
||||
matrix = led_matrix_create(rows, chained, parallel);
|
||||
if (matrix == (IntPtr)0)
|
||||
throw new ArgumentException("Could not initialize a new matrix");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new matrix.
|
||||
/// </summary>
|
||||
/// <param name="options">A configuration of a matrix.</param>
|
||||
public RGBLedMatrix(RGBLedMatrixOptions options)
|
||||
{
|
||||
InternalRGBLedMatrixOptions opt = default;
|
||||
try
|
||||
{
|
||||
opt = new(options);
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
|
||||
// Because gpio-slowdown is not provided in the options struct,
|
||||
// we manually add it.
|
||||
// Let's add it first to the command-line we pass to the
|
||||
// matrix constructor, so that it can be overridden with the
|
||||
// users' commandline.
|
||||
// As always, as the _very_ first, we need to provide the
|
||||
// program name argv[0].
|
||||
var argv = new string[args.Length + 1];
|
||||
argv[0] = args[0];
|
||||
argv[1] = $"--led-slowdown-gpio={options.GpioSlowdown}";
|
||||
Array.Copy(args, 1, argv, 2, args.Length - 1);
|
||||
|
||||
matrix = led_matrix_create_from_options_const_argv(ref opt, argv.Length, argv);
|
||||
if (matrix == (IntPtr)0)
|
||||
throw new ArgumentException("Could not initialize a new matrix");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(options.HardwareMapping is not null) Marshal.FreeHGlobal(opt.hardware_mapping);
|
||||
if(options.LedRgbSequence is not null) Marshal.FreeHGlobal(opt.led_rgb_sequence);
|
||||
if(options.PixelMapperConfig is not null) Marshal.FreeHGlobal(opt.pixel_mapper_config);
|
||||
if(options.PanelType is not null) Marshal.FreeHGlobal(opt.panel_type);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new backbuffer canvas for drawing on.
|
||||
/// </summary>
|
||||
/// <returns>An instance of <see cref="RGBLedCanvas"/> representing the canvas.</returns>
|
||||
public RGBLedCanvas CreateOffscreenCanvas() => new(led_matrix_create_offscreen_canvas(matrix));
|
||||
|
||||
/// <summary>
|
||||
/// Returns a canvas representing the current frame buffer.
|
||||
/// </summary>
|
||||
/// <returns>An instance of <see cref="RGBLedCanvas"/> representing the canvas.</returns>
|
||||
/// <remarks>Consider using <see cref="CreateOffscreenCanvas"/> instead.</remarks>
|
||||
public RGBLedCanvas GetCanvas() => new(led_matrix_get_canvas(matrix));
|
||||
|
||||
/// <summary>
|
||||
/// Swaps this canvas with the currently active canvas. The active canvas
|
||||
/// becomes a backbuffer and is mapped to <paramref name="canvas"/> instance.
|
||||
/// <br/>
|
||||
/// This operation guarantees vertical synchronization.
|
||||
/// </summary>
|
||||
/// <param name="canvas">Backbuffer canvas to swap.</param>
|
||||
public void SwapOnVsync(RGBLedCanvas canvas) =>
|
||||
canvas._canvas = led_matrix_swap_on_vsync(matrix, canvas._canvas);
|
||||
|
||||
/// <summary>
|
||||
/// The general brightness of the matrix.
|
||||
/// </summary>
|
||||
public byte Brightness
|
||||
{
|
||||
get => led_matrix_get_brightness(matrix);
|
||||
set => led_matrix_set_brightness(matrix, value);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposedValue) return;
|
||||
|
||||
led_matrix_delete(matrix);
|
||||
disposedValue = true;
|
||||
}
|
||||
|
||||
~RGBLedMatrix() => Dispose(false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
124
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedMatrixOptions.cs
Normal file
124
depends/rpi-rgb-led-matrix/bindings/c#/RGBLedMatrixOptions.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the matrix settings.
|
||||
/// </summary>
|
||||
public struct RGBLedMatrixOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the hardware mapping used. If passed
|
||||
/// <see langword="null"/> here, the default is used.
|
||||
/// </summary>
|
||||
public string? HardwareMapping = null;
|
||||
|
||||
/// <summary>
|
||||
/// The "rows" are the number of rows supported by the display, so 32 or 16.
|
||||
/// Default: 32.
|
||||
/// </summary>
|
||||
public int Rows = 32;
|
||||
|
||||
/// <summary>
|
||||
/// The "cols" are the number of columns per panel. Typically something
|
||||
/// like 32, but also 64 is possible. Sometimes even 40.
|
||||
/// <c>cols * chain_length</c> is the total length of the display, so you can
|
||||
/// represent a 64 wide display as cols=32, chain=2 or cols=64, chain=1;
|
||||
/// same thing, but more convenient to think of.
|
||||
/// </summary>
|
||||
public int Cols = 32;
|
||||
|
||||
/// <summary>
|
||||
/// The chain_length is the number of displays daisy-chained together
|
||||
/// (output of one connected to input of next). Default: 1
|
||||
/// </summary>
|
||||
public int ChainLength = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The number of parallel chains connected to the Pi; in old Pis with 26
|
||||
/// GPIO pins, that is 1, in newer Pis with 40 interfaces pins, that can also
|
||||
/// be 2 or 3. The effective number of pixels in vertical direction is then
|
||||
/// thus <c>rows * parallel</c>. Default: 1
|
||||
/// </summary>
|
||||
public int Parallel = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Set PWM bits used for output. Default is 11, but if you only deal with limited
|
||||
/// comic-colors, 1 might be sufficient. Lower require less CPU and increases refresh-rate.
|
||||
/// </summary>
|
||||
public int PwmBits = 11;
|
||||
|
||||
/// <summary>
|
||||
/// Change the base time-unit for the on-time in the lowest significant bit in
|
||||
/// nanoseconds. Higher numbers provide better quality (more accurate color, less
|
||||
/// ghosting), but have a negative impact on the frame rate.
|
||||
/// </summary>
|
||||
public int PwmLsbNanoseconds = 130;
|
||||
|
||||
/// <summary>
|
||||
/// The lower bits can be time-dithered for higher refresh rate.
|
||||
/// </summary>
|
||||
public int PwmDitherBits = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The initial brightness of the panel in percent. Valid range is 1..100
|
||||
/// </summary>
|
||||
public int Brightness = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Scan mode.
|
||||
/// </summary>
|
||||
public ScanModes ScanMode = ScanModes.Progressive;
|
||||
|
||||
/// <summary>
|
||||
/// Default row address type is 0, corresponding to direct setting of the
|
||||
/// row, while row address type 1 is used for panels that only have A/B,
|
||||
/// typically some 64x64 panels
|
||||
/// </summary>
|
||||
public int RowAddressType = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Type of multiplexing.
|
||||
/// </summary>
|
||||
public Multiplexing Multiplexing = Multiplexing.Direct;
|
||||
|
||||
/// <summary>
|
||||
/// In case the internal sequence of mapping is not <c>"RGB"</c>, this
|
||||
/// contains the real mapping. Some panels mix up these colors.
|
||||
/// </summary>
|
||||
public string? LedRgbSequence = null;
|
||||
|
||||
/// <summary>
|
||||
/// A string describing a sequence of pixel mappers that should be applied
|
||||
/// to this matrix. A semicolon-separated list of pixel-mappers with optional
|
||||
/// parameter.
|
||||
public string? PixelMapperConfig = null;
|
||||
|
||||
/// <summary>
|
||||
/// Panel type. Typically just empty, but certain panels (FM6126)
|
||||
/// requie an initialization sequence
|
||||
/// </summary>
|
||||
public string? PanelType = null;
|
||||
|
||||
/// <summary>
|
||||
/// Allow to use the hardware subsystem to create pulses. This won't do
|
||||
/// anything if output enable is not connected to GPIO 18.
|
||||
/// </summary>
|
||||
public bool DisableHardwarePulsing = false;
|
||||
public bool ShowRefreshRate = false;
|
||||
public bool InverseColors = false;
|
||||
|
||||
/// <summary>
|
||||
/// Limit refresh rate of LED panel. This will help on a loaded system
|
||||
/// to keep a constant refresh rate. <= 0 for no limit.
|
||||
/// </summary>
|
||||
public int LimitRefreshRateHz = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Slowdown GPIO. Needed for faster Pis/slower panels.
|
||||
/// </summary>
|
||||
public int GpioSlowdown = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Creates default matrix settings.
|
||||
/// </summary>
|
||||
public RGBLedMatrixOptions() { }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Skip builing native libraries by default on Windows -->
|
||||
<PropertyGroup Condition="$(SkipNative) == '' and $(OS) != 'Unix'">
|
||||
<SkipNative>true</SkipNative>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="examples\**" />
|
||||
<None Remove="examples\**" />
|
||||
<None Condition="$(SkipNative) != 'true'" Pack="true"
|
||||
Include="..\..\lib\librgbmatrix.so.1"
|
||||
PackagePath="\runtimes\linux-arm64\native" >
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CompileNative" BeforeTargets="Compile" Condition="$(SkipNative) != 'true'">
|
||||
<Message Text="Building native libraries" />
|
||||
<Exec Command="make library" />
|
||||
</Target>
|
||||
</Project>
|
||||
10
depends/rpi-rgb-led-matrix/bindings/c#/ScanModes.cs
Normal file
10
depends/rpi-rgb-led-matrix/bindings/c#/ScanModes.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace RPiRgbLEDMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Scan modes.
|
||||
/// </summary>
|
||||
public enum ScanModes
|
||||
{
|
||||
Progressive = 0,
|
||||
Interlaced = 1
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\RPiRgbLEDMatrix.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,29 @@
|
||||
using RPiRgbLEDMatrix;
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
Console.WriteLine("font-example.exe [font_path] <text>");
|
||||
return -1;
|
||||
}
|
||||
string text = "Hello World!";
|
||||
if (args.Length > 1)
|
||||
text = args[1];
|
||||
|
||||
|
||||
using var matrix = new RGBLedMatrix(32, 2, 1);
|
||||
var canvas = matrix.CreateOffscreenCanvas();
|
||||
using var font = new RGBLedFont(args[0]);
|
||||
|
||||
canvas.DrawText(font, 1, 6, new Color(0, 255, 0), text);
|
||||
matrix.SwapOnVsync(canvas);
|
||||
|
||||
// run until user presses Ctrl+C
|
||||
var running = true;
|
||||
Console.CancelKeyPress += (_, e) =>
|
||||
{
|
||||
running = false;
|
||||
e.Cancel = true; // do not terminate program with Ctrl+C, we need to dispose
|
||||
};
|
||||
while (running) Thread.Yield();
|
||||
|
||||
return 0;
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\RPiRgbLEDMatrix.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,74 @@
|
||||
using RPiRgbLEDMatrix;
|
||||
|
||||
const int MaxHeight = 16;
|
||||
const int ColorStep = 15;
|
||||
const int FrameStep = 1;
|
||||
|
||||
using var matrix = new RGBLedMatrix(new RGBLedMatrixOptions { ChainLength = 2 });
|
||||
var canvas = matrix.CreateOffscreenCanvas();
|
||||
|
||||
var rnd = new Random();
|
||||
var points = new List<Point>();
|
||||
var recycled = new Stack<Point>();
|
||||
var frame = 0;
|
||||
|
||||
var running = true;
|
||||
Console.CancelKeyPress += (s, e) =>
|
||||
{
|
||||
running = false;
|
||||
e.Cancel = true; // don't terminate, we need to dispose
|
||||
};
|
||||
|
||||
// run until user presses Ctrl+C
|
||||
while (running)
|
||||
{
|
||||
var frameStart = Environment.TickCount64;
|
||||
frame++;
|
||||
|
||||
if (frame % FrameStep == 0)
|
||||
{
|
||||
if (recycled.Count == 0)
|
||||
points.Add(new Point(rnd.Next(0, canvas.Width - 1), 0));
|
||||
else
|
||||
{
|
||||
var point = recycled.Pop();
|
||||
point.X = rnd.Next(0, canvas.Width - 1);
|
||||
point.Y = 0;
|
||||
point.Recycled = false;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.Clear();
|
||||
|
||||
foreach (var point in points)
|
||||
{
|
||||
if (point.Recycled) continue;
|
||||
point.Y++;
|
||||
|
||||
if (point.Y - MaxHeight > canvas.Height)
|
||||
{
|
||||
point.Recycled = true;
|
||||
recycled.Push(point);
|
||||
}
|
||||
|
||||
for (var i = 0; i < MaxHeight; i++)
|
||||
{
|
||||
canvas.SetPixel(point.X, point.Y - i, new Color(0, 255 - i * ColorStep, 0));
|
||||
}
|
||||
}
|
||||
|
||||
matrix.SwapOnVsync(canvas);
|
||||
|
||||
// force 30 FPS
|
||||
var elapsed = Environment.TickCount64 - frameStart;
|
||||
if (elapsed < 33) Thread.Sleep(33 - (int)elapsed);
|
||||
}
|
||||
|
||||
class Point
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public bool Recycled = false;
|
||||
|
||||
public Point(int x, int y) => (X, Y) = (x, y);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\RPiRgbLEDMatrix.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,19 @@
|
||||
using RPiRgbLEDMatrix;
|
||||
|
||||
using var matrix = new RGBLedMatrix(32, 2, 1);
|
||||
var canvas = matrix.CreateOffscreenCanvas();
|
||||
|
||||
var centerX = canvas.Width / 2;
|
||||
var centerY = canvas.Height / 2;
|
||||
for (var i = 0; i < 1000; ++i)
|
||||
{
|
||||
for (var y = 0; y < canvas.Height; ++y)
|
||||
for (var x = 0; x < canvas.Width; ++x)
|
||||
canvas.SetPixel(x, y, new Color(i & 0xFF, x, y));
|
||||
|
||||
canvas.DrawCircle(centerX, centerY, 6, new Color(0, 0, 255));
|
||||
canvas.DrawLine(centerX - 3, centerY - 3, centerX + 3, centerY + 3, new Color(0, 0, 255));
|
||||
canvas.DrawLine(centerX - 3, centerY + 3, centerX + 3, centerY - 3, new Color(0, 0, 255));
|
||||
|
||||
matrix.SwapOnVsync(canvas);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\RPiRgbLEDMatrix.csproj" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,40 @@
|
||||
using RPiRgbLEDMatrix;
|
||||
using System.Runtime.InteropServices;
|
||||
using Color = RPiRgbLEDMatrix.Color;
|
||||
|
||||
Console.Write("GIF path: ");
|
||||
var path = Console.ReadLine()!;
|
||||
|
||||
using var matrix = new RGBLedMatrix(32, 2, 1);
|
||||
var canvas = matrix.CreateOffscreenCanvas();
|
||||
|
||||
Configuration.Default.PreferContiguousImageBuffers = true;
|
||||
using var image = Image.Load<Rgb24>(path);
|
||||
image.Mutate(o => o.Resize(canvas.Width, canvas.Height));
|
||||
|
||||
var running = true;
|
||||
Console.CancelKeyPress += (s, e) =>
|
||||
{
|
||||
running = false;
|
||||
e.Cancel = true; // don't terminate, we need to dispose
|
||||
};
|
||||
|
||||
var frame = -1;
|
||||
// preprocess frames to get delays and pixel buffers
|
||||
var frames = image.Frames
|
||||
.Select(f => (
|
||||
Pixels: f.DangerousTryGetSinglePixelMemory(out var memory) ? memory : throw new("Could not get pixel buffer"),
|
||||
Delay: f.Metadata.GetGifMetadata().FrameDelay * 10
|
||||
)).ToArray();
|
||||
|
||||
// run until user presses Ctrl+C
|
||||
while (running)
|
||||
{
|
||||
frame = (frame + 1) % frames.Length;
|
||||
|
||||
var data = MemoryMarshal.Cast<Rgb24, Color>(frames[frame].Pixels.Span);
|
||||
canvas.SetPixels(0, 0, canvas.Width, canvas.Height, data);
|
||||
|
||||
matrix.SwapOnVsync(canvas);
|
||||
Thread.Sleep(frames[frame].Delay);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using RPiRgbLEDMatrix;
|
||||
|
||||
using var matrix = new RGBLedMatrix(new RGBLedMatrixOptions { Rows = 32, Cols = 64 });
|
||||
var canvas = matrix.CreateOffscreenCanvas();
|
||||
|
||||
var maxBrightness = matrix.Brightness;
|
||||
var rnd = new Random();
|
||||
|
||||
// run until user presses Ctrl+C
|
||||
var running = true;
|
||||
Console.CancelKeyPress += (_, e) =>
|
||||
{
|
||||
running = false;
|
||||
e.Cancel = true; // do not terminate program with Ctrl+C, we need to dispose
|
||||
};
|
||||
|
||||
var color = new Color(rnd.Next(0, 256), rnd.Next(0, 256), rnd.Next(0, 256));
|
||||
while (running)
|
||||
{
|
||||
if (matrix.Brightness < 1)
|
||||
{
|
||||
matrix.Brightness = maxBrightness;
|
||||
color = new Color(rnd.Next(0, 256), rnd.Next(0, 256), rnd.Next(0, 256));
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix.Brightness--;
|
||||
}
|
||||
|
||||
canvas.Fill(color);
|
||||
matrix.SwapOnVsync(canvas);
|
||||
Thread.Sleep(20);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\RPiRgbLEDMatrix.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,90 @@
|
||||
using RPiRgbLEDMatrix;
|
||||
using System.Numerics;
|
||||
|
||||
const float MaxModuleSpeed = 0.1f;
|
||||
const float FOV = 60f;
|
||||
const float Scale = 1.1f;
|
||||
const float LerpPow = 0.002f;
|
||||
const int ChangePerFrames = 50;
|
||||
|
||||
using var leds = new RGBLedMatrix(32, 1, 1);
|
||||
var canvas = leds.CreateOffscreenCanvas();
|
||||
|
||||
var (centerX, centerY) = (canvas.Width / 2, canvas.Height / 2);
|
||||
|
||||
var rnd = new Random();
|
||||
var angleSpeed = new Vector3();
|
||||
var nextAngleSpeed = new Vector3();
|
||||
var frame = -1;
|
||||
|
||||
var rotateMatrix = Matrix4x4.Identity;
|
||||
var scaleMatrix = Matrix4x4.CreateScale(Scale);
|
||||
var projectMatrix = Matrix4x4.CreatePerspectiveFieldOfView(FOV / 180 * MathF.PI, 1, 0.1f, 100f);
|
||||
var cameraMatrix = Matrix4x4.CreateLookAt(new(0, 0, 4), new(0, 0, 0), new(0, 1, 0));
|
||||
|
||||
// run until user presses Ctrl+C
|
||||
var running = true;
|
||||
Console.CancelKeyPress += (_, e) =>
|
||||
{
|
||||
running = false;
|
||||
e.Cancel = true; // do not terminate program with Ctrl+C, we need to dispose
|
||||
};
|
||||
while (running)
|
||||
{
|
||||
var frameStart = Environment.TickCount64;
|
||||
|
||||
// update angle speed
|
||||
frame = (frame + 1) % ChangePerFrames;
|
||||
if(frame == 0)
|
||||
nextAngleSpeed = new Vector3(
|
||||
(rnd.NextSingle() * 2 - 1) * MaxModuleSpeed,
|
||||
(rnd.NextSingle() * 2 - 1) * MaxModuleSpeed,
|
||||
(rnd.NextSingle() * 2 - 1) * MaxModuleSpeed
|
||||
);
|
||||
|
||||
angleSpeed = Vector3.Lerp(angleSpeed, nextAngleSpeed, LerpPow);
|
||||
|
||||
// update matrices
|
||||
rotateMatrix *= Matrix4x4.CreateRotationX(angleSpeed.X);
|
||||
rotateMatrix *= Matrix4x4.CreateRotationY(angleSpeed.Y);
|
||||
rotateMatrix *= Matrix4x4.CreateRotationZ(angleSpeed.Z);
|
||||
var matrix = scaleMatrix * rotateMatrix * cameraMatrix * projectMatrix;
|
||||
|
||||
// calculate points
|
||||
var top1 = Vector4.Transform(new Vector3( 1, 1, 1), matrix);
|
||||
var top2 = Vector4.Transform(new Vector3(-1, 1, 1), matrix);
|
||||
var top3 = Vector4.Transform(new Vector3(-1, 1, -1), matrix);
|
||||
var top4 = Vector4.Transform(new Vector3( 1, 1, -1), matrix);
|
||||
|
||||
var bot1 = Vector4.Transform(new Vector3( 1, -1, 1), matrix);
|
||||
var bot2 = Vector4.Transform(new Vector3(-1, -1, 1), matrix);
|
||||
var bot3 = Vector4.Transform(new Vector3(-1, -1, -1), matrix);
|
||||
var bot4 = Vector4.Transform(new Vector3( 1, -1, -1), matrix);
|
||||
|
||||
// draw
|
||||
canvas.Fill(new(0, 0, 0));
|
||||
DrawLine(top1, top2);
|
||||
DrawLine(top2, top3);
|
||||
DrawLine(top3, top4);
|
||||
DrawLine(top4, top1);
|
||||
|
||||
DrawLine(bot1, bot2);
|
||||
DrawLine(bot2, bot3);
|
||||
DrawLine(bot3, bot4);
|
||||
DrawLine(bot4, bot1);
|
||||
|
||||
DrawLine(top1, bot1);
|
||||
DrawLine(top2, bot2);
|
||||
DrawLine(top3, bot3);
|
||||
DrawLine(top4, bot4);
|
||||
|
||||
leds.SwapOnVsync(canvas);
|
||||
// force 30 FPS
|
||||
var elapsed = Environment.TickCount64 - frameStart;
|
||||
if (elapsed < 33) Thread.Sleep(33 - (int)elapsed);
|
||||
}
|
||||
|
||||
void DrawLine(Vector4 a, Vector4 b) => canvas.DrawLine(
|
||||
(int)(a.X * a.W + centerX), (int)(a.Y * a.W + centerY),
|
||||
(int)(b.X * b.W + centerX), (int)(b.Y * b.W + centerY),
|
||||
new(255, 255, 255));
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\RPiRgbLEDMatrix.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
1
depends/rpi-rgb-led-matrix/bindings/python/.gitignore
vendored
Normal file
1
depends/rpi-rgb-led-matrix/bindings/python/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
build/*
|
||||
92
depends/rpi-rgb-led-matrix/bindings/python/Makefile
Normal file
92
depends/rpi-rgb-led-matrix/bindings/python/Makefile
Normal file
@@ -0,0 +1,92 @@
|
||||
# TODO: This contains a lot of {c|p}ython build boilerplate, this needs cleanup.
|
||||
PYTHON ?= python
|
||||
SETUP := setup.py
|
||||
BUILD_ARGS := build --build-lib .
|
||||
INST_ARGS := install
|
||||
ifdef DESTDIR
|
||||
INST_ARGS += --root=$(DESTDIR)
|
||||
endif
|
||||
CLEAN_ARGS := clean --all
|
||||
|
||||
MANPAGES := $(patsubst %.txt,%,$(wildcard *.txt))
|
||||
TXTTOMAN := a2x -f manpage
|
||||
|
||||
# Where our library resides. It is split between includes and the binary
|
||||
# library in lib
|
||||
RGB_LIBDIR=../../lib
|
||||
RGB_LIBRARY_NAME=rgbmatrix
|
||||
RGB_LIBRARY=$(RGB_LIBDIR)/lib$(RGB_LIBRARY_NAME).a
|
||||
|
||||
ifneq "$(wildcard debian/changelog)" ""
|
||||
PKGNAME := $(shell dpkg-parsechangelog | sed -n 's/^Source: //p')
|
||||
VERSION := $(shell dpkg-parsechangelog | sed -n 's/^Version: \([^-]*\).*/\1/p')
|
||||
UPSDIST := $(PKGNAME)-$(VERSION).tar.gz
|
||||
DEBDIST := $(PKGNAME)_$(VERSION).orig.tar.gz
|
||||
endif
|
||||
|
||||
all: build
|
||||
build: build-python
|
||||
install: install-python
|
||||
clean: clean-python
|
||||
find ./rgbmatrix -type f -name \*.so -delete
|
||||
find . -type f -name \*.pyc -delete
|
||||
$(RM) build-* install-* test-*
|
||||
|
||||
$(RGB_LIBRARY): FORCE
|
||||
$(MAKE) -C $(RGB_LIBDIR)
|
||||
|
||||
test: test-python
|
||||
test-python:
|
||||
ifneq "$(wildcard tests/*.py)" ""
|
||||
nosetests -v -w tests
|
||||
else
|
||||
$(info Test suite is not implemented...)
|
||||
endif
|
||||
|
||||
ifneq "$(wildcard debian/control)" ""
|
||||
PYVERS := $(shell pyversions -r -v debian/control)
|
||||
PYEXEC := $(shell pyversions -d)
|
||||
BUILD_ARGS += --executable=/usr/bin/$(PYEXEC)
|
||||
INST_ARGS += --no-compile -O0
|
||||
|
||||
build-python: $(PYVERS:%=build-python-%)
|
||||
build-python-%: $(RGB_LIBRARY)
|
||||
$(info * Doing build for $(PYTHON)$* ...)
|
||||
$(PYTHON)$* $(SETUP) $(BUILD_ARGS)
|
||||
|
||||
install-python: $(PYVERS:%=install-python-%)
|
||||
install-python-%:
|
||||
$(info * Doing install for $(PYTHON)$* ...)
|
||||
$(PYTHON)$* $(SETUP) $(INST_ARGS)
|
||||
|
||||
clean-python: $(PYVERS:%=clean-python-%)
|
||||
clean-python-%:
|
||||
$(PYTHON)$* $(SETUP) $(CLEAN_ARGS)
|
||||
else
|
||||
build-python: $(RGB_LIBRARY)
|
||||
$(PYTHON) $(SETUP) $(BUILD_ARGS)
|
||||
|
||||
install-python:
|
||||
$(PYTHON) $(SETUP) $(INST_ARGS)
|
||||
|
||||
clean-python:
|
||||
$(PYTHON) $(SETUP) $(CLEAN_ARGS)
|
||||
endif
|
||||
|
||||
distclean: clean
|
||||
dist: distclean
|
||||
$(info * Creating ../$(UPSDIST) and ../$(DEBDIST))
|
||||
@tar --exclude='.svn' \
|
||||
--exclude='*.swp' \
|
||||
--exclude='debian' \
|
||||
-czvf ../$(UPSDIST) \
|
||||
-C ../ $(notdir $(CURDIR))
|
||||
@cp ../$(UPSDIST) ../$(DEBDIST)
|
||||
@if test -d ../tarballs; then \
|
||||
mv -v ../$(DEBDIST) ../tarballs; \
|
||||
fi
|
||||
|
||||
FORCE:
|
||||
.PHONY: FORCE
|
||||
.PHONY: build install test clean dist distclean
|
||||
.PHONY: build-python install-python clean-python
|
||||
147
depends/rpi-rgb-led-matrix/bindings/python/README.md
Executable file
147
depends/rpi-rgb-led-matrix/bindings/python/README.md
Executable file
@@ -0,0 +1,147 @@
|
||||
Python bindings for RGB Matrix library
|
||||
======================================
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
If you have a different than the standard wiring (for instance if you have an
|
||||
Adafruit HAT), you can edit the [../../lib/Makefile](../../lib/Makefile#L26) first to choose
|
||||
the hardware in question (see below for setting it via command line argument).
|
||||
|
||||
Then, in the root directory for the matrix library simply type:
|
||||
|
||||
### Python 2
|
||||
|
||||
```shell
|
||||
sudo apt-get update && sudo apt-get install python2.7-dev python-pillow -y
|
||||
make build-python
|
||||
sudo make install-python
|
||||
```
|
||||
|
||||
### Python 3
|
||||
You can also build for Python 3:
|
||||
|
||||
```shell
|
||||
sudo apt-get update && sudo apt-get install python3-dev python3-pillow -y
|
||||
make build-python PYTHON=$(command -v python3)
|
||||
sudo make install-python PYTHON=$(command -v python3)
|
||||
```
|
||||
|
||||
### PyPy
|
||||
The cython binding to PyPy seems to be somewhat working but extremely slow (20x
|
||||
slower even than the regular Python binding, 160x slower than C++), so this is
|
||||
not recommended.
|
||||
|
||||
So Cython is not good together with PyPy which works best with a
|
||||
[CFFI](https://cffi.readthedocs.io/) binding. @Duality4Y did an experiment here
|
||||
https://github.com/Duality4Y/rgb-matrix-cffi which works well with PyPy and is
|
||||
about twice as fast as running Python3+cython (but Python3+cffi is slower than
|
||||
Python3+cython, so we can't just replace everything with cffi).
|
||||
|
||||
Of course, it would be nice to have the fastest possible binding to all kinds
|
||||
of Python interpreters. If anyone wants to work on that, this would certainly
|
||||
be a welcome pull request.
|
||||
|
||||
Performance
|
||||
-----------
|
||||
The simplicity of scripting comes at a price: Python is slower than C++ of
|
||||
course.
|
||||
If you have to do a lot of pixel updates in your demo, this can be too slow
|
||||
depending on what you do. Here are some rough numbers for calling `SetPixel()`
|
||||
in a tight loop:
|
||||
|
||||
* On a Pi-2 and Pi-3, a Python script will be about 1/8 of the speed compared
|
||||
to the corresponding C++ program (pushing ~0.43 Megapixels/s Python
|
||||
vs. ~3.5 Megapixels/s C++ on a Pi-3 for instance)
|
||||
* On a Pi-1/Pi Zero, the difference is even worse: 1/24 of the speed to the
|
||||
corresponding C++ program. Given that this Pi is already about 1/10 the
|
||||
speed of a Pi-3, this almost makes Python unusable on a Pi-1
|
||||
(~0.015 Megapixels/s Python vs. ~0.36 Megapixels/s C++)
|
||||
* Also interesting: Python3 is a little bit slower than Python2.7.
|
||||
So if you can, stick with Python2.7 for now.
|
||||
* The good news is, that this is due to overhead per function call. If you
|
||||
can do more per function call, then this is less problematic. For instance
|
||||
if you have an image to be displayed with `SetImage()`, that will much
|
||||
faster per pixel (internally this then copies the pixels natively).
|
||||
|
||||
The ~0.015 Megapixels/s on a Pi-1 means that you can update a 32x32 matrix
|
||||
at most with ~15fps. If you have chained 5, then you barely reach 3fps.
|
||||
In a Pi-3, you get about 400fps update rate (85fps for 5-chain) with a Python
|
||||
program (while with C++, you can do the same thing with a comfortable 3500fps
|
||||
(700fps for 5)). Keep in mind that this is if all you do is just calling
|
||||
`SetPixel()`, it does not include any time of what you actually want to do in
|
||||
your demo - so anything in addition to that will drop your update rate.
|
||||
|
||||
If you can prepare the animation you want to show, then you can either prepare
|
||||
images and then use the much faster call to `SetImage()`, or can fill
|
||||
entire offscreen-frames (create with `CreateFrameCanvas()`) and then
|
||||
swap with `SwapOnVSync()` (this is the fastest method).
|
||||
|
||||
Using the library
|
||||
-----------------
|
||||
|
||||
Be aware of the fact that using the full performance of the RGBMatrix requires root privileges.
|
||||
Therefore you should run all you python scripts as using `sudo`.
|
||||
|
||||
You may find examples in the [samples/](./samples) subdirectory.
|
||||
The examples all use the [samplebase.py](./samples/samplebase.py) that provides
|
||||
some basic capabilities to all example programs, such as command-line parsing: all
|
||||
sample-programs accept `--led-rows`, `--led-chain` and `--led-parallel` as
|
||||
command line options to adapt to your configuration
|
||||
|
||||
```bash
|
||||
cd samples
|
||||
sudo ./runtext.py --led-chain=4
|
||||
```
|
||||
|
||||
To use different wiring without recompiling the library to change the default,
|
||||
you can use `--led-gpio-mapping` (or `-m`). For example, to use Adafruit HAT:
|
||||
```bash
|
||||
sudo ./runtext.py --led-gpio-mapping=adafruit-hat
|
||||
```
|
||||
|
||||
Here is a complete example showing how to write an image viewer:
|
||||
```python
|
||||
#!/usr/bin/env python
|
||||
import time
|
||||
import sys
|
||||
|
||||
from rgbmatrix import RGBMatrix, RGBMatrixOptions
|
||||
from PIL import Image
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit("Require an image argument")
|
||||
else:
|
||||
image_file = sys.argv[1]
|
||||
|
||||
image = Image.open(image_file)
|
||||
|
||||
# Configuration for the matrix
|
||||
options = RGBMatrixOptions()
|
||||
options.rows = 32
|
||||
options.chain_length = 1
|
||||
options.parallel = 1
|
||||
options.hardware_mapping = 'regular' # If you have an Adafruit HAT: 'adafruit-hat'
|
||||
|
||||
matrix = RGBMatrix(options = options)
|
||||
|
||||
# Make image fit our screen.
|
||||
image.thumbnail((matrix.width, matrix.height), Image.ANTIALIAS)
|
||||
|
||||
matrix.SetImage(image.convert('RGB'))
|
||||
|
||||
try:
|
||||
print("Press CTRL-C to stop.")
|
||||
while True:
|
||||
time.sleep(100)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
The source of truth for what is available in the Python bindings may be found [here](rgbmatrix/core.pyx) (RGBMatrix, FrameCanvas, RGBMatrixOptions) and [here](rgbmatrix/graphics.pyx) (graphics). The underlying implementation's ground truth documentation may be found [here](../../include), specifically for [RGBMatrix, RGBMatrixOptions, and FrameCanvas](../../include/led-matrix.h), [Canvas](../../include/canvas.h) (base class of RGBMatrix), and [graphics methods and Font](../../include/graphics.h).
|
||||
|
||||
### User
|
||||
|
||||
As noted in the Performance section above, Python programs not run as `root` will not be as high-performance as those run as `root`. When running as `root`, be aware of a potentially-unexpected behavior: to reduce the security attack surface, initializing an RGBMatrix as `root` changes the user from `root` to `daemon` (see [#1170](https://github.com/hzeller/rpi-rgb-led-matrix/issues/1170) for more information) by default. This means, for instance, that some file operations possible before initializing the RGBMatrix will not be possible after initialization. To disable this behavior, set `drop_privileges=False` in RGBMatrixOptions, but be aware that doing so will reduce security.
|
||||
@@ -0,0 +1,15 @@
|
||||
# The *.cpp files are included in the distribution; this is only needed when
|
||||
# working on the pyx files.
|
||||
#
|
||||
# Please check in modified *.cpp files with distribution to not require cython
|
||||
# to be installed on the users' machine.
|
||||
# for python3: make PYTHON=$(which python3) CYTHON=$(which cython3)
|
||||
CYTHON ?= cython
|
||||
|
||||
all : core.cpp graphics.cpp
|
||||
|
||||
%.cpp : %.pyx
|
||||
$(CYTHON) --cplus -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -rf core.cpp graphics.cpp
|
||||
7
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/__init__.py
Executable file
7
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/__init__.py
Executable file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
|
||||
__version__ = "0.0.1"
|
||||
__author__ = "Christoph Friedrich <christoph.friedrich@vonaffenfels.de>"
|
||||
|
||||
from .core import RGBMatrix, FrameCanvas, RGBMatrixOptions
|
||||
13196
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/core.cpp
Normal file
13196
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/core.cpp
Normal file
File diff suppressed because it is too large
Load Diff
24
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/core.pxd
Executable file
24
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/core.pxd
Executable file
@@ -0,0 +1,24 @@
|
||||
cimport cppinc
|
||||
|
||||
cdef class Canvas:
|
||||
cdef cppinc.Canvas *__getCanvas(self) except +
|
||||
|
||||
cdef class FrameCanvas(Canvas):
|
||||
cdef cppinc.FrameCanvas *__canvas
|
||||
|
||||
cdef class RGBMatrix(Canvas):
|
||||
cdef cppinc.RGBMatrix *__matrix
|
||||
|
||||
cdef class RGBMatrixOptions:
|
||||
cdef cppinc.Options __options
|
||||
cdef cppinc.RuntimeOptions __runtime_options
|
||||
# Must keep a reference to the encoded bytes for the strings,
|
||||
# otherwise, when the Options struct is used, it will be garbage collected
|
||||
cdef bytes __py_encoded_hardware_mapping
|
||||
cdef bytes __py_encoded_led_rgb_sequence
|
||||
cdef bytes __py_encoded_pixel_mapper_config
|
||||
cdef bytes __py_encoded_panel_type
|
||||
|
||||
# Local Variables:
|
||||
# mode: python
|
||||
# End:
|
||||
272
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/core.pyx
Executable file
272
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/core.pyx
Executable file
@@ -0,0 +1,272 @@
|
||||
# distutils: language = c++
|
||||
|
||||
from libcpp cimport bool
|
||||
from libc.stdint cimport uint8_t, uint32_t, uintptr_t
|
||||
from PIL import Image
|
||||
import cython
|
||||
|
||||
cdef class Canvas:
|
||||
cdef cppinc.Canvas* __getCanvas(self) except +:
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def SetImage(self, image, int offset_x = 0, int offset_y = 0, unsafe=True):
|
||||
if (image.mode != "RGB"):
|
||||
raise Exception("Currently, only RGB mode is supported for SetImage(). Please create images with mode 'RGB' or convert first with image = image.convert('RGB'). Pull requests to support more modes natively are also welcome :)")
|
||||
|
||||
if unsafe:
|
||||
#In unsafe mode we directly access the underlying PIL image array
|
||||
#in cython, which is considered unsafe pointer accecss,
|
||||
#however it's super fast and seems to work fine
|
||||
#https://groups.google.com/forum/#!topic/cython-users/Dc1ft5W6KM4
|
||||
img_width, img_height = image.size
|
||||
self.SetPixelsPillow(offset_x, offset_y, img_width, img_height, image)
|
||||
else:
|
||||
# First implementation of a SetImage(). OPTIMIZE_ME: A more native
|
||||
# implementation that directly reads the buffer and calls the underlying
|
||||
# C functions can certainly be faster.
|
||||
img_width, img_height = image.size
|
||||
pixels = image.load()
|
||||
for x in range(max(0, -offset_x), min(img_width, self.width - offset_x)):
|
||||
for y in range(max(0, -offset_y), min(img_height, self.height - offset_y)):
|
||||
(r, g, b) = pixels[x, y]
|
||||
self.SetPixel(x + offset_x, y + offset_y, r, g, b)
|
||||
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
def SetPixelsPillow(self, int xstart, int ystart, int width, int height, image):
|
||||
cdef cppinc.FrameCanvas* my_canvas = <cppinc.FrameCanvas*>self.__getCanvas()
|
||||
cdef int frame_width = my_canvas.width()
|
||||
cdef int frame_height = my_canvas.height()
|
||||
cdef int row, col
|
||||
cdef uint8_t r, g, b
|
||||
cdef uint32_t **image_ptr
|
||||
cdef uint32_t pixel
|
||||
image.load()
|
||||
ptr_tmp = dict(image.im.unsafe_ptrs)['image32']
|
||||
image_ptr = (<uint32_t **>(<uintptr_t>ptr_tmp))
|
||||
|
||||
for col in range(max(0, -xstart), min(width, frame_width - xstart)):
|
||||
for row in range(max(0, -ystart), min(height, frame_height - ystart)):
|
||||
pixel = image_ptr[row][col]
|
||||
r = (pixel ) & 0xFF
|
||||
g = (pixel >> 8) & 0xFF
|
||||
b = (pixel >> 16) & 0xFF
|
||||
my_canvas.SetPixel(xstart+col, ystart+row, r, g, b)
|
||||
|
||||
cdef class FrameCanvas(Canvas):
|
||||
def __dealloc__(self):
|
||||
if <void*>self.__canvas != NULL:
|
||||
self.__canvas = NULL
|
||||
|
||||
cdef cppinc.Canvas* __getCanvas(self) except *:
|
||||
if <void*>self.__canvas != NULL:
|
||||
return self.__canvas
|
||||
raise Exception("Canvas was destroyed or not initialized, you cannot use this object anymore")
|
||||
|
||||
def Fill(self, uint8_t red, uint8_t green, uint8_t blue):
|
||||
(<cppinc.FrameCanvas*>self.__getCanvas()).Fill(red, green, blue)
|
||||
|
||||
def Clear(self):
|
||||
(<cppinc.FrameCanvas*>self.__getCanvas()).Clear()
|
||||
|
||||
def SetPixel(self, int x, int y, uint8_t red, uint8_t green, uint8_t blue):
|
||||
(<cppinc.FrameCanvas*>self.__getCanvas()).SetPixel(x, y, red, green, blue)
|
||||
|
||||
|
||||
property width:
|
||||
def __get__(self): return (<cppinc.FrameCanvas*>self.__getCanvas()).width()
|
||||
|
||||
property height:
|
||||
def __get__(self): return (<cppinc.FrameCanvas*>self.__getCanvas()).height()
|
||||
|
||||
property pwmBits:
|
||||
def __get__(self): return (<cppinc.FrameCanvas*>self.__getCanvas()).pwmbits()
|
||||
def __set__(self, pwmBits): (<cppinc.FrameCanvas*>self.__getCanvas()).SetPWMBits(pwmBits)
|
||||
|
||||
property brightness:
|
||||
def __get__(self): return (<cppinc.FrameCanvas*>self.__getCanvas()).brightness()
|
||||
def __set__(self, val): (<cppinc.FrameCanvas*>self.__getCanvas()).SetBrightness(val)
|
||||
|
||||
|
||||
cdef class RGBMatrixOptions:
|
||||
def __cinit__(self):
|
||||
self.__options = cppinc.Options()
|
||||
self.__runtime_options = cppinc.RuntimeOptions()
|
||||
|
||||
# RGBMatrix::Options properties
|
||||
property hardware_mapping:
|
||||
def __get__(self): return self.__options.hardware_mapping
|
||||
def __set__(self, value):
|
||||
self.__py_encoded_hardware_mapping = value.encode('utf-8')
|
||||
self.__options.hardware_mapping = self.__py_encoded_hardware_mapping
|
||||
|
||||
property rows:
|
||||
def __get__(self): return self.__options.rows
|
||||
def __set__(self, uint8_t value): self.__options.rows = value
|
||||
|
||||
property cols:
|
||||
def __get__(self): return self.__options.cols
|
||||
def __set__(self, uint32_t value): self.__options.cols = value
|
||||
|
||||
property chain_length:
|
||||
def __get__(self): return self.__options.chain_length
|
||||
def __set__(self, uint8_t value): self.__options.chain_length = value
|
||||
|
||||
property parallel:
|
||||
def __get__(self): return self.__options.parallel
|
||||
def __set__(self, uint8_t value): self.__options.parallel = value
|
||||
|
||||
property pwm_bits:
|
||||
def __get__(self): return self.__options.pwm_bits
|
||||
def __set__(self, uint8_t value): self.__options.pwm_bits = value
|
||||
|
||||
property pwm_lsb_nanoseconds:
|
||||
def __get__(self): return self.__options.pwm_lsb_nanoseconds
|
||||
def __set__(self, uint32_t value): self.__options.pwm_lsb_nanoseconds = value
|
||||
|
||||
property brightness:
|
||||
def __get__(self): return self.__options.brightness
|
||||
def __set__(self, uint8_t value): self.__options.brightness = value
|
||||
|
||||
property scan_mode:
|
||||
def __get__(self): return self.__options.scan_mode
|
||||
def __set__(self, uint8_t value): self.__options.scan_mode = value
|
||||
|
||||
property multiplexing:
|
||||
def __get__(self): return self.__options.multiplexing
|
||||
def __set__(self, uint8_t value): self.__options.multiplexing = value
|
||||
|
||||
property row_address_type:
|
||||
def __get__(self): return self.__options.row_address_type
|
||||
def __set__(self, uint8_t value): self.__options.row_address_type = value
|
||||
|
||||
property disable_hardware_pulsing:
|
||||
def __get__(self): return self.__options.disable_hardware_pulsing
|
||||
def __set__(self, value): self.__options.disable_hardware_pulsing = value
|
||||
|
||||
property show_refresh_rate:
|
||||
def __get__(self): return self.__options.show_refresh_rate
|
||||
def __set__(self, value): self.__options.show_refresh_rate = value
|
||||
|
||||
property inverse_colors:
|
||||
def __get__(self): return self.__options.inverse_colors
|
||||
def __set__(self, value): self.__options.inverse_colors = value
|
||||
|
||||
property led_rgb_sequence:
|
||||
def __get__(self): return self.__options.led_rgb_sequence
|
||||
def __set__(self, value):
|
||||
self.__py_encoded_led_rgb_sequence = value.encode('utf-8')
|
||||
self.__options.led_rgb_sequence = self.__py_encoded_led_rgb_sequence
|
||||
|
||||
property pixel_mapper_config:
|
||||
def __get__(self): return self.__options.pixel_mapper_config
|
||||
def __set__(self, value):
|
||||
self.__py_encoded_pixel_mapper_config = value.encode('utf-8')
|
||||
self.__options.pixel_mapper_config = self.__py_encoded_pixel_mapper_config
|
||||
|
||||
property panel_type:
|
||||
def __get__(self): return self.__options.panel_type
|
||||
def __set__(self, value):
|
||||
self.__py_encoded_panel_type = value.encode('utf-8')
|
||||
self.__options.panel_type = self.__py_encoded_panel_type
|
||||
|
||||
property pwm_dither_bits:
|
||||
def __get__(self): return self.__options.pwm_dither_bits
|
||||
def __set__(self, uint8_t value): self.__options.pwm_dither_bits = value
|
||||
|
||||
property limit_refresh_rate_hz:
|
||||
def __get__(self): return self.__options.limit_refresh_rate_hz
|
||||
def __set__(self, value): self.__options.limit_refresh_rate_hz = value
|
||||
|
||||
|
||||
# RuntimeOptions properties
|
||||
|
||||
property gpio_slowdown:
|
||||
def __get__(self): return self.__runtime_options.gpio_slowdown
|
||||
def __set__(self, uint8_t value): self.__runtime_options.gpio_slowdown = value
|
||||
|
||||
property daemon:
|
||||
def __get__(self): return self.__runtime_options.daemon
|
||||
def __set__(self, uint8_t value): self.__runtime_options.daemon = value
|
||||
|
||||
property drop_privileges:
|
||||
def __get__(self): return self.__runtime_options.drop_privileges
|
||||
def __set__(self, uint8_t value): self.__runtime_options.drop_privileges = value
|
||||
|
||||
cdef class RGBMatrix(Canvas):
|
||||
def __cinit__(self, int rows = 0, int chains = 0, int parallel = 0,
|
||||
RGBMatrixOptions options = None):
|
||||
|
||||
# If RGBMatrixOptions not provided, create defaults and set any optional
|
||||
# parameters supplied
|
||||
if options == None:
|
||||
options = RGBMatrixOptions()
|
||||
|
||||
if rows > 0:
|
||||
options.rows = rows
|
||||
if chains > 0:
|
||||
options.chain_length = chains
|
||||
if parallel > 0:
|
||||
options.parallel = parallel
|
||||
|
||||
self.__matrix = cppinc.CreateMatrixFromOptions(options.__options,
|
||||
options.__runtime_options)
|
||||
|
||||
def __dealloc__(self):
|
||||
self.__matrix.Clear()
|
||||
del self.__matrix
|
||||
|
||||
cdef cppinc.Canvas* __getCanvas(self) except *:
|
||||
if <void*>self.__matrix != NULL:
|
||||
return self.__matrix
|
||||
raise Exception("Canvas was destroyed or not initialized, you cannot use this object anymore")
|
||||
|
||||
def Fill(self, uint8_t red, uint8_t green, uint8_t blue):
|
||||
self.__matrix.Fill(red, green, blue)
|
||||
|
||||
def SetPixel(self, int x, int y, uint8_t red, uint8_t green, uint8_t blue):
|
||||
self.__matrix.SetPixel(x, y, red, green, blue)
|
||||
|
||||
def Clear(self):
|
||||
self.__matrix.Clear()
|
||||
|
||||
def CreateFrameCanvas(self):
|
||||
return __createFrameCanvas(self.__matrix.CreateFrameCanvas())
|
||||
|
||||
# The optional "framerate_fraction" parameter allows to choose which
|
||||
# multiple of the global frame-count to use. So it slows down your animation
|
||||
# to an exact integer fraction of the refresh rate.
|
||||
# Default is 1, so immediately next available frame.
|
||||
# (Say you have 140Hz refresh rate, then a value of 5 would give you an
|
||||
# 28Hz animation, nicely locked to the refresh-rate).
|
||||
# If you combine this with RGBMatrixOptions.limit_refresh_rate_hz you can create
|
||||
# time-correct animations.
|
||||
def SwapOnVSync(self, FrameCanvas newFrame, uint8_t framerate_fraction = 1):
|
||||
return __createFrameCanvas(self.__matrix.SwapOnVSync(newFrame.__canvas, framerate_fraction))
|
||||
|
||||
property luminanceCorrect:
|
||||
def __get__(self): return self.__matrix.luminance_correct()
|
||||
def __set__(self, luminanceCorrect): self.__matrix.set_luminance_correct(luminanceCorrect)
|
||||
|
||||
property pwmBits:
|
||||
def __get__(self): return self.__matrix.pwmbits()
|
||||
def __set__(self, pwmBits): self.__matrix.SetPWMBits(pwmBits)
|
||||
|
||||
property brightness:
|
||||
def __get__(self): return self.__matrix.brightness()
|
||||
def __set__(self, brightness): self.__matrix.SetBrightness(brightness)
|
||||
|
||||
property height:
|
||||
def __get__(self): return self.__matrix.height()
|
||||
|
||||
property width:
|
||||
def __get__(self): return self.__matrix.width()
|
||||
|
||||
cdef __createFrameCanvas(cppinc.FrameCanvas* newCanvas):
|
||||
canvas = FrameCanvas()
|
||||
canvas.__canvas = newCanvas
|
||||
return canvas
|
||||
|
||||
# Local Variables:
|
||||
# mode: python
|
||||
# End:
|
||||
88
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/cppinc.pxd
Executable file
88
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/cppinc.pxd
Executable file
@@ -0,0 +1,88 @@
|
||||
from libcpp cimport bool
|
||||
from libc.stdint cimport uint8_t, uint32_t
|
||||
|
||||
########################
|
||||
### External classes ###
|
||||
########################
|
||||
|
||||
cdef extern from "canvas.h" namespace "rgb_matrix":
|
||||
cdef cppclass Canvas:
|
||||
int width()
|
||||
int height()
|
||||
void SetPixel(int, int, uint8_t, uint8_t, uint8_t) nogil
|
||||
void Clear() nogil
|
||||
void Fill(uint8_t, uint8_t, uint8_t) nogil
|
||||
|
||||
cdef extern from "led-matrix.h" namespace "rgb_matrix":
|
||||
cdef cppclass RGBMatrix(Canvas):
|
||||
bool SetPWMBits(uint8_t)
|
||||
uint8_t pwmbits()
|
||||
void set_luminance_correct(bool)
|
||||
bool luminance_correct()
|
||||
void SetBrightness(uint8_t)
|
||||
uint8_t brightness()
|
||||
FrameCanvas *CreateFrameCanvas()
|
||||
FrameCanvas *SwapOnVSync(FrameCanvas*, uint8_t)
|
||||
|
||||
cdef cppclass FrameCanvas(Canvas):
|
||||
bool SetPWMBits(uint8_t)
|
||||
uint8_t pwmbits()
|
||||
void SetBrightness(uint8_t)
|
||||
uint8_t brightness()
|
||||
|
||||
struct RuntimeOptions:
|
||||
RuntimeOptions() except +
|
||||
int gpio_slowdown
|
||||
int daemon
|
||||
int drop_privileges
|
||||
|
||||
|
||||
RGBMatrix *CreateMatrixFromOptions(Options &options, RuntimeOptions runtime_options)
|
||||
|
||||
|
||||
|
||||
cdef extern from "led-matrix.h" namespace "rgb_matrix::RGBMatrix":
|
||||
cdef struct Options:
|
||||
Options() except +
|
||||
|
||||
const char *hardware_mapping
|
||||
|
||||
int rows
|
||||
int cols
|
||||
int chain_length
|
||||
int parallel
|
||||
int pwm_bits
|
||||
int pwm_lsb_nanoseconds
|
||||
int brightness
|
||||
int scan_mode
|
||||
int row_address_type
|
||||
int multiplexing
|
||||
int pwm_dither_bits
|
||||
int limit_refresh_rate_hz
|
||||
|
||||
bool disable_hardware_pulsing
|
||||
bool show_refresh_rate
|
||||
bool inverse_colors
|
||||
|
||||
const char *led_rgb_sequence
|
||||
const char *pixel_mapper_config
|
||||
const char *panel_type
|
||||
|
||||
cdef extern from "graphics.h" namespace "rgb_matrix":
|
||||
cdef struct Color:
|
||||
Color(uint8_t, uint8_t, uint8_t) except +
|
||||
uint8_t r
|
||||
uint8_t g
|
||||
uint8_t b
|
||||
|
||||
cdef cppclass Font:
|
||||
Font() except +
|
||||
bool LoadFont(const char*)
|
||||
int height()
|
||||
int baseline()
|
||||
int CharacterWidth(uint32_t)
|
||||
int DrawGlyph(Canvas*, int, int, const Color, uint32_t);
|
||||
|
||||
cdef int DrawText(Canvas*, const Font, int, int, const Color, const char*)
|
||||
cdef void DrawCircle(Canvas*, int, int, int, const Color)
|
||||
cdef void DrawLine(Canvas*, int, int, int, int, const Color)
|
||||
6528
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/graphics.cpp
Normal file
6528
depends/rpi-rgb-led-matrix/bindings/python/rgbmatrix/graphics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
cimport cppinc
|
||||
|
||||
cdef class Color:
|
||||
cdef cppinc.Color __color
|
||||
|
||||
cdef class Font:
|
||||
cdef cppinc.Font __font
|
||||
|
||||
# Local Variables:
|
||||
# mode: python
|
||||
# End:
|
||||
@@ -0,0 +1,54 @@
|
||||
# distutils: language = c++
|
||||
|
||||
from libcpp cimport bool
|
||||
from libc.stdint cimport uint8_t, uint32_t
|
||||
|
||||
cimport core
|
||||
|
||||
cdef class Color:
|
||||
def __init__(self, uint8_t red = 0, uint8_t green = 0, uint8_t blue = 0):
|
||||
self.__color.r = red
|
||||
self.__color.g = green
|
||||
self.__color.b = blue
|
||||
|
||||
property red:
|
||||
def __get__(self): return self.__color.r
|
||||
def __set__(self, uint8_t value): self.__color.r = value
|
||||
|
||||
property green:
|
||||
def __get__(self): return self.__color.g
|
||||
def __set__(self, uint8_t value): self.__color.g = value
|
||||
|
||||
property blue:
|
||||
def __get__(self): return self.__color.b
|
||||
def __set__(self, uint8_t value): self.__color.b = value
|
||||
|
||||
cdef class Font:
|
||||
def CharacterWidth(self, uint32_t char):
|
||||
return self.__font.CharacterWidth(char)
|
||||
|
||||
def LoadFont(self, file):
|
||||
if (not self.__font.LoadFont(file.encode('utf-8'))):
|
||||
raise Exception("Couldn't load font " + file)
|
||||
|
||||
def DrawGlyph(self, core.Canvas c, int x, int y, Color color, uint32_t char):
|
||||
return self.__font.DrawGlyph(c.__getCanvas(), x, y, color.__color, char)
|
||||
|
||||
property height:
|
||||
def __get__(self): return self.__font.height()
|
||||
|
||||
property baseline:
|
||||
def __get__(self): return self.__font.baseline()
|
||||
|
||||
def DrawText(core.Canvas c, Font f, int x, int y, Color color, text):
|
||||
return cppinc.DrawText(c.__getCanvas(), f.__font, x, y, color.__color, text.encode('utf-8'))
|
||||
|
||||
def DrawCircle(core.Canvas c, int x, int y, int r, Color color):
|
||||
cppinc.DrawCircle(c.__getCanvas(), x, y, r, color.__color)
|
||||
|
||||
def DrawLine(core.Canvas c, int x1, int y1, int x2, int y2, Color color):
|
||||
cppinc.DrawLine(c.__getCanvas(), x1, y1, x2, y2, color.__color)
|
||||
|
||||
# Local Variables:
|
||||
# mode: python
|
||||
# End:
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
import time
|
||||
import sys
|
||||
|
||||
from rgbmatrix import RGBMatrix, RGBMatrixOptions
|
||||
from PIL import Image
|
||||
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit("Require a gif argument")
|
||||
else:
|
||||
image_file = sys.argv[1]
|
||||
|
||||
gif = Image.open(image_file)
|
||||
|
||||
try:
|
||||
num_frames = gif.n_frames
|
||||
except Exception:
|
||||
sys.exit("provided image is not a gif")
|
||||
|
||||
|
||||
# Configuration for the matrix
|
||||
options = RGBMatrixOptions()
|
||||
options.rows = 32
|
||||
options.cols = 32
|
||||
options.chain_length = 1
|
||||
options.parallel = 1
|
||||
options.hardware_mapping = 'regular' # If you have an Adafruit HAT: 'adafruit-hat'
|
||||
|
||||
matrix = RGBMatrix(options = options)
|
||||
|
||||
# Preprocess the gifs frames into canvases to improve playback performance
|
||||
canvases = []
|
||||
print("Preprocessing gif, this may take a moment depending on the size of the gif...")
|
||||
for frame_index in range(0, num_frames):
|
||||
gif.seek(frame_index)
|
||||
# must copy the frame out of the gif, since thumbnail() modifies the image in-place
|
||||
frame = gif.copy()
|
||||
frame.thumbnail((matrix.width, matrix.height), Image.ANTIALIAS)
|
||||
canvas = matrix.CreateFrameCanvas()
|
||||
canvas.SetImage(frame.convert("RGB"))
|
||||
canvases.append(canvas)
|
||||
# Close the gif file to save memory now that we have copied out all of the frames
|
||||
gif.close()
|
||||
|
||||
print("Completed Preprocessing, displaying gif")
|
||||
|
||||
try:
|
||||
print("Press CTRL-C to stop.")
|
||||
|
||||
# Infinitely loop through the gif
|
||||
cur_frame = 0
|
||||
while(True):
|
||||
matrix.SwapOnVSync(canvases[cur_frame], framerate_fraction=10)
|
||||
if cur_frame == num_frames - 1:
|
||||
cur_frame = 0
|
||||
else:
|
||||
cur_frame += 1
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
32
depends/rpi-rgb-led-matrix/bindings/python/samples/graphics.py
Executable file
32
depends/rpi-rgb-led-matrix/bindings/python/samples/graphics.py
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
from samplebase import SampleBase
|
||||
from rgbmatrix import graphics
|
||||
import time
|
||||
|
||||
|
||||
class GraphicsTest(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GraphicsTest, self).__init__(*args, **kwargs)
|
||||
|
||||
def run(self):
|
||||
canvas = self.matrix
|
||||
font = graphics.Font()
|
||||
font.LoadFont("../../../fonts/7x13.bdf")
|
||||
|
||||
red = graphics.Color(255, 0, 0)
|
||||
graphics.DrawLine(canvas, 5, 5, 22, 13, red)
|
||||
|
||||
green = graphics.Color(0, 255, 0)
|
||||
graphics.DrawCircle(canvas, 15, 15, 10, green)
|
||||
|
||||
blue = graphics.Color(0, 0, 255)
|
||||
graphics.DrawText(canvas, font, 2, 10, blue, "Text")
|
||||
|
||||
time.sleep(10) # show display for 10 seconds before exit
|
||||
|
||||
|
||||
# Main function
|
||||
if __name__ == "__main__":
|
||||
graphics_test = GraphicsTest()
|
||||
if (not graphics_test.process()):
|
||||
graphics_test.print_help()
|
||||
39
depends/rpi-rgb-led-matrix/bindings/python/samples/grayscale-block.py
Executable file
39
depends/rpi-rgb-led-matrix/bindings/python/samples/grayscale-block.py
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python
|
||||
from samplebase import SampleBase
|
||||
import time
|
||||
|
||||
|
||||
class GrayscaleBlock(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GrayscaleBlock, self).__init__(*args, **kwargs)
|
||||
|
||||
def run(self):
|
||||
sub_blocks = 16
|
||||
width = self.matrix.width
|
||||
height = self.matrix.height
|
||||
x_step = max(1, width / sub_blocks)
|
||||
y_step = max(1, height / sub_blocks)
|
||||
count = 0
|
||||
|
||||
while True:
|
||||
for y in range(0, height):
|
||||
for x in range(0, width):
|
||||
c = sub_blocks * int(y / y_step) + int(x / x_step)
|
||||
if count % 4 == 0:
|
||||
self.matrix.SetPixel(x, y, c, c, c)
|
||||
elif count % 4 == 1:
|
||||
self.matrix.SetPixel(x, y, c, 0, 0)
|
||||
elif count % 4 == 2:
|
||||
self.matrix.SetPixel(x, y, 0, c, 0)
|
||||
elif count % 4 == 3:
|
||||
self.matrix.SetPixel(x, y, 0, 0, c)
|
||||
|
||||
count += 1
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
# Main function
|
||||
if __name__ == "__main__":
|
||||
grayscale_block = GrayscaleBlock()
|
||||
if (not grayscale_block.process()):
|
||||
grayscale_block.print_help()
|
||||
48
depends/rpi-rgb-led-matrix/bindings/python/samples/image-draw.py
Executable file
48
depends/rpi-rgb-led-matrix/bindings/python/samples/image-draw.py
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# (This is an example similar to an example from the Adafruit fork
|
||||
# to show the similarities. Most important difference currently is, that
|
||||
# this library wants RGB mode.)
|
||||
#
|
||||
# A more complex RGBMatrix example works with the Python Imaging Library,
|
||||
# demonstrating a few graphics primitives and image loading.
|
||||
# Note that PIL graphics do not have an immediate effect on the display --
|
||||
# image is drawn into a separate buffer, which is then copied to the matrix
|
||||
# using the SetImage() function (see examples below).
|
||||
# Requires rgbmatrix.so present in the same directory.
|
||||
|
||||
# PIL Image module (create or load images) is explained here:
|
||||
# http://effbot.org/imagingbook/image.htm
|
||||
# PIL ImageDraw module (draw shapes to images) explained here:
|
||||
# http://effbot.org/imagingbook/imagedraw.htm
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageDraw
|
||||
import time
|
||||
from rgbmatrix import RGBMatrix, RGBMatrixOptions
|
||||
|
||||
# Configuration for the matrix
|
||||
options = RGBMatrixOptions()
|
||||
options.rows = 32
|
||||
options.chain_length = 1
|
||||
options.parallel = 1
|
||||
options.hardware_mapping = 'regular' # If you have an Adafruit HAT: 'adafruit-hat'
|
||||
|
||||
matrix = RGBMatrix(options = options)
|
||||
|
||||
# RGB example w/graphics prims.
|
||||
# Note, only "RGB" mode is supported currently.
|
||||
image = Image.new("RGB", (32, 32)) # Can be larger than matrix if wanted!!
|
||||
draw = ImageDraw.Draw(image) # Declare Draw instance before prims
|
||||
# Draw some shapes into image (no immediate effect on matrix)...
|
||||
draw.rectangle((0, 0, 31, 31), fill=(0, 0, 0), outline=(0, 0, 255))
|
||||
draw.line((0, 0, 31, 31), fill=(255, 0, 0))
|
||||
draw.line((0, 31, 31, 0), fill=(0, 255, 0))
|
||||
|
||||
# Then scroll image across matrix...
|
||||
for n in range(-32, 33): # Start off top-left, move off bottom-right
|
||||
matrix.Clear()
|
||||
matrix.SetImage(image, n, n)
|
||||
time.sleep(0.05)
|
||||
|
||||
matrix.Clear()
|
||||
40
depends/rpi-rgb-led-matrix/bindings/python/samples/image-scroller.py
Executable file
40
depends/rpi-rgb-led-matrix/bindings/python/samples/image-scroller.py
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
import time
|
||||
from samplebase import SampleBase
|
||||
from PIL import Image
|
||||
|
||||
|
||||
class ImageScroller(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ImageScroller, self).__init__(*args, **kwargs)
|
||||
self.parser.add_argument("-i", "--image", help="The image to display", default="../../../examples-api-use/runtext.ppm")
|
||||
|
||||
def run(self):
|
||||
if not 'image' in self.__dict__:
|
||||
self.image = Image.open(self.args.image).convert('RGB')
|
||||
self.image.resize((self.matrix.width, self.matrix.height), Image.ANTIALIAS)
|
||||
|
||||
double_buffer = self.matrix.CreateFrameCanvas()
|
||||
img_width, img_height = self.image.size
|
||||
|
||||
# let's scroll
|
||||
xpos = 0
|
||||
while True:
|
||||
xpos += 1
|
||||
if (xpos > img_width):
|
||||
xpos = 0
|
||||
|
||||
double_buffer.SetImage(self.image, -xpos)
|
||||
double_buffer.SetImage(self.image, -xpos + img_width)
|
||||
|
||||
double_buffer = self.matrix.SwapOnVSync(double_buffer)
|
||||
time.sleep(0.01)
|
||||
|
||||
# Main function
|
||||
# e.g. call with
|
||||
# sudo ./image-scroller.py --chain=4
|
||||
# if you have a chain of four
|
||||
if __name__ == "__main__":
|
||||
image_scroller = ImageScroller()
|
||||
if (not image_scroller.process()):
|
||||
image_scroller.print_help()
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python
|
||||
import time
|
||||
import sys
|
||||
|
||||
from rgbmatrix import RGBMatrix, RGBMatrixOptions
|
||||
from PIL import Image
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit("Require an image argument")
|
||||
else:
|
||||
image_file = sys.argv[1]
|
||||
|
||||
image = Image.open(image_file)
|
||||
|
||||
# Configuration for the matrix
|
||||
options = RGBMatrixOptions()
|
||||
options.rows = 32
|
||||
options.chain_length = 1
|
||||
options.parallel = 1
|
||||
options.hardware_mapping = 'regular' # If you have an Adafruit HAT: 'adafruit-hat'
|
||||
|
||||
matrix = RGBMatrix(options = options)
|
||||
|
||||
# Make image fit our screen.
|
||||
image.thumbnail((matrix.width, matrix.height), Image.ANTIALIAS)
|
||||
|
||||
matrix.SetImage(image.convert('RGB'))
|
||||
|
||||
try:
|
||||
print("Press CTRL-C to stop.")
|
||||
while True:
|
||||
time.sleep(100)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
36
depends/rpi-rgb-led-matrix/bindings/python/samples/pulsing-brightness.py
Executable file
36
depends/rpi-rgb-led-matrix/bindings/python/samples/pulsing-brightness.py
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
from samplebase import SampleBase
|
||||
|
||||
|
||||
class GrayscaleBlock(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GrayscaleBlock, self).__init__(*args, **kwargs)
|
||||
|
||||
def run(self):
|
||||
max_brightness = self.matrix.brightness
|
||||
count = 0
|
||||
c = 255
|
||||
|
||||
while (True):
|
||||
if self.matrix.brightness < 1:
|
||||
self.matrix.brightness = max_brightness
|
||||
count += 1
|
||||
else:
|
||||
self.matrix.brightness -= 1
|
||||
|
||||
if count % 4 == 0:
|
||||
self.matrix.Fill(c, 0, 0)
|
||||
elif count % 4 == 1:
|
||||
self.matrix.Fill(0, c, 0)
|
||||
elif count % 4 == 2:
|
||||
self.matrix.Fill(0, 0, c)
|
||||
elif count % 4 == 3:
|
||||
self.matrix.Fill(c, c, c)
|
||||
|
||||
self.usleep(20 * 1000)
|
||||
|
||||
# Main function
|
||||
if __name__ == "__main__":
|
||||
grayscale_block = GrayscaleBlock()
|
||||
if (not grayscale_block.process()):
|
||||
grayscale_block.print_help()
|
||||
42
depends/rpi-rgb-led-matrix/bindings/python/samples/pulsing-colors.py
Executable file
42
depends/rpi-rgb-led-matrix/bindings/python/samples/pulsing-colors.py
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
from samplebase import SampleBase
|
||||
|
||||
|
||||
class PulsingColors(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PulsingColors, self).__init__(*args, **kwargs)
|
||||
|
||||
def run(self):
|
||||
self.offscreen_canvas = self.matrix.CreateFrameCanvas()
|
||||
continuum = 0
|
||||
|
||||
while True:
|
||||
self.usleep(5 * 1000)
|
||||
continuum += 1
|
||||
continuum %= 3 * 255
|
||||
|
||||
red = 0
|
||||
green = 0
|
||||
blue = 0
|
||||
|
||||
if continuum <= 255:
|
||||
c = continuum
|
||||
blue = 255 - c
|
||||
red = c
|
||||
elif continuum > 255 and continuum <= 511:
|
||||
c = continuum - 256
|
||||
red = 255 - c
|
||||
green = c
|
||||
else:
|
||||
c = continuum - 512
|
||||
green = 255 - c
|
||||
blue = c
|
||||
|
||||
self.offscreen_canvas.Fill(red, green, blue)
|
||||
self.offscreen_canvas = self.matrix.SwapOnVSync(self.offscreen_canvas)
|
||||
|
||||
# Main function
|
||||
if __name__ == "__main__":
|
||||
pulsing_colors = PulsingColors()
|
||||
if (not pulsing_colors.process()):
|
||||
pulsing_colors.print_help()
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
from samplebase import SampleBase
|
||||
import math
|
||||
|
||||
|
||||
def scale_col(val, lo, hi):
|
||||
if val < lo:
|
||||
return 0
|
||||
if val > hi:
|
||||
return 255
|
||||
return 255 * (val - lo) / (hi - lo)
|
||||
|
||||
|
||||
def rotate(x, y, sin, cos):
|
||||
return x * cos - y * sin, x * sin + y * cos
|
||||
|
||||
|
||||
class RotatingBlockGenerator(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RotatingBlockGenerator, self).__init__(*args, **kwargs)
|
||||
|
||||
def run(self):
|
||||
cent_x = self.matrix.width / 2
|
||||
cent_y = self.matrix.height / 2
|
||||
|
||||
rotate_square = min(self.matrix.width, self.matrix.height) * 1.41
|
||||
min_rotate = cent_x - rotate_square / 2
|
||||
max_rotate = cent_x + rotate_square / 2
|
||||
|
||||
display_square = min(self.matrix.width, self.matrix.height) * 0.7
|
||||
min_display = cent_x - display_square / 2
|
||||
max_display = cent_x + display_square / 2
|
||||
|
||||
deg_to_rad = 2 * 3.14159265 / 360
|
||||
rotation = 0
|
||||
|
||||
# Pre calculate colors
|
||||
col_table = []
|
||||
for x in range(int(min_rotate), int(max_rotate)):
|
||||
col_table.insert(x, scale_col(x, min_display, max_display))
|
||||
|
||||
offset_canvas = self.matrix.CreateFrameCanvas()
|
||||
|
||||
while True:
|
||||
rotation += 1
|
||||
rotation %= 360
|
||||
|
||||
# calculate sin and cos once for each frame
|
||||
angle = rotation * deg_to_rad
|
||||
sin = math.sin(angle)
|
||||
cos = math.cos(angle)
|
||||
|
||||
for x in range(int(min_rotate), int(max_rotate)):
|
||||
for y in range(int(min_rotate), int(max_rotate)):
|
||||
# Our rotate center is always offset by cent_x
|
||||
rot_x, rot_y = rotate(x - cent_x, y - cent_x, sin, cos)
|
||||
|
||||
if x >= min_display and x < max_display and y >= min_display and y < max_display:
|
||||
x_col = col_table[x]
|
||||
y_col = col_table[y]
|
||||
offset_canvas.SetPixel(rot_x + cent_x, rot_y + cent_y, x_col, 255 - y_col, y_col)
|
||||
else:
|
||||
offset_canvas.SetPixel(rot_x + cent_x, rot_y + cent_y, 0, 0, 0)
|
||||
|
||||
offset_canvas = self.matrix.SwapOnVSync(offset_canvas)
|
||||
|
||||
|
||||
# Main function
|
||||
if __name__ == "__main__":
|
||||
rotating_block_generator = RotatingBlockGenerator()
|
||||
if (not rotating_block_generator.process()):
|
||||
rotating_block_generator.print_help()
|
||||
36
depends/rpi-rgb-led-matrix/bindings/python/samples/runtext.py
Executable file
36
depends/rpi-rgb-led-matrix/bindings/python/samples/runtext.py
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python
|
||||
# Display a runtext with double-buffering.
|
||||
from samplebase import SampleBase
|
||||
from rgbmatrix import graphics
|
||||
import time
|
||||
|
||||
|
||||
class RunText(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RunText, self).__init__(*args, **kwargs)
|
||||
self.parser.add_argument("-t", "--text", help="The text to scroll on the RGB LED panel", default="Hello world!")
|
||||
|
||||
def run(self):
|
||||
offscreen_canvas = self.matrix.CreateFrameCanvas()
|
||||
font = graphics.Font()
|
||||
font.LoadFont("../../../fonts/7x13.bdf")
|
||||
textColor = graphics.Color(255, 255, 0)
|
||||
pos = offscreen_canvas.width
|
||||
my_text = self.args.text
|
||||
|
||||
while True:
|
||||
offscreen_canvas.Clear()
|
||||
len = graphics.DrawText(offscreen_canvas, font, pos, 10, textColor, my_text)
|
||||
pos -= 1
|
||||
if (pos + len < 0):
|
||||
pos = offscreen_canvas.width
|
||||
|
||||
time.sleep(0.05)
|
||||
offscreen_canvas = self.matrix.SwapOnVSync(offscreen_canvas)
|
||||
|
||||
|
||||
# Main function
|
||||
if __name__ == "__main__":
|
||||
run_text = RunText()
|
||||
if (not run_text.process()):
|
||||
run_text.print_help()
|
||||
81
depends/rpi-rgb-led-matrix/bindings/python/samples/samplebase.py
Executable file
81
depends/rpi-rgb-led-matrix/bindings/python/samples/samplebase.py
Executable file
@@ -0,0 +1,81 @@
|
||||
import argparse
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/..'))
|
||||
from rgbmatrix import RGBMatrix, RGBMatrixOptions
|
||||
|
||||
|
||||
class SampleBase(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
self.parser.add_argument("-r", "--led-rows", action="store", help="Display rows. 16 for 16x32, 32 for 32x32. Default: 32", default=32, type=int)
|
||||
self.parser.add_argument("--led-cols", action="store", help="Panel columns. Typically 32 or 64. (Default: 32)", default=32, type=int)
|
||||
self.parser.add_argument("-c", "--led-chain", action="store", help="Daisy-chained boards. Default: 1.", default=1, type=int)
|
||||
self.parser.add_argument("-P", "--led-parallel", action="store", help="For Plus-models or RPi2: parallel chains. 1..3. Default: 1", default=1, type=int)
|
||||
self.parser.add_argument("-p", "--led-pwm-bits", action="store", help="Bits used for PWM. Something between 1..11. Default: 11", default=11, type=int)
|
||||
self.parser.add_argument("-b", "--led-brightness", action="store", help="Sets brightness level. Default: 100. Range: 1..100", default=100, type=int)
|
||||
self.parser.add_argument("-m", "--led-gpio-mapping", help="Hardware Mapping: regular, adafruit-hat, adafruit-hat-pwm" , choices=['regular', 'regular-pi1', 'adafruit-hat', 'adafruit-hat-pwm'], type=str)
|
||||
self.parser.add_argument("--led-scan-mode", action="store", help="Progressive or interlaced scan. 0 Progressive, 1 Interlaced (default)", default=1, choices=range(2), type=int)
|
||||
self.parser.add_argument("--led-pwm-lsb-nanoseconds", action="store", help="Base time-unit for the on-time in the lowest significant bit in nanoseconds. Default: 130", default=130, type=int)
|
||||
self.parser.add_argument("--led-show-refresh", action="store_true", help="Shows the current refresh rate of the LED panel")
|
||||
self.parser.add_argument("--led-slowdown-gpio", action="store", help="Slow down writing to GPIO. Range: 0..4. Default: 1", default=1, type=int)
|
||||
self.parser.add_argument("--led-no-hardware-pulse", action="store", help="Don't use hardware pin-pulse generation")
|
||||
self.parser.add_argument("--led-rgb-sequence", action="store", help="Switch if your matrix has led colors swapped. Default: RGB", default="RGB", type=str)
|
||||
self.parser.add_argument("--led-pixel-mapper", action="store", help="Apply pixel mappers. e.g \"Rotate:90\"", default="", type=str)
|
||||
self.parser.add_argument("--led-row-addr-type", action="store", help="0 = default; 1=AB-addressed panels; 2=row direct; 3=ABC-addressed panels; 4 = ABC Shift + DE direct", default=0, type=int, choices=[0,1,2,3,4])
|
||||
self.parser.add_argument("--led-multiplexing", action="store", help="Multiplexing type: 0=direct; 1=strip; 2=checker; 3=spiral; 4=ZStripe; 5=ZnMirrorZStripe; 6=coreman; 7=Kaler2Scan; 8=ZStripeUneven... (Default: 0)", default=0, type=int)
|
||||
self.parser.add_argument("--led-panel-type", action="store", help="Needed to initialize special panels. Supported: 'FM6126A'", default="", type=str)
|
||||
self.parser.add_argument("--led-no-drop-privs", dest="drop_privileges", help="Don't drop privileges from 'root' after initializing the hardware.", action='store_false')
|
||||
self.parser.set_defaults(drop_privileges=True)
|
||||
|
||||
def usleep(self, value):
|
||||
time.sleep(value / 1000000.0)
|
||||
|
||||
def run(self):
|
||||
print("Running")
|
||||
|
||||
def process(self):
|
||||
self.args = self.parser.parse_args()
|
||||
|
||||
options = RGBMatrixOptions()
|
||||
|
||||
if self.args.led_gpio_mapping != None:
|
||||
options.hardware_mapping = self.args.led_gpio_mapping
|
||||
options.rows = self.args.led_rows
|
||||
options.cols = self.args.led_cols
|
||||
options.chain_length = self.args.led_chain
|
||||
options.parallel = self.args.led_parallel
|
||||
options.row_address_type = self.args.led_row_addr_type
|
||||
options.multiplexing = self.args.led_multiplexing
|
||||
options.pwm_bits = self.args.led_pwm_bits
|
||||
options.brightness = self.args.led_brightness
|
||||
options.pwm_lsb_nanoseconds = self.args.led_pwm_lsb_nanoseconds
|
||||
options.led_rgb_sequence = self.args.led_rgb_sequence
|
||||
options.pixel_mapper_config = self.args.led_pixel_mapper
|
||||
options.panel_type = self.args.led_panel_type
|
||||
|
||||
|
||||
if self.args.led_show_refresh:
|
||||
options.show_refresh_rate = 1
|
||||
|
||||
if self.args.led_slowdown_gpio != None:
|
||||
options.gpio_slowdown = self.args.led_slowdown_gpio
|
||||
if self.args.led_no_hardware_pulse:
|
||||
options.disable_hardware_pulsing = True
|
||||
if not self.args.drop_privileges:
|
||||
options.drop_privileges=False
|
||||
|
||||
self.matrix = RGBMatrix(options = options)
|
||||
|
||||
try:
|
||||
# Start loop
|
||||
print("Press CTRL-C to stop sample")
|
||||
self.run()
|
||||
except KeyboardInterrupt:
|
||||
print("Exiting\n")
|
||||
sys.exit(0)
|
||||
|
||||
return True
|
||||
30
depends/rpi-rgb-led-matrix/bindings/python/samples/simple-square.py
Executable file
30
depends/rpi-rgb-led-matrix/bindings/python/samples/simple-square.py
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
from samplebase import SampleBase
|
||||
|
||||
|
||||
class SimpleSquare(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SimpleSquare, self).__init__(*args, **kwargs)
|
||||
|
||||
def run(self):
|
||||
offset_canvas = self.matrix.CreateFrameCanvas()
|
||||
while True:
|
||||
for x in range(0, self.matrix.width):
|
||||
offset_canvas.SetPixel(x, x, 255, 255, 255)
|
||||
offset_canvas.SetPixel(offset_canvas.height - 1 - x, x, 255, 0, 255)
|
||||
|
||||
for x in range(0, offset_canvas.width):
|
||||
offset_canvas.SetPixel(x, 0, 255, 0, 0)
|
||||
offset_canvas.SetPixel(x, offset_canvas.height - 1, 255, 255, 0)
|
||||
|
||||
for y in range(0, offset_canvas.height):
|
||||
offset_canvas.SetPixel(0, y, 0, 0, 255)
|
||||
offset_canvas.SetPixel(offset_canvas.width - 1, y, 0, 255, 0)
|
||||
offset_canvas = self.matrix.SwapOnVSync(offset_canvas)
|
||||
|
||||
|
||||
# Main function
|
||||
if __name__ == "__main__":
|
||||
simple_square = SimpleSquare()
|
||||
if (not simple_square.process()):
|
||||
simple_square.print_help()
|
||||
33
depends/rpi-rgb-led-matrix/bindings/python/setup.py
Normal file
33
depends/rpi-rgb-led-matrix/bindings/python/setup.py
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/python
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
core_ext = Extension(
|
||||
name = 'core',
|
||||
sources = ['rgbmatrix/core.cpp'],
|
||||
include_dirs = ['../../include'],
|
||||
library_dirs = ['../../lib'],
|
||||
libraries = ['rgbmatrix'],
|
||||
extra_compile_args = ["-O3", "-Wall"],
|
||||
language = 'c++'
|
||||
)
|
||||
|
||||
graphics_ext = Extension(
|
||||
name = 'graphics',
|
||||
sources = ['rgbmatrix/graphics.cpp'],
|
||||
include_dirs = ['../../include'],
|
||||
library_dirs = ['../../lib'],
|
||||
libraries = ['rgbmatrix'],
|
||||
extra_compile_args = ["-O3", "-Wall"],
|
||||
language = 'c++'
|
||||
)
|
||||
|
||||
setup(
|
||||
name = 'rgbmatrix',
|
||||
version = '0.0.1',
|
||||
author = 'Christoph Friedrich',
|
||||
author_email = 'christoph.friedrich@vonaffenfels.de',
|
||||
classifiers = ['Development Status :: 3 - Alpha'],
|
||||
ext_package = 'rgbmatrix',
|
||||
ext_modules = [core_ext, graphics_ext],
|
||||
packages = ['rgbmatrix']
|
||||
)
|
||||
Reference in New Issue
Block a user