mirror of https://github.com/periph/devices
mcp23xxx: Add GPIO Group support (#92)
* Add GPIO Group support to mcp23xxx * Add unit tests for group * Fix unit test * add file * Fix lint errorspull/94/head
parent
d5aac04cf4
commit
5bcc204c9a
@ -0,0 +1,217 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package mcp23xxx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"periph.io/x/conn/v3"
|
||||||
|
"periph.io/x/conn/v3/gpio"
|
||||||
|
"periph.io/x/conn/v3/pin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The internal structure for a group of pins.
|
||||||
|
type pinGroup struct {
|
||||||
|
dev *Dev
|
||||||
|
port int
|
||||||
|
pins []*portpin
|
||||||
|
defaultMask gpio.GPIOValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group returns a gpio.Group that is made up of the specified pins.
|
||||||
|
func (dev *Dev) Group(port int, pins []int) *gpio.Group {
|
||||||
|
grouppins := make([]*portpin, len(pins))
|
||||||
|
for ix, number := range pins {
|
||||||
|
pp, ok := dev.Pins[port][number].(*portpin)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
grouppins[ix] = pp
|
||||||
|
}
|
||||||
|
defMask := gpio.GPIOValue((1 << len(pins)) - 1)
|
||||||
|
var pgif interface{} = &pinGroup{dev: dev, port: port, pins: grouppins, defaultMask: defMask}
|
||||||
|
if gpiogroup, ok := pgif.(gpio.Group); ok {
|
||||||
|
return &gpiogroup
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pins returns the set of pin.Pin that make up that group.
|
||||||
|
func (pg *pinGroup) Pins() []pin.Pin {
|
||||||
|
pins := make([]pin.Pin, len(pg.pins))
|
||||||
|
|
||||||
|
for ix, p := range pg.pins {
|
||||||
|
pins[ix] = p
|
||||||
|
}
|
||||||
|
return pins
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the offset within the group, return the corresponding GPIO pin.
|
||||||
|
func (pg *pinGroup) ByOffset(offset int) pin.Pin {
|
||||||
|
return pg.pins[offset]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the specific name of a pin, return it. If it can't be found, nil is
|
||||||
|
// returned.
|
||||||
|
func (pg *pinGroup) ByName(name string) pin.Pin {
|
||||||
|
for _, pin := range pg.pins {
|
||||||
|
if pin.Name() == name {
|
||||||
|
return pin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the GPIO pin number, return that pin from the set.
|
||||||
|
func (pg *pinGroup) ByNumber(number int) pin.Pin {
|
||||||
|
for _, pin := range pg.pins {
|
||||||
|
if pin.Number() == number {
|
||||||
|
return pin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Out writes value to the specified pins of the device/port. If mask is 0,
|
||||||
|
// the default mask of all pins in the group is used.
|
||||||
|
func (pg *pinGroup) Out(value, mask gpio.GPIOValue) error {
|
||||||
|
if mask == 0 {
|
||||||
|
mask = pg.defaultMask
|
||||||
|
} else {
|
||||||
|
mask &= pg.defaultMask
|
||||||
|
}
|
||||||
|
value &= mask
|
||||||
|
// Convert the write value which is relative to the pins to the
|
||||||
|
// absolute value for the port.
|
||||||
|
wr := uint8(0)
|
||||||
|
wrMask := uint8(0)
|
||||||
|
for bit := range len(pg.pins) {
|
||||||
|
if (mask & (1 << bit)) > 0 {
|
||||||
|
if (value & 0x01) == 0x01 {
|
||||||
|
wr |= 1 << pg.pins[bit].Number()
|
||||||
|
}
|
||||||
|
wrMask |= 1 << pg.pins[bit].Number()
|
||||||
|
}
|
||||||
|
value = value >> 1
|
||||||
|
}
|
||||||
|
port := pg.pins[0].port
|
||||||
|
// Verify pins are set for output
|
||||||
|
outputPins, err := port.iodir.readValue(true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((outputPins ^ 0xff) & wrMask) != wrMask {
|
||||||
|
outputPins &= (wrMask ^ 0xff)
|
||||||
|
err = port.iodir.writeValue(outputPins, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the current value
|
||||||
|
currentValue, err := port.olat.readValue(true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Apply the mask to clear bits we're writing.
|
||||||
|
currentValue &= (0xff ^ wrMask)
|
||||||
|
// Or the value with the bits to modify
|
||||||
|
currentValue |= wr
|
||||||
|
// And, write the value out the port.
|
||||||
|
return port.olat.writeValue(currentValue, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads from the device and port and returns the state of the GPIO
|
||||||
|
// pins in the group. If a pin specified by mask is not configured for
|
||||||
|
// input, it is transparently re-configured.
|
||||||
|
func (pg *pinGroup) Read(mask gpio.GPIOValue) (result gpio.GPIOValue, err error) {
|
||||||
|
if mask == 0 {
|
||||||
|
mask = pg.defaultMask
|
||||||
|
} else {
|
||||||
|
mask &= pg.defaultMask
|
||||||
|
}
|
||||||
|
// Compute the read mask
|
||||||
|
rmask := uint8(0)
|
||||||
|
for bit := range 8 {
|
||||||
|
if (mask & (1 << bit)) > 0 {
|
||||||
|
rmask |= (1 << pg.pins[bit].Number())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make sure the direction for the pins involved in this write read is
|
||||||
|
// Input.
|
||||||
|
port := pg.pins[0].port
|
||||||
|
currentIn, err := port.iodir.readValue(true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// We need to make some pins Input. Write the value to the iodir register.
|
||||||
|
if (currentIn & rmask) != rmask {
|
||||||
|
err = port.iodir.writeValue(currentIn|rmask, false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now, perform the read itself.
|
||||||
|
v, err := port.gpio.readValue(false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Now convert the set pins into the Group value
|
||||||
|
for ix, pin := range pg.pins {
|
||||||
|
if (v & (1 << pin.Number())) > 0 {
|
||||||
|
result |= 1 << ix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForEdge listens for a GPIO pin change event. The MCP23XXXX devices
|
||||||
|
// can't directly signal an edge event. To do this, you must call
|
||||||
|
// Dev.SetEdgePin() with a HOST GPIO pin configured for falling edge
|
||||||
|
// detection. That pin should be connected to the MCP23XXX INT pin. When
|
||||||
|
// a falling edge is detected on the supplied host GPIO pin, the code
|
||||||
|
// will return the GPIO Pin number on the device that changed.
|
||||||
|
//
|
||||||
|
// Note that the MCP23XXX devices only detect change. You can't configure
|
||||||
|
// falling or rising edge. Consequently, the returned edge will always be
|
||||||
|
// gpio.NoEdge.
|
||||||
|
//
|
||||||
|
// For a change event to be detected, the pin must be configured for input.
|
||||||
|
// This function will NOT set pins for input. Additionally, the calling
|
||||||
|
// code must set the INTCON register appropriately. Refer to the datasheet.
|
||||||
|
//
|
||||||
|
// In the event that the changed pin is NOT part of the io group, the
|
||||||
|
// triggering pin number will be returned, along with the error
|
||||||
|
// ErrPinNotInGroup
|
||||||
|
func (pg *pinGroup) WaitForEdge(timeout time.Duration) (number int, edge gpio.Edge, err error) {
|
||||||
|
return -1, gpio.NoEdge, gpio.ErrGroupFeatureNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// Halt() interrupts a pending WaitForEdge() call if one is in process.
|
||||||
|
func (pg *pinGroup) Halt() error {
|
||||||
|
if pg.dev.edgePin != nil {
|
||||||
|
var ifpin interface{} = pg.dev.edgePin
|
||||||
|
if r, ok := ifpin.(conn.Resource); ok {
|
||||||
|
return r.Halt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: I think we want to call Dev.Halt()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the device variant name and configured pins for the group.
|
||||||
|
func (pg *pinGroup) String() string {
|
||||||
|
s := fmt.Sprintf("%s - [ ", pg.dev)
|
||||||
|
for ix := range len(pg.pins) {
|
||||||
|
s += fmt.Sprintf("%d ", pg.pins[ix].Number())
|
||||||
|
}
|
||||||
|
s += "]"
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ gpio.Group = &pinGroup{}
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package mcp23xxx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"periph.io/x/conn/v3/gpio"
|
||||||
|
"periph.io/x/conn/v3/i2c/i2ctest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
liveTest = false
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGroup(t *testing.T) {
|
||||||
|
bus := i2ctest.Playback{Ops: recordingData["TestGroup"]}
|
||||||
|
extender, err := NewI2C(&bus, MCP23008, 0x20)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for portnum, port := range extender.Pins {
|
||||||
|
for _, pin := range port {
|
||||||
|
t.Logf("Port: %d Pin: %d %s", portnum, pin.Number(), pin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The test fixture has an led on pin 0, and also wires pin 0 -> pin 4.
|
||||||
|
// If I don't set pin 4 for input, then it breaks the LED blinking.
|
||||||
|
// It's not important to the test, but it's nice to have a visual indicator.
|
||||||
|
reader, _ := interface{}(extender.Pins[0][4]).(gpio.PinIn)
|
||||||
|
_ = reader.In(gpio.PullNoChange, gpio.NoEdge)
|
||||||
|
var ifpin interface{} = extender.Pins[0][0]
|
||||||
|
if writer, ok := ifpin.(gpio.PinOut); ok {
|
||||||
|
l := gpio.High
|
||||||
|
for range 20 {
|
||||||
|
writer.Out(l)
|
||||||
|
l = !l
|
||||||
|
if liveTest {
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Error("pin[0] not converted to gpio.PinOut!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestReadWrite exercises the group Out()/Read() functions. It's expected
|
||||||
|
// that pin 0 of MCP23xxx port 0 is connected to pin 4 of port 0, pin 1
|
||||||
|
// is connected to pin 5, etc...
|
||||||
|
func TestReadWrite(t *testing.T) {
|
||||||
|
bus := i2ctest.Playback{Ops: recordingData["TestReadWrite"]}
|
||||||
|
extender, err := NewI2C(&bus, MCP23008, 0x20)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defMask := gpio.GPIOValue(0xf)
|
||||||
|
gOut := *extender.Group(0, []int{0, 1, 2, 3})
|
||||||
|
if gOut == nil {
|
||||||
|
t.Error("gOut is nil!")
|
||||||
|
}
|
||||||
|
gRead := *extender.Group(0, []int{4, 5, 6, 7})
|
||||||
|
if gRead == nil {
|
||||||
|
t.Error("gRead is nil!")
|
||||||
|
}
|
||||||
|
// Turn off the GPIOs
|
||||||
|
defer gOut.Out(0, 0)
|
||||||
|
defer gRead.Out(0, 0)
|
||||||
|
|
||||||
|
for i := range 2 {
|
||||||
|
if i == 1 {
|
||||||
|
/* Now invert it. */
|
||||||
|
x := gRead
|
||||||
|
gRead = gOut
|
||||||
|
gOut = x
|
||||||
|
}
|
||||||
|
for i := range gpio.GPIOValue(16) {
|
||||||
|
err := gOut.Out(i, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if liveTest {
|
||||||
|
time.Sleep(time.Millisecond)
|
||||||
|
}
|
||||||
|
r, err := gRead.Read(defMask)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if r != i {
|
||||||
|
t.Errorf("Error reading/writing GPIO Group(). Wrote 0x%x Read 0x%x", i, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For this test, write to the pins individually, and then
|
||||||
|
// confirm read on the other set works as expected.
|
||||||
|
gRead = gOut
|
||||||
|
t.Log(gRead)
|
||||||
|
pinset := extender.Pins[0][:4]
|
||||||
|
for i := range gpio.GPIOValue(16) {
|
||||||
|
wvalue := i
|
||||||
|
for bit := range 4 {
|
||||||
|
if (wvalue & (1 << bit)) == (1 << bit) {
|
||||||
|
pinset[bit].Out(gpio.High)
|
||||||
|
} else {
|
||||||
|
pinset[bit].Out(gpio.Low)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r, err := gRead.Read(0)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if r != i {
|
||||||
|
t.Errorf("Error writing GPIO pins and reading back result. Read 0x%x Expected 0x%x", r, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,159 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package mcp23xxx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"periph.io/x/conn/v3/i2c/i2ctest"
|
||||||
|
)
|
||||||
|
|
||||||
|
var recordingData = map[string][]i2ctest.IO{
|
||||||
|
"TestGroup": {
|
||||||
|
{Addr: 0x20, W: []uint8{0x0}, R: []uint8{0x0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0x10}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa}, R: []uint8{0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x40}}},
|
||||||
|
"TestReadWrite": {
|
||||||
|
{Addr: 0x20, W: []uint8{0x0}, R: []uint8{0x10}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa}, R: []uint8{0x40}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0xf0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x41}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x11}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x42}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x22}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x43}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x33}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x44}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x44}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x45}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x55}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x46}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x66}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x47}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x77}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x48}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x88}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x49}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x99}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x4a}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xaa}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x4b}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xbb}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x4c}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xcc}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x4d}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xdd}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x4e}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xee}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x4f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xff}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0x0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0xf}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x1f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x11}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x2f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x22}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x3f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x33}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x4f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x44}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x5f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x55}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x6f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x66}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x7f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x77}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x8f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x88}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x9f}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x99}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xaf}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xaa}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xbf}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xbb}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xcf}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xcc}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xdf}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xdd}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xef}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xee}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xff}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xff}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0xe}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfe}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0xc}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfc}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0x8}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf8}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0x0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0xf0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf1}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x11}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf2}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x22}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf3}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x33}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf2}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf4}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x44}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf5}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x55}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf4}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf6}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x66}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf7}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x77}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf6}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf4}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf8}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x88}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf9}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0x99}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf8}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfa}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xaa}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfb}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xbb}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfa}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf8}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfc}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xcc}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfd}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xdd}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfc}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xfe}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xee}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xff}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x9}, R: []uint8{0xff}},
|
||||||
|
{Addr: 0x20, W: []uint8{0x0, 0x0}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0xf}},
|
||||||
|
{Addr: 0x20, W: []uint8{0xa, 0x0}}},
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue