mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-03 06:27:47 +00:00
f57b5ecee9
sharpmem: add implementation of sharpmem display driver * Implement Configure, Clear and ClearBuffer, add some tests, add documentation/comments * Reverse white * Inverted bits, fix and improve ClearBuffer, cleanup * Refine doc comment * Driver refactor, optimizations toggle, additional tests & support for all SKUs * Fix address overflow padding, add wire-level tests for assumed address encoding * Minor rename * Cleanup and doc fixes * Add device configs * Bounds check * Add example and smoketest entry * Use uf2 output file format * Refine example
226 lines
4.9 KiB
Go
226 lines
4.9 KiB
Go
package sharpmem
|
|
|
|
import (
|
|
"image/color"
|
|
"math/rand/v2"
|
|
"testing"
|
|
|
|
qt "github.com/frankban/quicktest"
|
|
)
|
|
|
|
func Test_setBit(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
for i := uint8(0); i < 8; i++ {
|
|
v := uint8(1) << i
|
|
|
|
c.Assert(setBit(0x00, i), qt.Equals, v)
|
|
c.Assert(setBit(0x00, (i+1)%8), qt.Not(qt.Equals), v)
|
|
}
|
|
}
|
|
|
|
func Test_unsetBit(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
for i := uint8(0); i < 8; i++ {
|
|
v := uint8(1) << i
|
|
|
|
c.Assert(unsetBit(v, i), qt.Equals, uint8(0x00))
|
|
c.Assert(unsetBit(v, (i+1)%8), qt.Not(qt.Equals), uint8(0x00))
|
|
}
|
|
}
|
|
|
|
func Test_hasBit(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
for i := uint8(0); i < 8; i++ {
|
|
v := uint8(1) << i
|
|
|
|
c.Assert(hasBit(v, i), qt.Equals, true)
|
|
c.Assert(hasBit(v, (i+1)%8), qt.Equals, false)
|
|
}
|
|
}
|
|
|
|
func Test_bitfieldBufLen(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
for i := int16(1); i < 536; i++ {
|
|
requiredBufferSize := i / 8
|
|
wouldOverflow := i % 8
|
|
|
|
if wouldOverflow > 0 {
|
|
requiredBufferSize += 1
|
|
}
|
|
|
|
c.Assert(bitfieldBufLen(i), qt.Equals, requiredBufferSize)
|
|
}
|
|
}
|
|
|
|
type mockBus struct {
|
|
b []byte
|
|
}
|
|
|
|
func (m *mockBus) Tx(w, _ []byte) error {
|
|
m.b = append(m.b, w...)
|
|
return nil
|
|
}
|
|
|
|
func (m *mockBus) Transfer(b byte) (byte, error) {
|
|
m.b = append(m.b, b)
|
|
return 0x00, nil
|
|
}
|
|
|
|
type mockPin struct{}
|
|
|
|
func (m mockPin) High() {
|
|
}
|
|
|
|
func (m mockPin) Low() {
|
|
}
|
|
|
|
func Test_Device(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
cfgs := []Config{
|
|
ConfigLS010B7DH04,
|
|
ConfigLS011B7DH03,
|
|
ConfigLS012B7DD01,
|
|
ConfigLS013B7DH03,
|
|
ConfigLS013B7DH05,
|
|
ConfigLS018B7DH02,
|
|
ConfigLS027B7DH01,
|
|
ConfigLS027B7DH01A,
|
|
ConfigLS032B7DD02,
|
|
ConfigLS044Q7DH01,
|
|
}
|
|
|
|
cfgLen := len(cfgs)
|
|
for i := 0; i < cfgLen; i++ {
|
|
cfgs = append(cfgs, Config{
|
|
Width: cfgs[i].Width,
|
|
Height: cfgs[i].Height,
|
|
DisableOptimizations: true,
|
|
})
|
|
}
|
|
|
|
spi := &mockBus{}
|
|
pin := mockPin{}
|
|
display := New(spi, pin)
|
|
|
|
for _, cfg := range cfgs {
|
|
display.Configure(cfg)
|
|
|
|
x, y := display.Size()
|
|
c.Assert(x, qt.Equals, cfg.Width)
|
|
c.Assert(y, qt.Equals, cfg.Height)
|
|
|
|
for i := 0; i < 10; i++ {
|
|
x := int16(rand.IntN(int(cfg.Width)))
|
|
y := int16(rand.IntN(int(cfg.Height)))
|
|
display.SetPixel(x, y, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
x := int16(rand.IntN(int(cfg.Width)))
|
|
y := int16(rand.IntN(int(cfg.Height)))
|
|
display.SetPixel(x, y, color.RGBA{R: 0, G: 0, B: 0, A: 255})
|
|
}
|
|
|
|
err := display.Display()
|
|
c.Assert(err, qt.Equals, nil)
|
|
|
|
err = display.ClearDisplay()
|
|
c.Assert(err, qt.Equals, nil)
|
|
|
|
display.ClearBuffer()
|
|
}
|
|
}
|
|
|
|
func Test_HiPad(t *testing.T) {
|
|
c := qt.New(t)
|
|
|
|
spi := &mockBus{}
|
|
pin := mockPin{}
|
|
display := New(spi, pin)
|
|
|
|
t.Run("LS011B7DH03, 8-bit address", func(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
spi.b = nil
|
|
})
|
|
|
|
display.Configure(ConfigLS011B7DH03)
|
|
|
|
display.SetPixel(0, display.height-1, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
|
err := display.Display()
|
|
c.Assert(err, qt.Equals, nil)
|
|
|
|
// 160 perfectly divisible by 16, so 20 bytes of pixel data
|
|
c.Assert(spi.b, qt.HasLen, 2+20+2)
|
|
|
|
// line is 1-indexed on the wire (67+1)
|
|
// 68 in binary
|
|
// 0b01000100
|
|
|
|
// DDDDDMMM
|
|
c.Assert(spi.b[0], qt.Equals, uint8(0b00000011)) // mode 1, vcom is high on first run
|
|
|
|
c.Assert(spi.b[1], qt.Equals, uint8(0b01000100)) // the actual address
|
|
})
|
|
|
|
t.Run("LS018B7DH02, 9-bit address", func(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
spi.b = nil
|
|
})
|
|
|
|
display.Configure(ConfigLS018B7DH02)
|
|
|
|
display.SetPixel(0, display.height-1, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
|
err := display.Display()
|
|
c.Assert(err, qt.Equals, nil)
|
|
|
|
// 2 first bytes command+address
|
|
// 230 bits are not divisible by 16, 240 is (15*16), so 30 bytes for line data
|
|
// 2 trailing bytes
|
|
c.Assert(spi.b, qt.HasLen, 2+30+2)
|
|
|
|
// line is 1-indexed on the wire (302+1)
|
|
// 303 in binary (split in 2 bytes)
|
|
// R
|
|
// 0b00000001 0b00101111
|
|
// ^
|
|
|
|
// RDDDDMMM
|
|
c.Assert(spi.b[0], qt.Equals, uint8(0b10000011)) // mode 1, vcom is high on first run
|
|
// ^
|
|
|
|
c.Assert(spi.b[1], qt.Equals, uint8(0b00101111)) // rest of the address (low 8 bits)
|
|
})
|
|
|
|
t.Run("LS032B7DD02, 10-bit address", func(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
spi.b = nil
|
|
})
|
|
|
|
display.Configure(ConfigLS032B7DD02)
|
|
|
|
display.SetPixel(0, display.height-1, color.RGBA{R: 255, G: 255, B: 255, A: 255})
|
|
err := display.Display()
|
|
c.Assert(err, qt.Equals, nil)
|
|
|
|
c.Assert(spi.b, qt.HasLen, 2+336/8+2) // 2 command+address, width / 2, 2 trailing bytes
|
|
|
|
// line is 1-indexed on the wire (535+1)
|
|
// 536 in binary (split in 2 bytes)
|
|
// RR
|
|
// 0b00000010 0b00011000
|
|
// ^^
|
|
|
|
// RRDDDMMM
|
|
c.Assert(spi.b[0], qt.Equals, uint8(0b10000011)) // mode 1, vcom is high on first run
|
|
// ^^
|
|
|
|
c.Assert(spi.b[1], qt.Equals, uint8(0b00011000)) // rest of the address (low 8 bits)
|
|
})
|
|
|
|
}
|