From d2dea8058c88b39f161178f59c6bfec0e32dfa02 Mon Sep 17 00:00:00 2001 From: Martin Ashby Date: Fri, 18 May 2018 22:22:20 +0100 Subject: Initial implementation of go unicorn hat driver --- FakeUnicorn.go | 94 ++++++++++++++++++++++++++++++++++++ RealUnicorn.go | 62 ++++++++++++++++++++++++ Unicorn.go | 148 ++++++--------------------------------------------------- 3 files changed, 171 insertions(+), 133 deletions(-) create mode 100644 FakeUnicorn.go create mode 100644 RealUnicorn.go diff --git a/FakeUnicorn.go b/FakeUnicorn.go new file mode 100644 index 0000000..2258e58 --- /dev/null +++ b/FakeUnicorn.go @@ -0,0 +1,94 @@ +package main + +import ( + "github.com/veandco/go-sdl2/sdl" +) + +type FakeUnicorn struct { + BaseUnicorn + displayWidth int32 + displayHeight int32 + window *sdl.Window + renderer *sdl.Renderer +} + +// NewFake ... +// Constructs a new fake unicorn out of paint and glue +func NewFake(width, height uint8) (*FakeUnicorn, error) { + if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil { + return nil, err + } + + unicorn := &FakeUnicorn{ + BaseUnicorn{ + pixels: makePixels(width, height), + }, + 300, + 300, + nil, + nil, + } + if err := unicorn.createWindow(); err != nil { + unicorn.Close() + return nil, err + } + if err := unicorn.createRenderer(); err != nil { + unicorn.Close() + return nil, err + } + return unicorn, nil +} + +func (f *FakeUnicorn) createWindow() error { + window, err := sdl.CreateWindow("Fake Unicorn", + sdl.WINDOWPOS_UNDEFINED, + sdl.WINDOWPOS_UNDEFINED, + f.displayWidth, + f.displayHeight, + sdl.WINDOW_SHOWN) + f.window = window + return err +} + +func (f *FakeUnicorn) createRenderer() error { + renderer, err := sdl.CreateRenderer(f.window, -1, sdl.RENDERER_ACCELERATED) + f.renderer = renderer + return err +} + +func (f *FakeUnicorn) Close() error { + if f.window != nil { + f.window.Destroy() + } + if f.renderer != nil { + f.renderer.Destroy() + } + return nil +} + +func (f *FakeUnicorn) Show() { + width, height := f.GetWidth(), f.GetHeight() + for x := uint8(0); x < width; x++ { + for y := uint8(0); y < height; y++ { + r, g, b := rgb(f.pixels[x][y]) + if err := f.renderer.SetDrawColor(r, g, b, uint8(255)); err != nil { + panic(err) + } + cellWidth := f.displayWidth / int32(width) + cellHeight := f.displayHeight / int32(height) + if err := f.renderer.FillRect(&sdl.Rect{ + X: cellWidth * int32(x), + Y: f.displayHeight - (cellHeight * int32(y)) - cellHeight, // SDL Y coordinate is from the top + W: cellWidth, + H: cellHeight, + }); err != nil { + panic(err) + } + } + } + f.renderer.Present() +} + +func (f *FakeUnicorn) Off() { + f.Close() +} diff --git a/RealUnicorn.go b/RealUnicorn.go new file mode 100644 index 0000000..d9665d8 --- /dev/null +++ b/RealUnicorn.go @@ -0,0 +1,62 @@ +package main + +import ( + "golang.org/x/exp/io/spi" + "log" +) + +type RealUnicorn struct { + BaseUnicorn + device *spi.Device +} + +// NewReal ... +// Constructs a new real unicorn from fairy dust and sprinkles +func NewReal() (*RealUnicorn, error) { + dev, err := spi.Open(&spi.Devfs{ + Dev: "/dev/spidev0.0", + Mode: spi.Mode0, + MaxSpeed: 9000000, + }) + if err != nil { + return nil, err + } + + return &RealUnicorn{ + BaseUnicorn{ + pixels: makePixels(16, 16), + }, + dev, + }, nil +} + +func (u *RealUnicorn) Show() { + // Width * height * colours + leading bit + width := u.GetWidth() + height := u.GetHeight() + write := make([]byte, (width*height*3)+1) + + // Add the leading bit + write[0] = 0x72 + // Add all the pixel values + ix := 1 + for x := uint8(0); x < width; x++ { + for y := uint8(0); y < height; y++ { + for j := 0; j < 3; j++ { + write[ix] = u.pixels[x][y][j] + ix++ + } + } + } + // Write to the device + err := u.device.Tx(write, nil) + if err != nil { + log.Printf("Error writing to SPI device %v", err) + } +} +func (u *RealUnicorn) Off() { + u.Close() +} +func (u *RealUnicorn) Close() error { + return u.device.Close() +} diff --git a/Unicorn.go b/Unicorn.go index 2e0e73f..905cc0a 100644 --- a/Unicorn.go +++ b/Unicorn.go @@ -1,9 +1,7 @@ package main import ( - "github.com/veandco/go-sdl2/sdl" - // "golang.org/x/exp/io/spi" - // "github.com/veandco/go-sdl2/sdl" + "log" ) // Unicorn ... @@ -33,126 +31,37 @@ type Unicorn interface { // Get a unicorn. Tries to get you a real one, // if it can't find one then gives you a fake one. func GetUnicorn() (unicorn Unicorn, err error) { - // unicorn, err = NewReal() - // if err != nil { - // log.Println("Couldn't get a real unicorn, trying a fake one") - // unicorn, err = NewFake(int8(16), int8(16)) - // } + unicorn, err = NewReal() + if err != nil { + log.Println("Couldn't get a real unicorn, trying a fake one") + unicorn, err = NewFake(uint8(16), uint8(16)) + } unicorn, err = NewFake(uint8(16), uint8(16)) return } -// FakeUnicorn ... -// Shows an SDL window pretending to be a unicorn. -type FakeUnicorn struct { +type BaseUnicorn struct { pixels [][][]uint8 - displayWidth int32 - displayHeight int32 - - window *sdl.Window - renderer *sdl.Renderer -} - -// NewFake ... -// Constructs a new fake unicorn out of paint and glue -func NewFake(width, height uint8) (*FakeUnicorn, error) { - if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil { - return nil, err - } - - unicorn := &FakeUnicorn{ - pixels: makePixels(width, height), - window: nil, - renderer: nil, - displayWidth: 300, - displayHeight: 300, - } - if err := unicorn.createWindow(); err != nil { - unicorn.Close() - return nil, err - } - if err := unicorn.createRenderer(); err != nil { - unicorn.Close() - return nil, err - } - return unicorn, nil } -func (f *FakeUnicorn) createWindow() error { - window, err := sdl.CreateWindow("Fake Unicorn", - sdl.WINDOWPOS_UNDEFINED, - sdl.WINDOWPOS_UNDEFINED, - f.displayWidth, - f.displayHeight, - sdl.WINDOW_SHOWN) - f.window = window - return err -} - -func (f *FakeUnicorn) createRenderer() error { - renderer, err := sdl.CreateRenderer(f.window, -1, sdl.RENDERER_ACCELERATED) - f.renderer = renderer - return err -} - -func (f *FakeUnicorn) Close() error { - if f.window != nil { - f.window.Destroy() - } - if f.renderer != nil { - f.renderer.Destroy() - } - return nil -} - -func (f *FakeUnicorn) GetWidth() uint8 { +func (f *BaseUnicorn) GetWidth() uint8 { return uint8(len(f.pixels)) } -func (f *FakeUnicorn) GetHeight() uint8 { +func (f *BaseUnicorn) GetHeight() uint8 { if len(f.pixels) > 0 { return uint8(len(f.pixels[0])) } return 0 } -func (f *FakeUnicorn) GetPixels() [][][]uint8 { +func (f *BaseUnicorn) GetPixels() [][][]uint8 { return f.pixels } -func (f *FakeUnicorn) SetPixel(x, y, r, g, b uint8) { +func (f *BaseUnicorn) SetPixel(x, y, r, g, b uint8) { f.pixels[x][y] = []uint8{r, g, b} } -func (f *FakeUnicorn) Show() { - width, height := f.GetWidth(), f.GetHeight() - for x := uint8(0); x < width; x++ { - for y := uint8(0); y < height; y++ { - r, g, b := rgb(f.pixels[x][y]) - if err := f.renderer.SetDrawColor(r, g, b, uint8(255)); err != nil { - panic(err) - } - cellWidth := f.displayWidth / int32(width) - cellHeight := f.displayHeight / int32(height) - if err := f.renderer.FillRect(&sdl.Rect{ - X: cellWidth * int32(x), - Y: f.displayHeight - (cellHeight * int32(y)) - cellHeight, // SDL Y coordinate is from the top - W: cellWidth, - H: cellHeight, - }); err != nil { - panic(err) - } - } - } - f.renderer.Present() -} - -func rgb(pixel []uint8) (uint8, uint8, uint8) { - return pixel[0], pixel[1], pixel[2] -} - -func (f *FakeUnicorn) Clear() { +func (f *BaseUnicorn) Clear() { f.pixels = makePixels(f.GetWidth(), f.GetHeight()) } -func (f *FakeUnicorn) Off() { - f.Close() -} func makePixels(width, height uint8) [][][]uint8 { pixels := make([][][]uint8, width) @@ -165,34 +74,7 @@ func makePixels(width, height uint8) [][][]uint8 { return pixels } -// RealUnicorn ... -// A real one! *gasps* -// type RealUnicorn struct {} - -// // NewReal ... -// // Constructs a new real unicorn from fairy dust and sprinkles -// func NewReal() (*RealUnicorn, error) { -// return nil, errors.New("Couldn't make a real unicorn sorry") -// } - -// func (u *RealUnicorn) GetWidth() int8 { -// return 0 -// } -// func (u *RealUnicorn) GetHeight() int8 { -// return 0 -// } -// func (u *RealUnicorn) GetPixels() [][][]int8 { -// return nil -// } -// func (u *RealUnicorn) SetPixel(x, y, r, g, b int8) { - -// } -// func (u *RealUnicorn) Show() { -// } -// func (u *RealUnicorn) Clear() { - -// } -// func (u *RealUnicorn) Off() { - -// } +func rgb(pixel []uint8) (uint8, uint8, uint8) { + return pixel[0], pixel[1], pixel[2] +} \ No newline at end of file -- cgit v1.2.3-ZIG