mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-12 19:03:42 +00:00
98 lines
2.4 KiB
Go
98 lines
2.4 KiB
Go
package mcp23017
|
|
|
|
import (
|
|
qt "github.com/frankban/quicktest"
|
|
)
|
|
|
|
// fakeBus implements the I2C interface in memory for testing.
|
|
type fakeBus struct {
|
|
c *qt.C
|
|
devs []*fakeDev
|
|
}
|
|
|
|
// newBus returns a fakeBus instance that uses c to flag errors
|
|
// if they happen. After creating a fakeBus instance, add devices
|
|
// to it with addDevice before using the interface.
|
|
func newBus(c *qt.C) *fakeBus {
|
|
return &fakeBus{
|
|
c: c,
|
|
}
|
|
}
|
|
|
|
// fakeDev represents a device on the bus.
|
|
type fakeDev struct {
|
|
c *qt.C
|
|
addr uint8
|
|
// Registers holds the device registers. It can be inspected
|
|
// or changed as desired for testing.
|
|
Registers [registerCount]uint8
|
|
// If Err is non-nil, it will be returned as the error from the
|
|
// I2C methods.
|
|
Err error
|
|
}
|
|
|
|
// addDevice adds a new device at the given address.
|
|
func (bus *fakeBus) addDevice(addr uint8) *fakeDev {
|
|
dev := &fakeDev{
|
|
c: bus.c,
|
|
addr: addr,
|
|
Registers: [registerCount]uint8{
|
|
// IODIRA and IODIRB are all ones by default.
|
|
rIODIR: 0xff,
|
|
rIODIR | portB: 0xff,
|
|
},
|
|
}
|
|
bus.devs = append(bus.devs, dev)
|
|
return dev
|
|
}
|
|
|
|
// ReadRegister implements I2C.ReadRegister.
|
|
func (bus *fakeBus) ReadRegister(addr uint8, r uint8, buf []byte) error {
|
|
return bus.findDev(addr).readRegister(r, buf)
|
|
}
|
|
|
|
// WriteRegister implements I2C.WriteRegister.
|
|
func (bus *fakeBus) WriteRegister(addr uint8, r uint8, buf []byte) error {
|
|
return bus.findDev(addr).writeRegister(r, buf)
|
|
}
|
|
|
|
func (d *fakeDev) readRegister(r uint8, buf []byte) error {
|
|
if d.Err != nil {
|
|
return d.Err
|
|
}
|
|
d.assertRegisterRange(r, buf)
|
|
copy(buf, d.Registers[r:])
|
|
return nil
|
|
}
|
|
|
|
func (d *fakeDev) writeRegister(r uint8, buf []byte) error {
|
|
if d.Err != nil {
|
|
return d.Err
|
|
}
|
|
d.assertRegisterRange(r, buf)
|
|
copy(d.Registers[r:], buf)
|
|
return nil
|
|
}
|
|
|
|
// assertRegisterRange asserts that reading or writing the given
|
|
// register and subsequent registers is in range of the available registers.
|
|
func (d *fakeDev) assertRegisterRange(r uint8, buf []byte) {
|
|
if int(r) >= len(d.Registers) {
|
|
d.c.Fatalf("register read/write [%#x, %#x] start out of range", r, int(r)+len(buf))
|
|
}
|
|
if int(r)+len(buf) > len(d.Registers) {
|
|
d.c.Fatalf("register read/write [%#x, %#x] end out of range", r, int(r)+len(buf))
|
|
}
|
|
}
|
|
|
|
// findDev returns the device with the given address.
|
|
func (bus *fakeBus) findDev(addr uint8) *fakeDev {
|
|
for _, dev := range bus.devs {
|
|
if dev.addr == addr {
|
|
return dev
|
|
}
|
|
}
|
|
bus.c.Fatalf("invalid device addr %#x passed to i2c bus", addr)
|
|
panic("unreachable")
|
|
}
|