From 58fa88515eba310e4ee7a504c568b424beddda11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ximo=20Cuadros?= Date: Sat, 22 Oct 2016 19:13:41 +0200 Subject: [PATCH] matrix implementation --- matrix.go | 228 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 150 insertions(+), 78 deletions(-) diff --git a/matrix.go b/matrix.go index 17fd2a5..2d9045d 100644 --- a/matrix.go +++ b/matrix.go @@ -1,112 +1,184 @@ -package main +package rgbmatrix /* -#cgo CFLAGS: -std=c99 -Ivendor/rpi-rgb-led-matrix/include -DSHOW_REFRESH_RATE -#cgo LDFLAGS: -lrgbmatrix -Lvendor/rpi-rgb-led-matrix/lib -lstdc++ -lm +#cgo CFLAGS: -std=c99 -I${SRCDIR}/vendor/rpi-rgb-led-matrix/include -DSHOW_REFRESH_RATE +#cgo LDFLAGS: -lrgbmatrix -L${SRCDIR}/vendor/rpi-rgb-led-matrix/lib -lstdc++ -lm #include -#include -#include -#include -struct RGBLedMatrix *matrix; -struct LedCanvas *offscreen_canvas; - -void setCanvas(struct LedCanvas *offscreen_canvas, const uint32_t pixels[]) { +void led_matrix_swap(struct LedCanvas *offscreen_canvas, + int width, int height, const uint32_t pixels[]) { int i, x, y; - uint32_t color; - for (y = 0; y < 32; ++y) { - for (x = 0; x < 64; ++x) { - i = x + (y * 64); - - color = pixels[i]; - led_canvas_set_pixel(offscreen_canvas, x, y, - (color >> 16) & 255, (color >> 8) & 255, color & 255); - } - } -} - -int example(struct RGBLedMatrixOptions *options) { - struct LedCanvas *offscreen_canvas; - int width, height; - int x, y, i; - - matrix = led_matrix_create_from_options(options, NULL, NULL); - if (matrix == NULL) - return 1; - - offscreen_canvas = led_matrix_create_offscreen_canvas(matrix); - - led_canvas_get_size(offscreen_canvas, &width, &height); - - fprintf(stderr, "Size: %dx%d. Hardware gpio mapping: %s\n", - width, height, options->hardware_mapping); - - for (i = 0; i < 1000; ++i) { - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - led_canvas_set_pixel(offscreen_canvas, x, y, i & 0xff, x, y); - } + uint32_t color; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + i = x + (y * 64); + color = pixels[i]; + + led_canvas_set_pixel(offscreen_canvas, x, y, + (color >> 16) & 255, (color >> 8) & 255, color & 255); } - - offscreen_canvas = led_matrix_swap_on_vsync(matrix, offscreen_canvas); } - - led_matrix_delete(matrix); - - return 0; } */ import "C" import ( "fmt" "image/color" - "time" "unsafe" ) -func main() { +// DefaultConfig default WS281x configuration +var DefaultConfig = HardwareConfig{ + Rows: 32, + ChainLength: 1, + Parallel: 1, + PWMBits: 11, + PWMLSBNanoseconds: 130, + Brightness: 100, + ScanMode: Progressive, +} + +// HardwareConfig rgb-led-matrix configuration +type HardwareConfig struct { + // Rows the number of rows supported by the display, so 32 or 16. + Rows int + // ChainLengthis the number of displays daisy-chained together + // (output of one connected to input of next). + ChainLength int + // Parallel is 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 rows * parallel. + Parallel int + // 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. + PWMBits int + // 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. + PWMLSBNanoseconds int // the DMA channel to use + // Brightness is the initial brightness of the panel in percent. Valid range + // is 1..100 + Brightness int + // ScanMode progressive or interlaced + ScanMode ScanMode // strip color layout + // Disable the PWM hardware subsystem to create pulses. Typically, you don't + // want to disable hardware pulsing, this is mostly for debugging and figuring + // out if there is interference with the sound system. + // This won't do anything if output enable is not connected to GPIO 18 in + // non-standard wirings. + DisableHardwarePulsing bool + + ShowRefreshRate bool + InverseColors bool +} + +func (c *HardwareConfig) geometry() (width, height int) { + return c.Rows * c.ChainLength, c.Rows +} + +func (c *HardwareConfig) toC() *C.struct_RGBLedMatrixOptions { o := &C.struct_RGBLedMatrixOptions{} - o.rows = 32 - o.chain_length = 2 + o.rows = C.int(c.Rows) + o.chain_length = C.int(c.ChainLength) + o.parallel = C.int(c.Parallel) + o.pwm_bits = C.int(c.PWMBits) + o.pwm_lsb_nanoseconds = C.int(c.PWMLSBNanoseconds) + o.brightness = C.int(c.Brightness) + o.scan_mode = C.int(c.ScanMode) + // o.disable_hardware_pulsing = c.DisableHardwarePulsing + // o.show_refresh_rate = c.ShowRefreshRate + // o.inverse_colors = c.InverseColors + + return o +} - s := time.Now() - C.example(o) - fmt.Println(time.Since(s)) +type ScanMode int8 - s = time.Now() - example(o) - fmt.Println(time.Since(s)) +const ( + Progressive ScanMode = 0 + Interlaced ScanMode = 1 +) + +// RGBLedMatrix matrix representation for ws281x +type RGBLedMatrix struct { + Config *HardwareConfig + height int + width int + matrix *C.struct_RGBLedMatrix + leds []C.uint32_t } -func example(o *C.struct_RGBLedMatrixOptions) { - matrix := C.led_matrix_create_from_options(o, nil, nil) - if matrix == nil { - panic("jodido") +// NewRGBLedMatrix returns a new matrix using the given size and config +func NewRGBLedMatrix(config *HardwareConfig) (Matrix, error) { + w, h := config.geometry() + + c := &RGBLedMatrix{ + Config: config, + width: w, height: h, + matrix: C.led_matrix_create_from_options(config.toC(), nil, nil), + leds: make([]C.uint32_t, 2048), + } + + if c.matrix == nil { + return nil, fmt.Errorf("unable to allocate memory") } - //offscreen := C.led_matrix_create_offscreen_canvas(matrix) - for i := 1; i < 1000; i++ { - p := make([]C.uint32_t, 2048) - for y := 0; y < 32; y++ { - for x := 0; x < 64; x++ { - pos := x + (y * 64) + return c, nil +} - c := color.RGBA{uint8(i & 0xff), uint8(x), uint8(y), 0} - p[pos] = C.uint32_t(colorToUint32(c)) - } - } +// Initialize initialize library, must be called once before other functions are +// called. +func (c *RGBLedMatrix) Initialize() error { + return nil +} - C.setCanvas(matrix, (*C.uint32_t)(unsafe.Pointer(&p[0]))) - //offscreen = C.led_matrix_swap_on_vsync(matrix, offscreen) - } +// Geometry returns the width and the height of the matrix +func (c *RGBLedMatrix) Geometry() (width, height int) { + return c.width, c.height +} + +// Render update the display with the data from the LED buffer +func (c *RGBLedMatrix) Render() error { + C.led_matrix_swap( + c.matrix, + C.int(64), C.int(32), + (*C.uint32_t)(unsafe.Pointer(&c.leds[0])), + ) - C.led_matrix_delete(matrix) + return nil +} + +// At return an Color which allows access to the LED display data as +// if it were a sequence of 24-bit RGB values. +func (c *RGBLedMatrix) At(position int) color.Color { + return uint32ToColor(c.leds[position]) +} + +// Set set LED at position x,y to the provided 24-bit color value. +func (c *RGBLedMatrix) Set(position int, color color.Color) { + c.leds[position] = C.uint32_t(colorToUint32(color)) +} + +// Close finalizes the ws281x interface +func (c *RGBLedMatrix) Close() error { + C.led_matrix_delete(c.matrix) + return nil } func colorToUint32(c color.Color) uint32 { // A color's RGBA method returns values in the range [0, 65535] red, green, blue, _ := c.RGBA() - // r<<16 | g<<8 | b return (red>>8)<<16 | (green>>8)<<8 | blue>>8 } + +func uint32ToColor(u C.uint32_t) color.Color { + return color.RGBA{ + uint8(u>>16) & 255, + uint8(u>>8) & 255, + uint8(u>>0) & 255, + 0, + } +}