mirror of https://github.com/periph/devices
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
2.9 KiB
Go
117 lines
2.9 KiB
Go
// Copyright 2018 The Periph Authors. All rights reserved.
|
|
// Use of this source code is governed under the Apache License, Version 2.0
|
|
// that can be found in the LICENSE file.
|
|
|
|
// Package unicornhd implements interfacing code to Pimoroni's Unicorn HD hat.
|
|
package unicornhd
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
|
|
"periph.io/x/conn/display"
|
|
"periph.io/x/conn/physic"
|
|
"periph.io/x/conn/spi"
|
|
)
|
|
|
|
const (
|
|
height = 16
|
|
width = 16
|
|
speed = 9 * physic.MegaHertz
|
|
bits = 8
|
|
prefix = 0x72
|
|
)
|
|
|
|
// Dev represents a Unicorn HAT HD (https://shop.pimoroni.com/products/unicorn-hat-hd)
|
|
// connected over a SPI port.
|
|
type Dev struct {
|
|
// Communication
|
|
connector spi.Conn
|
|
pixels *image.NRGBA
|
|
txBuffer []byte
|
|
}
|
|
|
|
// New returns a unicornHD driver that communicates over SPI.
|
|
//
|
|
// The SPI port speed must be 9MHz and the SPI mode, 0, as in the
|
|
// python example library.
|
|
func New(port spi.Port) (*Dev, error) {
|
|
connector, err := port.Connect(speed, spi.Mode0, bits)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Dev{
|
|
connector: connector,
|
|
pixels: image.NewNRGBA(image.Rect(0, 0, width, height)),
|
|
txBuffer: make([]byte, width*height*3+1),
|
|
}, nil
|
|
}
|
|
|
|
// String implements display.Drawer
|
|
//
|
|
// Returns a string with the driver name and the width and height of the
|
|
// display.
|
|
func (device *Dev) String() string {
|
|
return fmt.Sprintf("UnicornHD{%d, %d}", width, height)
|
|
}
|
|
|
|
// Halt sets all the pixels to black. Error is always nil.
|
|
func (device *Dev) Halt() error {
|
|
black := color.RGBA{0, 0, 0, 0}
|
|
return device.Draw(device.Bounds(), &image.Uniform{black}, image.Point{})
|
|
}
|
|
|
|
// ColorModel implements devices.Display. There's no surprise, it is
|
|
// color.RGBAModel.
|
|
func (device *Dev) ColorModel() color.Model {
|
|
return color.NRGBAModel
|
|
}
|
|
|
|
// Bounds implements devices.Display.
|
|
//
|
|
// Min is guaranteed to be {0, 0}.
|
|
func (device *Dev) Bounds() image.Rectangle {
|
|
return device.pixels.Bounds()
|
|
}
|
|
|
|
// Draw implements devices.Display.
|
|
//
|
|
// Using something else than image.NRGBA is 10x slower. When using image.NRGBA,
|
|
// the alpha channel is ignored.
|
|
func (device *Dev) Draw(dstRect image.Rectangle, src image.Image, srcPts image.Point) error {
|
|
// Use stdlib image copying functionality.
|
|
draw.Draw(device.pixels, dstRect, src, srcPts, draw.Src)
|
|
// And then copy the image into the transmission buffer, where it is sent via SPI.
|
|
return device.flush()
|
|
}
|
|
|
|
func (device *Dev) flush() error {
|
|
device.txBuffer[0] = prefix
|
|
x := 0
|
|
y := 0
|
|
for i := 0; i < width*height; i++ {
|
|
color := device.pixels.NRGBAAt(x, y)
|
|
x++
|
|
if x >= width {
|
|
x = 0
|
|
y++
|
|
}
|
|
red := color.R
|
|
green := color.G
|
|
blue := color.B
|
|
|
|
k := 3*i + 1
|
|
device.txBuffer[k] = red
|
|
device.txBuffer[k+1] = green
|
|
device.txBuffer[k+2] = blue
|
|
}
|
|
|
|
return device.connector.Tx(device.txBuffer, nil)
|
|
}
|
|
|
|
// Test that driver implements display.Drawer interface. This is
|
|
// enforced at compile time.
|
|
var _ display.Drawer = (*Dev)(nil)
|