emulator: improvements and integration

pull/3/head
Máximo Cuadros 8 years ago
parent 40b62517bc
commit 741ec8a743

@ -81,6 +81,15 @@ The image of the header was recorded using this few lines, the running _Mario_ g
Check the folder [`examples`](https://github.com/mcuadros/go-rpi-rgb-led-matrix/tree/master/examples) folder for more examples Check the folder [`examples`](https://github.com/mcuadros/go-rpi-rgb-led-matrix/tree/master/examples) folder for more examples
Matrix Emulation
----------------
As part of the library an small Matrix emulator is provided. The emulator renderize a virtual RGB matrix on a window in your desktop, without needing a real RGB matrix connected to your computer.
To execute the emulator set the `MATRIX_EMULATOR` environment variable to `1`, then when `NewRGBLedMatrix` is used, a `emulator.Emulator` is returned instead of a interface the real board.
License License
------- -------

@ -3,10 +3,12 @@ package emulator
import ( import (
"image" "image"
"image/color" "image/color"
"log" "os"
"sync" "sync"
"fmt"
"golang.org/x/exp/shiny/driver" "golang.org/x/exp/shiny/driver"
"golang.org/x/exp/shiny/imageutil" "golang.org/x/exp/shiny/imageutil"
"golang.org/x/exp/shiny/screen" "golang.org/x/exp/shiny/screen"
@ -14,10 +16,8 @@ import (
"golang.org/x/mobile/event/size" "golang.org/x/mobile/event/size"
) )
var ( const DefaultPixelPitch = 12
black = color.RGBA{0x00, 0x00, 0x00, 0xff} const windowTitle = "RGB led matrix emulator"
red = color.RGBA{0x7f, 0x00, 0x00, 0x7f}
)
var margin = 10 var margin = 10
@ -27,60 +27,81 @@ type Emulator struct {
Width int Width int
Height int Height int
leds []color.Color leds []color.Color
w screen.Window w screen.Window
s screen.Screen
wg sync.WaitGroup
isReady bool isReady bool
}
func NewEmulator(w, h, pixelPitch int, autoInit bool) *Emulator {
e := &Emulator{
PixelPitch: pixelPitch,
Gutter: int(float64(pixelPitch) * 0.66),
Width: w,
Height: h,
}
wg sync.WaitGroup if autoInit {
e.Init()
}
return e
} }
// Init initialize the emulator, creating a new Window and waiting until is
// painted. If something goes wrong the function panics
func (e *Emulator) Init() { func (e *Emulator) Init() {
e.leds = make([]color.Color, 2048) e.leds = make([]color.Color, 2048)
e.wg.Add(1) e.wg.Add(1)
go e.init() go driver.Main(e.mainWindowLoop)
e.wg.Wait() e.wg.Wait()
} }
func (e *Emulator) init() { func (e *Emulator) mainWindowLoop(s screen.Screen) {
driver.Main(func(s screen.Screen) { var err error
var err error e.s = s
e.w, err = s.NewWindow(&screen.NewWindowOptions{ e.w, err = s.NewWindow(&screen.NewWindowOptions{
Title: "Basic Shiny Example", Title: windowTitle,
}) })
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer e.w.Release() defer e.w.Release()
var sz size.Event var sz size.Event
for { for {
evn := e.w.NextEvent() evn := e.w.NextEvent()
switch evn := evn.(type) { switch evn := evn.(type) {
case paint.Event: case paint.Event:
for _, r := range imageutil.Border(sz.Bounds(), margin) { e.drawContext(sz)
e.w.Fill(r, red, screen.Src) if e.isReady {
} continue
e.w.Fill(sz.Bounds().Inset(margin), black, screen.Src)
e.w.Publish()
if e.isReady {
continue
}
e.Apply(make([]color.Color, 2048))
e.wg.Done()
e.isReady = true
case size.Event:
sz = evn
case error:
log.Print(e)
} }
e.Apply(make([]color.Color, 2048))
e.wg.Done()
e.isReady = true
case size.Event:
sz = evn
case error:
fmt.Fprintln(os.Stderr, e)
} }
}) }
}
func (e *Emulator) drawContext(sz size.Event) {
for _, r := range imageutil.Border(sz.Bounds(), margin) {
e.w.Fill(r, color.White, screen.Src)
}
e.w.Fill(sz.Bounds().Inset(margin), color.Black, screen.Src)
e.w.Publish()
} }
func (e *Emulator) Geometry() (width, height int) { func (e *Emulator) Geometry() (width, height int) {
@ -98,8 +119,10 @@ func (e *Emulator) Apply(leds []color.Color) error {
x += margin * 2 x += margin * 2
y += margin * 2 y += margin * 2
c := e.At(col + (row * e.Width)) color := e.At(col + (row * e.Width))
e.w.Fill(image.Rect(x, y, x+e.PixelPitch, y+e.PixelPitch), c, screen.Over) led := image.Rect(x, y, x+e.PixelPitch, y+e.PixelPitch)
e.w.Fill(led, color, screen.Over)
} }
} }

@ -29,7 +29,10 @@ import "C"
import ( import (
"fmt" "fmt"
"image/color" "image/color"
"os"
"unsafe" "unsafe"
"github.com/mcuadros/go-rpi-rgb-led-matrix/emulator"
) )
// DefaultConfig default WS281x configuration // DefaultConfig default WS281x configuration
@ -116,8 +119,14 @@ type RGBLedMatrix struct {
leds []C.uint32_t leds []C.uint32_t
} }
const MatrixEmulatorENV = "MATRIX_EMULATOR"
// NewRGBLedMatrix returns a new matrix using the given size and config // NewRGBLedMatrix returns a new matrix using the given size and config
func NewRGBLedMatrix(config *HardwareConfig) (*RGBLedMatrix, error) { func NewRGBLedMatrix(config *HardwareConfig) (Matrix, error) {
if isMatrixEmulator() {
return buildMatrixEmulator(config), nil
}
w, h := config.geometry() w, h := config.geometry()
c := &RGBLedMatrix{ c := &RGBLedMatrix{
@ -134,6 +143,19 @@ func NewRGBLedMatrix(config *HardwareConfig) (*RGBLedMatrix, error) {
return c, nil return c, nil
} }
func isMatrixEmulator() bool {
if os.Getenv(MatrixEmulatorENV) == "1" {
return true
}
return false
}
func buildMatrixEmulator(config *HardwareConfig) Matrix {
w, h := config.geometry()
return emulator.NewEmulator(w, h, emulator.DefaultPixelPitch, true)
}
// Initialize initialize library, must be called once before other functions are // Initialize initialize library, must be called once before other functions are
// called. // called.
func (c *RGBLedMatrix) Initialize() error { func (c *RGBLedMatrix) Initialize() error {

Loading…
Cancel
Save