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.
217 lines
5.0 KiB
Go
217 lines
5.0 KiB
Go
// Copyright 2025 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.
|
|
//
|
|
// This test assumes you have a PCF8575 and that the data pins are jumpered
|
|
//
|
|
// 0 => 8
|
|
// 1 => 9
|
|
// ...
|
|
// 7 => 15
|
|
|
|
package pcf857x
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"periph.io/x/conn/v3/gpio"
|
|
"periph.io/x/conn/v3/gpio/gpioreg"
|
|
"periph.io/x/conn/v3/i2c/i2ctest"
|
|
)
|
|
|
|
func getDev(recordingName string, t *testing.T) (*Dev, error) {
|
|
// Create a new I2C IO extender
|
|
bus := i2ctest.Playback{Ops: recordingData[recordingName]}
|
|
extender, err := New(&bus, DefaultAddress, PCF8575)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
return extender, err
|
|
}
|
|
|
|
// Test basic dev and pin functions.
|
|
func TestBasic(t *testing.T) {
|
|
dev, err := getDev(t.Name(), t)
|
|
if err != nil {
|
|
return
|
|
}
|
|
t.Logf("dev=%#v", dev)
|
|
pin := dev.Pins[1]
|
|
t.Logf("pin=%#v", pin)
|
|
|
|
s := dev.String()
|
|
if len(s) == 0 {
|
|
t.Error("String() failure")
|
|
} //
|
|
|
|
if len(dev.Pins) != 16 {
|
|
t.Errorf("expected 16 GPIO pins. Found %d", len(dev.Pins))
|
|
}
|
|
|
|
e := pin.PWM(10, 10)
|
|
if !errors.Is(e, ErrNotImplmented) {
|
|
t.Errorf("PWM() expected ErrNotImplemented. Received %#v", e)
|
|
}
|
|
if pin.Halt() != nil {
|
|
t.Error("expected nil on pin.Halt()")
|
|
}
|
|
|
|
if pin.Name() != pin.String() {
|
|
t.Error("pin.Name()!=pin.String()")
|
|
}
|
|
|
|
if !strings.HasPrefix(pin.Name(), dev.String()) {
|
|
t.Errorf("Expected pin.Name()=%s to start with dev.String()=%s", pin.Name(), dev.String())
|
|
}
|
|
|
|
err = dev.Halt()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// Test that the pins are registered in gpioreg as expected.
|
|
func TestGPIOReg(t *testing.T) {
|
|
dev, err := getDev(t.Name(), t)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for ix := range dev.width {
|
|
p := dev.Pins[ix]
|
|
if p.Number() != ix {
|
|
t.Errorf("pin.Number() does not match ordinal position %d! Found %d", ix, p.Number())
|
|
}
|
|
pReg := gpioreg.ByName(p.Name())
|
|
if pReg == nil {
|
|
t.Errorf("pin %s not found in gpioreg", p.Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
// This test goes through the pins from 0-7, and writes to them and then reads
|
|
// the value on pin+8 and verifies it's correct. Then, it reverses direction and
|
|
// writes to pin[8] and reads from pin[0].
|
|
func TestPinsSequentially(t *testing.T) {
|
|
dev, err := getDev(t.Name(), t)
|
|
if err != nil {
|
|
return
|
|
}
|
|
limit := dev.width >> 1
|
|
for ixOuter := range limit {
|
|
// Iterate over the lower 8 pins
|
|
for ixInner := range limit {
|
|
// Sequentially, set each pin to High if it's not the value of ix
|
|
p := dev.Pins[ixInner]
|
|
pRead := dev.Pins[ixInner+limit]
|
|
for direction := range 2 {
|
|
writeLevel := gpio.Level(ixInner != ixOuter)
|
|
err = p.Out(writeLevel)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
readVal := pRead.Read()
|
|
if readVal != writeLevel {
|
|
t.Errorf("wrote %t to pin[%d]. Expected same on pin[%d], found %t",
|
|
writeLevel,
|
|
p.Number(),
|
|
pRead.Number(),
|
|
readVal)
|
|
}
|
|
if direction == 0 {
|
|
// swap the direction so we're now going pin[8] => pin[0] and stay in
|
|
// the loop to repeat the test.
|
|
x := pRead
|
|
pRead = p
|
|
p = x
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This tests the group functionality.
|
|
func TestGroup(t *testing.T) {
|
|
dev, err := getDev(t.Name(), t)
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer func() { _ = dev.Halt() }()
|
|
|
|
set1 := make([]int, dev.width>>1)
|
|
set2 := make([]int, dev.width>>1)
|
|
for ix := range len(set1) {
|
|
set1[ix] = ix
|
|
set2[ix] = ix + len(set1)
|
|
}
|
|
gr1, err := dev.Group(set1...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
gr2, err := dev.Group(set2...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
// Test the basic group functionality. Note that for group1, pinOffset==pin.Number, but
|
|
// for group2, pinOffset!=pin.Number
|
|
grTest := gr1
|
|
for range 2 {
|
|
for pinNumber, pin := range grTest.Pins() {
|
|
x := grTest.ByNumber(pin.Number())
|
|
if x == nil {
|
|
t.Errorf("group.ByNumber() returned nil for pin %d", pin.Number())
|
|
}
|
|
x = grTest.ByOffset(pinNumber)
|
|
if x == nil {
|
|
t.Errorf("group.ByOffset returned nil for pin number %d", pinNumber)
|
|
} else {
|
|
if x.Number() != pin.Number() {
|
|
t.Errorf("group.ByOffset() didn't return the expected pin. Expected %d, found %d", pin.Number(), x.Number())
|
|
}
|
|
}
|
|
x = grTest.ByName(pin.Name())
|
|
if x == nil || x.Name() != pin.Name() {
|
|
t.Error("group.ByName() didn't find a pin or returned the wrong pin!")
|
|
}
|
|
}
|
|
grTest = gr2
|
|
}
|
|
if len(gr1.String()) == 0 {
|
|
t.Error("group.String() didn't return a value")
|
|
}
|
|
// Test the read/write functionality.
|
|
limit := (1 << len(set1))
|
|
var read gpio.GPIOValue
|
|
for groupNumber := range 2 {
|
|
for val := range limit {
|
|
err = gr1.Out(gpio.GPIOValue(val), 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
read, err = gr2.Read(0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if read != gpio.GPIOValue(val) {
|
|
t.Errorf("Error writing/reading groups. Wrote %d on write group %s, read %d on read group%s", val, gr1, read, gr2)
|
|
}
|
|
}
|
|
if groupNumber == 0 {
|
|
x := gr1
|
|
gr1 = gr2
|
|
gr2 = x
|
|
}
|
|
}
|
|
err = gr1.Halt()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = gr2.Halt()
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|