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.
devices/serlcd/serlcd_test.go

388 lines
15 KiB
Go

// Copyright 2024 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 serlcd
import (
"errors"
"fmt"
"os"
"testing"
"time"
"periph.io/x/conn/v3/display"
"periph.io/x/conn/v3/display/displaytest"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/i2c/i2creg"
"periph.io/x/conn/v3/i2c/i2ctest"
"periph.io/x/host/v3"
)
var liveDevice bool = false
var bus i2c.Bus
var eepromTests bool = false
var sleepDuration time.Duration = time.Millisecond
// Playback for interface tests.
var pbInterface = []i2ctest.IO{
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x70, 0x61, 0x72, 0x6b, 0x46, 0x75, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x4c, 0x43, 0x44, 0x20, 0x32, 0x30, 0x78, 0x34, 0x20, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x2d, 0x20, 0x70}},
{Addr: DefaultI2CAddress, W: []uint8{0x65, 0x72, 0x69, 0x70, 0x68, 0x2e, 0x69, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x2e, 0x43, 0x6f, 0x6e, 0x6e}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x41, 0x75, 0x74, 0x6f, 0x20, 0x53, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x80}},
{Addr: DefaultI2CAddress, W: []uint8{0x41}},
{Addr: DefaultI2CAddress, W: []uint8{0x42}},
{Addr: DefaultI2CAddress, W: []uint8{0x43}},
{Addr: DefaultI2CAddress, W: []uint8{0x44}},
{Addr: DefaultI2CAddress, W: []uint8{0x45}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x47}},
{Addr: DefaultI2CAddress, W: []uint8{0x48}},
{Addr: DefaultI2CAddress, W: []uint8{0x49}},
{Addr: DefaultI2CAddress, W: []uint8{0x4a}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x4c}},
{Addr: DefaultI2CAddress, W: []uint8{0x4d}},
{Addr: DefaultI2CAddress, W: []uint8{0x4e}},
{Addr: DefaultI2CAddress, W: []uint8{0x4f}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x51}},
{Addr: DefaultI2CAddress, W: []uint8{0x52}},
{Addr: DefaultI2CAddress, W: []uint8{0x53}},
{Addr: DefaultI2CAddress, W: []uint8{0x54}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc0}},
{Addr: DefaultI2CAddress, W: []uint8{0x41}},
{Addr: DefaultI2CAddress, W: []uint8{0x42}},
{Addr: DefaultI2CAddress, W: []uint8{0x43}},
{Addr: DefaultI2CAddress, W: []uint8{0x44}},
{Addr: DefaultI2CAddress, W: []uint8{0x45}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x47}},
{Addr: DefaultI2CAddress, W: []uint8{0x48}},
{Addr: DefaultI2CAddress, W: []uint8{0x49}},
{Addr: DefaultI2CAddress, W: []uint8{0x4a}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x4c}},
{Addr: DefaultI2CAddress, W: []uint8{0x4d}},
{Addr: DefaultI2CAddress, W: []uint8{0x4e}},
{Addr: DefaultI2CAddress, W: []uint8{0x4f}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x51}},
{Addr: DefaultI2CAddress, W: []uint8{0x52}},
{Addr: DefaultI2CAddress, W: []uint8{0x53}},
{Addr: DefaultI2CAddress, W: []uint8{0x54}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x94}},
{Addr: DefaultI2CAddress, W: []uint8{0x41}},
{Addr: DefaultI2CAddress, W: []uint8{0x42}},
{Addr: DefaultI2CAddress, W: []uint8{0x43}},
{Addr: DefaultI2CAddress, W: []uint8{0x44}},
{Addr: DefaultI2CAddress, W: []uint8{0x45}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x47}},
{Addr: DefaultI2CAddress, W: []uint8{0x48}},
{Addr: DefaultI2CAddress, W: []uint8{0x49}},
{Addr: DefaultI2CAddress, W: []uint8{0x4a}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x4c}},
{Addr: DefaultI2CAddress, W: []uint8{0x4d}},
{Addr: DefaultI2CAddress, W: []uint8{0x4e}},
{Addr: DefaultI2CAddress, W: []uint8{0x4f}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x51}},
{Addr: DefaultI2CAddress, W: []uint8{0x52}},
{Addr: DefaultI2CAddress, W: []uint8{0x53}},
{Addr: DefaultI2CAddress, W: []uint8{0x54}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xd4}},
{Addr: DefaultI2CAddress, W: []uint8{0x41}},
{Addr: DefaultI2CAddress, W: []uint8{0x42}},
{Addr: DefaultI2CAddress, W: []uint8{0x43}},
{Addr: DefaultI2CAddress, W: []uint8{0x44}},
{Addr: DefaultI2CAddress, W: []uint8{0x45}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x47}},
{Addr: DefaultI2CAddress, W: []uint8{0x48}},
{Addr: DefaultI2CAddress, W: []uint8{0x49}},
{Addr: DefaultI2CAddress, W: []uint8{0x4a}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x4c}},
{Addr: DefaultI2CAddress, W: []uint8{0x4d}},
{Addr: DefaultI2CAddress, W: []uint8{0x4e}},
{Addr: DefaultI2CAddress, W: []uint8{0x4f}},
{Addr: DefaultI2CAddress, W: []uint8{0x20}},
{Addr: DefaultI2CAddress, W: []uint8{0x51}},
{Addr: DefaultI2CAddress, W: []uint8{0x52}},
{Addr: DefaultI2CAddress, W: []uint8{0x53}},
{Addr: DefaultI2CAddress, W: []uint8{0x54}},
{Addr: DefaultI2CAddress, W: []uint8{0x61, 0x75, 0x74, 0x6f, 0x20, 0x73, 0x63, 0x72, 0x6f, 0x6c, 0x6c, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, 0x6e}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x41, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x20, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x80}},
{Addr: DefaultI2CAddress, W: []uint8{0x28, 0x30, 0x2c, 0x30, 0x29}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc1}},
{Addr: DefaultI2CAddress, W: []uint8{0x28, 0x31, 0x2c, 0x31, 0x29}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x96}},
{Addr: DefaultI2CAddress, W: []uint8{0x28, 0x32, 0x2c, 0x32, 0x29}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xd7}},
{Addr: DefaultI2CAddress, W: []uint8{0x28, 0x33, 0x2c, 0x33, 0x29}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc0}},
{Addr: DefaultI2CAddress, W: []uint8{0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x3a, 0x20, 0x4f, 0x66, 0x66}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc0}},
{Addr: DefaultI2CAddress, W: []uint8{0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x3a, 0x20, 0x55, 0x6e, 0x64, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x65}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xe}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc0}},
{Addr: DefaultI2CAddress, W: []uint8{0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x3a, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xd}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc0}},
{Addr: DefaultI2CAddress, W: []uint8{0x43, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x3a, 0x20, 0x42, 0x6c, 0x69, 0x6e, 0x6b}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xd}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x3e}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x14}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x14}},
{Addr: DefaultI2CAddress, W: []uint8{0x30}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x31}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x32}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x33}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x34}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x35}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x36}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x37}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x38}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x39}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x10}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x64, 0x65, 0x76, 0x20, 0x6f, 0x66, 0x66}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0x8}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x64, 0x65, 0x76, 0x20, 0x6f, 0x6e}}}
var pbBacklight = []i2ctest.IO{
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x4f, 0x66, 0x66}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2b, 0x0, 0x0, 0x0}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2b, 0xff, 0xff, 0xff}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x4f, 0x6e}}}
var pbRGBBacklight = []i2ctest.IO{
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x5b, 0x5d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74}},
{Addr: DefaultI2CAddress, W: []uint8{0x79, 0x7b, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x7d}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2b, 0xff, 0x0, 0x0}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x5b, 0x5d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74}},
{Addr: DefaultI2CAddress, W: []uint8{0x79, 0x7b, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x30, 0x7d}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2b, 0x0, 0xff, 0x0}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x42, 0x61, 0x63, 0x6b, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x5b, 0x5d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74}},
{Addr: DefaultI2CAddress, W: []uint8{0x79, 0x7b, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x7d}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2b, 0x0, 0x0, 0xff}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2b, 0xff, 0xff, 0xff}}}
var pbContrast = []i2ctest.IO{
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x73, 0x74, 0x20, 0x35}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x18, 0x5}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc0}},
{Addr: DefaultI2CAddress, W: []uint8{0x53, 0x65, 0x74, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x73, 0x74, 0x20, 0x30, 0x78, 0x38, 0x30}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x18, 0x80}},
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x18, 0x28}}}
var pbHalt = []i2ctest.IO{
{Addr: DefaultI2CAddress, W: []uint8{0x7c, 0x2d}},
{Addr: DefaultI2CAddress, W: []uint8{0xfe, 0xc}}}
func init() {
var err error
// If the environment variable is set, assume we have a live device on
// the default i2c bus and use it for testing. If the variable is not
// present, then use the playback/read values.
liveDevice = os.Getenv("SERLCD") != ""
// If EEPROM is set, then tests that write to EEPROM (display intensity /
// contrast are tested if it's a live test.
eepromTests = os.Getenv("EEPROM") != ""
if _, err = host.Init(); err != nil {
fmt.Println(err)
}
if liveDevice {
sleepDuration = 5 * time.Second
bus, err = i2creg.Open("")
if err != nil {
fmt.Println(err)
}
// Add the recorder to dump the data stream when we're using a live device.
bus = &i2ctest.Record{Bus: bus}
} else {
bus = &i2ctest.Playback{DontPanic: true}
}
}
// getDev returns a SerLCD device for testing connected to either a live
// bus, or a playback bus. playbackOps is a slice of i2ctest.IO
// operations to be used for playback mode. Ignored for live device
// testing.
func getDev(t *testing.T, playbackOps ...[]i2ctest.IO) (*Dev, error) {
if liveDevice {
if recorder, ok := bus.(*i2ctest.Record); ok {
// Clear the operations buffer.
recorder.Ops = make([]i2ctest.IO, 0, 32)
}
} else {
if len(playbackOps) == 1 {
pb := bus.(*i2ctest.Playback)
pb.Ops = playbackOps[0]
pb.Count = 0
}
}
conn := &i2c.Dev{Bus: bus, Addr: DefaultI2CAddress}
dev := NewConn(conn, 4, 20)
return dev, nil
}
// shutdown dumps the recorder values if we we're running a live device.
func shutdown(t *testing.T) {
if recorder, ok := bus.(*i2ctest.Record); ok {
t.Logf("%#v", recorder.Ops)
}
}
// This tests all functions in the TextDisplay interface.
func TestInterface(t *testing.T) {
dev, err := getDev(t, pbInterface)
defer shutdown(t)
if err != nil {
t.Fatal(err)
}
errs := displaytest.TestTextDisplay(dev, liveDevice)
for _, err := range errs {
if !errors.Is(err, display.ErrNotImplemented) {
t.Error(err)
}
}
}
// TestBacklight verifies the backlight turns off.
func TestBacklight(t *testing.T) {
if liveDevice && !eepromTests {
return
}
dev, err := getDev(t, pbBacklight)
defer shutdown(t)
if err != nil {
t.Fatal(err)
}
_ = dev.Clear()
_, err = dev.WriteString("Set Backlight Off")
if err != nil {
t.Error(err)
}
err = dev.Backlight(0)
if err != nil {
t.Error(err)
}
time.Sleep(sleepDuration)
_ = dev.Clear()
err = dev.Backlight(0xff)
if err != nil {
t.Error(err)
}
_, _ = dev.WriteString("Set Backlight On")
time.Sleep(sleepDuration)
}
// TestRGBBacklight tests the RGB Backlight works as expected
func TestRGBBacklight(t *testing.T) {
if liveDevice && !eepromTests {
return
}
dev, err := getDev(t, pbRGBBacklight)
defer shutdown(t)
if err != nil {
t.Fatal(err)
}
_ = dev.Clear()
for ix := range 3 {
w := make([]display.Intensity, 3)
w[ix] = 0xff
_, err = dev.WriteString(fmt.Sprintf("Set Backlight %#v", w))
if err != nil {
t.Error(err)
}
err = dev.RGBBacklight(w[0], w[1], w[2])
if err != nil {
t.Error(err)
}
time.Sleep(sleepDuration)
}
err = dev.RGBBacklight(0xff, 0xff, 0xff)
if err != nil {
t.Error(err)
}
}
// TestContrast() checks contrast operations.
func TestContrast(t *testing.T) {
if liveDevice && !eepromTests {
return
}
dev, err := getDev(t, pbContrast)
defer shutdown(t)
if err != nil {
t.Fatal(err)
}
_ = dev.Clear()
_, _ = dev.WriteString("Set Contrast 5")
err = dev.Contrast(5)
if err != nil {
t.Error(err)
}
_ = dev.MoveTo(dev.MinRow()+1, dev.MinCol())
time.Sleep(sleepDuration)
_, _ = dev.WriteString("Set Contrast 0x80")
time.Sleep(sleepDuration)
err = dev.Contrast(0x80)
if err != nil {
t.Error(err)
}
time.Sleep(sleepDuration)
_ = dev.Contrast(40)
}
func TestHalt(t *testing.T) {
dev, err := getDev(t, pbHalt)
defer shutdown(t)
if err != nil {
t.Fatal(err)
}
err = dev.Halt()
if err != nil {
t.Error(err)
}
}