mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-27 13:48:56 +08:00
BUGFIX: tests with sysfs mocks, ReadBlockData, WriteBlockData
This commit is contained in:
commit
8cadea2a6d
6
Makefile
6
Makefile
@ -13,16 +13,18 @@ EXAMPLES := $(EXAMPLES_NO_GOCV)
|
||||
including_except := $(shell go list ./... | grep -v platforms/opencv)
|
||||
|
||||
# Run tests on nearly all directories without test cache
|
||||
# TODO: set back to parallel running (remove "-p 1"), when issue #878 is fixed
|
||||
test:
|
||||
go test -count=1 -v $(including_except)
|
||||
go test -p 1 -count=1 -v $(including_except)
|
||||
|
||||
# Run tests with race detection
|
||||
test_race:
|
||||
go test -race $(including_except)
|
||||
|
||||
# Test, generate and show coverage in browser
|
||||
# TODO: set back to parallel running (remove "-p 1"), when issue #878 is fixed
|
||||
test_cover:
|
||||
go test -v $(including_except) -coverprofile=coverage.txt ; \
|
||||
go test -p 1 -v $(including_except) -coverprofile=coverage.txt ; \
|
||||
go tool cover -html=coverage.txt ; \
|
||||
|
||||
robeaux:
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
"gobot.io/x/gobot/sysfs"
|
||||
)
|
||||
|
||||
const dev = "/dev/i2c-1"
|
||||
|
||||
func syscallImpl(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
if (trap == syscall.SYS_IOCTL) && (a2 == sysfs.I2C_FUNCS) {
|
||||
var funcPtr *uint64 = (*uint64)(unsafe.Pointer(a3))
|
||||
@ -31,38 +33,37 @@ func syscallImplFail(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errn
|
||||
}
|
||||
|
||||
func initI2CDevice() I2cDevice {
|
||||
fs := sysfs.NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
fs := sysfs.NewMockFilesystem([]string{dev})
|
||||
sysfs.SetFilesystem(fs)
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{Impl: syscallImpl})
|
||||
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{
|
||||
Impl: syscallImpl,
|
||||
})
|
||||
i, _ := sysfs.NewI2cDevice("/dev/i2c-1")
|
||||
i, _ := sysfs.NewI2cDevice(dev)
|
||||
return i
|
||||
}
|
||||
|
||||
func initI2CDeviceAddressError() I2cDevice {
|
||||
fs := sysfs.NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
func cleanupI2CDevice() {
|
||||
sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
}
|
||||
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{
|
||||
Impl: syscallImplFail,
|
||||
})
|
||||
i, _ := sysfs.NewI2cDevice("/dev/i2c-1")
|
||||
func initI2CDeviceAddressError() I2cDevice {
|
||||
fs := sysfs.NewMockFilesystem([]string{dev})
|
||||
sysfs.SetFilesystem(fs)
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{Impl: syscallImplFail})
|
||||
|
||||
i, _ := sysfs.NewI2cDevice(dev)
|
||||
return i
|
||||
}
|
||||
|
||||
func TestI2CAddress(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x66)
|
||||
defer cleanupI2CDevice()
|
||||
gobottest.Assert(t, c.address, 0x66)
|
||||
}
|
||||
|
||||
func TestI2CClose(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
gobottest.Assert(t, c.Close(), nil)
|
||||
}
|
||||
|
||||
@ -74,102 +75,119 @@ func TestI2CRead(t *testing.T) {
|
||||
|
||||
func TestI2CReadAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
_, err := c.Read([]byte{})
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CWrite(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
i, _ := c.Write([]byte{0x01})
|
||||
gobottest.Assert(t, i, 1)
|
||||
}
|
||||
|
||||
func TestI2CWriteAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
_, err := c.Write([]byte{0x01})
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CReadByte(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
v, _ := c.ReadByte()
|
||||
gobottest.Assert(t, v, uint8(0))
|
||||
gobottest.Assert(t, v, uint8(0xFC))
|
||||
}
|
||||
|
||||
func TestI2CReadByteAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
_, err := c.ReadByte()
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CReadByteData(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
v, _ := c.ReadByteData(0x01)
|
||||
gobottest.Assert(t, v, uint8(0))
|
||||
gobottest.Assert(t, v, uint8(0xFD))
|
||||
}
|
||||
|
||||
func TestI2CReadByteDataAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
_, err := c.ReadByteData(0x01)
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CReadWordData(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
v, _ := c.ReadWordData(0x01)
|
||||
gobottest.Assert(t, v, uint16(0))
|
||||
gobottest.Assert(t, v, uint16(0xFFFE))
|
||||
}
|
||||
|
||||
func TestI2CReadWordDataAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
_, err := c.ReadWordData(0x01)
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CWriteByte(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteByte(0x01)
|
||||
gobottest.Assert(t, err, nil)
|
||||
}
|
||||
|
||||
func TestI2CWriteByteAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteByte(0x01)
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CWriteByteData(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteByteData(0x01, 0x01)
|
||||
gobottest.Assert(t, err, nil)
|
||||
}
|
||||
|
||||
func TestI2CWriteByteDataAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteByteData(0x01, 0x01)
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CWriteWordData(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteWordData(0x01, 0x01)
|
||||
gobottest.Assert(t, err, nil)
|
||||
}
|
||||
|
||||
func TestI2CWriteWordDataAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteWordData(0x01, 0x01)
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestI2CWriteBlockData(t *testing.T) {
|
||||
c := NewConnection(initI2CDevice(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteBlockData(0x01, []byte{0x01, 0x02})
|
||||
gobottest.Assert(t, err, nil)
|
||||
}
|
||||
|
||||
func TestI2CWriteBlockDataAddressError(t *testing.T) {
|
||||
c := NewConnection(initI2CDeviceAddressError(), 0x06)
|
||||
defer cleanupI2CDevice()
|
||||
err := c.WriteBlockData(0x01, []byte{0x01, 0x02})
|
||||
gobottest.Assert(t, err, errors.New("Setting address failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package i2c
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gobot.io/x/gobot"
|
||||
)
|
||||
@ -85,7 +87,15 @@ func (d *Driver) Halt() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write implements a simple write mechanism to the given register of an i2c device.
|
||||
// Write writes one byte to the i2c device.
|
||||
func (d *Driver) WriteByte(val byte) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
return d.connection.WriteByte(val)
|
||||
}
|
||||
|
||||
// Write implements a simple write mechanism, starting from the given register of an i2c device.
|
||||
func (d *Driver) Write(pin string, val int) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
@ -95,10 +105,77 @@ func (d *Driver) Write(pin string, val int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: create buffer from size
|
||||
// currently only one byte value is supported
|
||||
b := []byte{uint8(val)}
|
||||
return d.connection.WriteBlockData(uint8(register), b)
|
||||
if val > 0xFFFF {
|
||||
buf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(buf, uint32(val))
|
||||
return d.connection.WriteBlockData(register, buf)
|
||||
}
|
||||
if val > 0xFF {
|
||||
return d.connection.WriteWordData(register, uint16(val))
|
||||
}
|
||||
return d.connection.WriteByteData(register, uint8(val))
|
||||
}
|
||||
|
||||
// WriteByteData writes the given byte value to the given register of an i2c device.
|
||||
func (d *Driver) WriteByteData(pin string, val byte) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.connection.WriteByteData(register, val)
|
||||
}
|
||||
|
||||
// WriteWordData writes the given 16 bit value to the given register of an i2c device.
|
||||
func (d *Driver) WriteWordData(pin string, val uint16) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.connection.WriteWordData(register, val)
|
||||
}
|
||||
|
||||
// WriteBlockData writes the given buffer to the given register of an i2c device.
|
||||
func (d *Driver) WriteBlockData(pin string, data []byte) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.connection.WriteBlockData(uint8(register), data)
|
||||
}
|
||||
|
||||
// WriteData writes the given buffer to the given register of an i2c device.
|
||||
// It uses plain write to prevent WriteBlockData(), which is sometimes not supported by adaptor.
|
||||
func (d *Driver) WriteData(pin string, data []byte) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := make([]byte, len(data)+1)
|
||||
copy(buf[1:], data)
|
||||
buf[0] = register
|
||||
|
||||
cnt, err := d.connection.Write(buf)
|
||||
if cnt != len(buf) {
|
||||
return fmt.Errorf("written count (%d) differ from expected (%d)", cnt, len(buf))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Read implements a simple read mechanism from the given register of an i2c device.
|
||||
@ -111,14 +188,88 @@ func (d *Driver) Read(pin string) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// TODO: create buffer from size
|
||||
// currently only one byte value is supported
|
||||
b := []byte{0}
|
||||
if err := d.connection.ReadBlockData(register, b); err != nil {
|
||||
val, err := d.connection.ReadByteData(register)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(b[0]), nil
|
||||
return int(val), nil
|
||||
}
|
||||
|
||||
// ReadByte reads a byte from the current register of an i2c device.
|
||||
func (d *Driver) ReadByte() (byte, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
return d.connection.ReadByte()
|
||||
}
|
||||
|
||||
// ReadByteData reads a byte from the given register of an i2c device.
|
||||
func (d *Driver) ReadByteData(pin string) (byte, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return d.connection.ReadByteData(register)
|
||||
}
|
||||
|
||||
// ReadWordData reads a 16 bit value starting from the given register of an i2c device.
|
||||
func (d *Driver) ReadWordData(pin string) (uint16, error) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return d.connection.ReadWordData(register)
|
||||
}
|
||||
|
||||
// ReadBlockData fills the given buffer with reads starting from the given register of an i2c device.
|
||||
func (d *Driver) ReadBlockData(pin string, data []byte) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.connection.ReadBlockData(register, data)
|
||||
}
|
||||
|
||||
// ReadBlockData fills the given buffer with reads from the given register of an i2c device.
|
||||
// It uses plain read to prevent ReadBlockData(), which is sometimes not supported by adaptor.
|
||||
func (d *Driver) ReadData(pin string, data []byte) error {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
|
||||
register, err := driverParseRegister(pin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.connection.WriteByte(register); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write process needs some time, so wait at least 5ms before read a value
|
||||
// when decreasing to much, the check below will fail
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
n, err := d.connection.Read(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(data) {
|
||||
return fmt.Errorf("Read %v bytes from device by sysfs, expected %v", n, len(data))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func driverParseRegister(pin string) (uint8, error) {
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
// Wiring
|
||||
// PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND)
|
||||
// I2C1 Tinkerboard: 3 (SDA), 5 (SCL)
|
||||
// PCF8583 DIP package: 1 (OSCI, 50Hz), 2 (OSCO, nc), 3 (A0 - GND), 4 (VSS, +3.3V), 5 (SDA), 6 (SCL), 7 (/INT, nc), 8 (VDD, GND)
|
||||
// PCF8583 DIP package: 1 (OSCI, 50Hz), 2 (OSCO, nc), 3 (A0 - GND), 4 (VSS, GND), 5 (SDA), 6 (SCL), 7 (/INT, nc), 8 (VDD, +3.3V)
|
||||
func main() {
|
||||
board := tinkerboard.NewAdaptor()
|
||||
pcf := i2c.NewPCF8583Driver(board, i2c.WithBus(1), i2c.WithPCF8583Mode(i2c.PCF8583CtrlModeClock50))
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
// Wiring
|
||||
// PWR Tinkerboard: 1 (+3.3V, VCC), 6, 9, 14, 20 (GND)
|
||||
// I2C1 Tinkerboard: 3 (SDA), 5 (SCL)
|
||||
// PCF8583 DIP package: 1 (OSCI, event), 2 (OSCO, nc), 3 (A0 - GND), 4 (VSS, +3.3V), 5 (SDA), 6 (SCL), 7 (/INT, nc), 8 (VDD, GND)
|
||||
// PCF8583 DIP package: 1 (OSCI, event), 2 (OSCO, nc), 3 (A0 - GND), 4 (VSS, GND), 5 (SDA), 6 (SCL), 7 (/INT, nc), 8 (VDD, +3.3V)
|
||||
// Note: event can be created by e.g. an debounced button
|
||||
func main() {
|
||||
board := tinkerboard.NewAdaptor()
|
||||
|
@ -82,6 +82,7 @@ func TestBeagleboneAdaptor(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a, _ := initBBBTestAdaptor()
|
||||
|
||||
@ -170,6 +171,7 @@ func TestBeagleboneAdaptor(t *testing.T) {
|
||||
|
||||
// I2c
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 2)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -205,6 +207,7 @@ func TestBeagleboneAnalogReadFileError(t *testing.T) {
|
||||
"/sys/devices/platform/whatever",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a, _ := initBBBTestAdaptor()
|
||||
|
||||
@ -219,6 +222,7 @@ func TestBeagleboneDigitalPinDirectionFileError(t *testing.T) {
|
||||
"/sys/devices/platform/ocp/ocp:P9_12_pinmux/state",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a, _ := initBBBTestAdaptor()
|
||||
|
||||
@ -237,6 +241,7 @@ func TestBeagleboneDigitalPinFinalizeFileError(t *testing.T) {
|
||||
"/sys/devices/platform/ocp/ocp:P9_12_pinmux/state",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a, _ := initBBBTestAdaptor()
|
||||
|
||||
|
@ -40,6 +40,7 @@ func initTestChipAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
|
||||
return a, fs
|
||||
}
|
||||
|
||||
@ -64,6 +65,10 @@ func initTestChipProAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
|
||||
return a, fs
|
||||
}
|
||||
|
||||
func cleanTestChipAdaptor() {
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
}
|
||||
|
||||
func TestChipAdaptorName(t *testing.T) {
|
||||
a := NewAdaptor()
|
||||
gobottest.Assert(t, strings.HasPrefix(a.Name(), "CHIP"), true)
|
||||
@ -81,6 +86,7 @@ func TestChipAdaptorBoard(t *testing.T) {
|
||||
|
||||
func TestAdaptorFinalizeErrorAfterGPIO(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.DigitalWrite("CSID7", 1), nil)
|
||||
|
||||
@ -92,6 +98,7 @@ func TestAdaptorFinalizeErrorAfterGPIO(t *testing.T) {
|
||||
|
||||
func TestAdaptorFinalizeErrorAfterPWM(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.PwmWrite("PWM0", 100), nil)
|
||||
|
||||
@ -103,6 +110,7 @@ func TestAdaptorFinalizeErrorAfterPWM(t *testing.T) {
|
||||
|
||||
func TestChipAdaptorDigitalIO(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
a.Connect()
|
||||
|
||||
a.DigitalWrite("CSID7", 1)
|
||||
@ -118,6 +126,7 @@ func TestChipAdaptorDigitalIO(t *testing.T) {
|
||||
|
||||
func TestChipProAdaptorDigitalIO(t *testing.T) {
|
||||
a, fs := initTestChipProAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
a.Connect()
|
||||
|
||||
a.DigitalWrite("CSID7", 1)
|
||||
@ -133,6 +142,7 @@ func TestChipProAdaptorDigitalIO(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
err := a.DigitalWrite("CSID7", 1)
|
||||
@ -141,6 +151,7 @@ func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalReadWriteError(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
_, err := a.DigitalRead("CSID7")
|
||||
@ -156,6 +167,7 @@ func TestChipAdaptorI2c(t *testing.T) {
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 1)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -170,6 +182,7 @@ func TestChipAdaptorI2c(t *testing.T) {
|
||||
|
||||
func TestChipAdaptorInvalidPWMPin(t *testing.T) {
|
||||
a, _ := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
a.Connect()
|
||||
|
||||
err := a.PwmWrite("LCD-D2", 42)
|
||||
@ -181,6 +194,7 @@ func TestChipAdaptorInvalidPWMPin(t *testing.T) {
|
||||
|
||||
func TestChipAdaptorPWM(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
a.Connect()
|
||||
|
||||
err := a.PwmWrite("PWM0", 100)
|
||||
@ -205,6 +219,7 @@ func TestChipAdaptorPWM(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwmWriteError(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
err := a.PwmWrite("PWM0", 100)
|
||||
@ -213,6 +228,7 @@ func TestAdaptorPwmWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwmReadError(t *testing.T) {
|
||||
a, fs := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
fs.WithReadError = true
|
||||
|
||||
err := a.PwmWrite("PWM0", 100)
|
||||
@ -221,11 +237,13 @@ func TestAdaptorPwmReadError(t *testing.T) {
|
||||
|
||||
func TestChipDefaultBus(t *testing.T) {
|
||||
a, _ := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 1)
|
||||
}
|
||||
|
||||
func TestChipGetConnectionInvalidBus(t *testing.T) {
|
||||
a, _ := initTestChipAdaptor()
|
||||
defer cleanTestChipAdaptor()
|
||||
_, err := a.GetConnection(0x01, 99)
|
||||
gobottest.Assert(t, err, errors.New("Bus number 99 out of range"))
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ func TestDragonBoardAdaptorDigitalIO(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
_ = a.DigitalWrite("GPIO_B", 1)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio12/value"].Contents, "1")
|
||||
@ -63,7 +64,9 @@ func TestDragonBoardAdaptorI2c(t *testing.T) {
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 1)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -99,6 +102,7 @@ func TestAdaptorFinalizeErrorAfterGPIO(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.DigitalWrite("GPIO_B", 1), nil)
|
||||
|
@ -102,8 +102,13 @@ func initTestAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
|
||||
return a, fs
|
||||
}
|
||||
|
||||
func cleanTestAdaptor() {
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
}
|
||||
|
||||
func TestEdisonAdaptorName(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
gobottest.Assert(t, strings.HasPrefix(a.Name(), "Edison"), true)
|
||||
a.SetName("NewName")
|
||||
gobottest.Assert(t, a.Name(), "NewName")
|
||||
@ -111,6 +116,7 @@ func TestEdisonAdaptorName(t *testing.T) {
|
||||
|
||||
func TestAdaptorConnect(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 6)
|
||||
gobottest.Assert(t, a.Board(), "arduino")
|
||||
@ -120,6 +126,7 @@ func TestAdaptorConnect(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoSetupFail263(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
delete(fs.Files, "/sys/class/gpio/gpio263/direction")
|
||||
|
||||
err := a.arduinoSetup()
|
||||
@ -128,6 +135,7 @@ func TestAdaptorArduinoSetupFail263(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoSetupFail240(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
delete(fs.Files, "/sys/class/gpio/gpio240/direction")
|
||||
|
||||
err := a.arduinoSetup()
|
||||
@ -136,6 +144,7 @@ func TestAdaptorArduinoSetupFail240(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoSetupFail111(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
delete(fs.Files, "/sys/kernel/debug/gpio_debug/gpio111/current_pinmux")
|
||||
|
||||
err := a.arduinoSetup()
|
||||
@ -144,6 +153,7 @@ func TestAdaptorArduinoSetupFail111(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoSetupFail131(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
delete(fs.Files, "/sys/kernel/debug/gpio_debug/gpio131/current_pinmux")
|
||||
|
||||
err := a.arduinoSetup()
|
||||
@ -152,6 +162,7 @@ func TestAdaptorArduinoSetupFail131(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoI2CSetupFailTristate(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
gobottest.Assert(t, a.arduinoSetup(), nil)
|
||||
|
||||
@ -162,6 +173,7 @@ func TestAdaptorArduinoI2CSetupFailTristate(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoI2CSetupFail14(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
gobottest.Assert(t, a.arduinoSetup(), nil)
|
||||
delete(fs.Files, "/sys/class/gpio/gpio14/direction")
|
||||
@ -172,6 +184,7 @@ func TestAdaptorArduinoI2CSetupFail14(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoI2CSetupUnexportFail(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
gobottest.Assert(t, a.arduinoSetup(), nil)
|
||||
delete(fs.Files, "/sys/class/gpio/unexport")
|
||||
@ -182,6 +195,7 @@ func TestAdaptorArduinoI2CSetupUnexportFail(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoI2CSetupFail236(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
gobottest.Assert(t, a.arduinoSetup(), nil)
|
||||
delete(fs.Files, "/sys/class/gpio/gpio236/direction")
|
||||
@ -192,6 +206,7 @@ func TestAdaptorArduinoI2CSetupFail236(t *testing.T) {
|
||||
|
||||
func TestAdaptorArduinoI2CSetupFail28(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
gobottest.Assert(t, a.arduinoSetup(), nil)
|
||||
delete(fs.Files, "/sys/kernel/debug/gpio_debug/gpio28/current_pinmux")
|
||||
@ -202,6 +217,7 @@ func TestAdaptorArduinoI2CSetupFail28(t *testing.T) {
|
||||
|
||||
func TestAdaptorConnectArduinoError(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
a.writeFile = func(string, []byte) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
}
|
||||
@ -212,6 +228,7 @@ func TestAdaptorConnectArduinoError(t *testing.T) {
|
||||
|
||||
func TestAdaptorConnectArduinoWriteError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
fs.WithWriteError = true
|
||||
err := a.Connect()
|
||||
gobottest.Assert(t, strings.Contains(err.Error(), "write error"), true)
|
||||
@ -219,6 +236,7 @@ func TestAdaptorConnectArduinoWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorConnectSparkfun(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
a.SetBoard("sparkfun")
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 1)
|
||||
@ -227,6 +245,7 @@ func TestAdaptorConnectSparkfun(t *testing.T) {
|
||||
|
||||
func TestAdaptorConnectMiniboard(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
a.SetBoard("miniboard")
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 1)
|
||||
@ -235,16 +254,19 @@ func TestAdaptorConnectMiniboard(t *testing.T) {
|
||||
|
||||
func TestAdaptorConnectUnknown(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
a.SetBoard("wha")
|
||||
gobottest.Refute(t, a.Connect(), nil)
|
||||
}
|
||||
|
||||
func TestAdaptorFinalize(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
a.DigitalWrite("3", 1)
|
||||
a.PwmWrite("5", 100)
|
||||
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
a.GetConnection(0xff, 6)
|
||||
|
||||
gobottest.Assert(t, a.Finalize(), nil)
|
||||
@ -255,6 +277,7 @@ func TestAdaptorFinalize(t *testing.T) {
|
||||
|
||||
func TestAdaptorFinalizeError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
a.PwmWrite("5", 100)
|
||||
|
||||
fs.WithWriteError = true
|
||||
@ -263,6 +286,7 @@ func TestAdaptorFinalizeError(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalIO(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
a.DigitalWrite("13", 1)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio40/value"].Contents, "1")
|
||||
@ -289,6 +313,7 @@ func TestAdaptorDigitalPinInFileError(t *testing.T) {
|
||||
"/sys/class/gpio/gpio261/direction",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a.Connect()
|
||||
|
||||
@ -313,6 +338,7 @@ func TestAdaptorDigitalPinInResistorFileError(t *testing.T) {
|
||||
"/sys/class/gpio/gpio261/direction",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a.Connect()
|
||||
|
||||
@ -336,6 +362,7 @@ func TestAdaptorDigitalPinInLevelShifterFileError(t *testing.T) {
|
||||
// "/sys/class/gpio/gpio261/direction",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a.Connect()
|
||||
|
||||
@ -359,6 +386,7 @@ func TestAdaptorDigitalPinInMuxFileError(t *testing.T) {
|
||||
"/sys/class/gpio/gpio261/direction",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a.Connect()
|
||||
|
||||
@ -368,6 +396,7 @@ func TestAdaptorDigitalPinInMuxFileError(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
err := a.DigitalWrite("13", 1)
|
||||
@ -376,6 +405,7 @@ func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalReadWriteError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
_, err := a.DigitalRead("13")
|
||||
@ -384,8 +414,11 @@ func TestAdaptorDigitalReadWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorI2c(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 6)
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
@ -399,12 +432,14 @@ func TestAdaptorI2c(t *testing.T) {
|
||||
|
||||
func TestAdaptorI2cInvalidBus(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
_, err := a.GetConnection(0xff, 3)
|
||||
gobottest.Assert(t, err, errors.New("Unsupported I2C bus"))
|
||||
}
|
||||
|
||||
func TestAdaptorPwm(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
err := a.PwmWrite("5", 100)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -432,6 +467,7 @@ func TestAdaptorPwmExportError(t *testing.T) {
|
||||
"/sys/class/pwm/pwmchip0/pwm1/enable",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
a.Connect()
|
||||
|
||||
err := a.PwmWrite("5", 100)
|
||||
@ -456,6 +492,7 @@ func TestAdaptorPwmEnableError(t *testing.T) {
|
||||
//"/sys/class/pwm/pwmchip0/pwm1/enable",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
a.Connect()
|
||||
|
||||
err := a.PwmWrite("5", 100)
|
||||
@ -464,6 +501,7 @@ func TestAdaptorPwmEnableError(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwmWritePinError(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
a.writeFile = func(string, []byte) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
@ -475,6 +513,7 @@ func TestAdaptorPwmWritePinError(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwmWriteError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
fs.WithWriteError = true
|
||||
|
||||
@ -484,6 +523,7 @@ func TestAdaptorPwmWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwmReadError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
fs.WithReadError = true
|
||||
|
||||
@ -493,6 +533,7 @@ func TestAdaptorPwmReadError(t *testing.T) {
|
||||
|
||||
func TestAdaptorAnalog(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
fs.Files["/sys/bus/iio/devices/iio:device1/in_voltage0_raw"].Contents = "1000\n"
|
||||
i, _ := a.AnalogRead("0")
|
||||
@ -501,6 +542,7 @@ func TestAdaptorAnalog(t *testing.T) {
|
||||
|
||||
func TestAdaptorAnalogError(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
a.readFile = func(string) ([]byte, error) {
|
||||
return nil, errors.New("read error")
|
||||
|
@ -88,13 +88,19 @@ func initTestAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
|
||||
"/dev/i2c-0",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
|
||||
fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "5000"
|
||||
a.Connect()
|
||||
return a, fs
|
||||
}
|
||||
|
||||
func cleanTestAdaptor() {
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
}
|
||||
|
||||
func TestJouleAdaptorName(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
gobottest.Assert(t, strings.HasPrefix(a.Name(), "Joule"), true)
|
||||
a.SetName("NewName")
|
||||
gobottest.Assert(t, a.Name(), "NewName")
|
||||
@ -102,12 +108,14 @@ func TestJouleAdaptorName(t *testing.T) {
|
||||
|
||||
func TestAdaptorConnect(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 0)
|
||||
}
|
||||
|
||||
func TestAdaptorInvalidBus(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
|
||||
_, err := a.GetConnection(0xff, 10)
|
||||
@ -116,10 +124,13 @@ func TestAdaptorInvalidBus(t *testing.T) {
|
||||
|
||||
func TestAdaptorFinalize(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
a.DigitalWrite("J12_1", 1)
|
||||
a.PwmWrite("J12_26", 100)
|
||||
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
gobottest.Assert(t, a.Finalize(), nil)
|
||||
_, err := a.GetConnection(0xff, 0)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -131,6 +142,7 @@ func TestAdaptorFinalize(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalIO(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
a.DigitalWrite("J12_1", 1)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio451/value"].Contents, "1")
|
||||
@ -143,6 +155,7 @@ func TestAdaptorDigitalIO(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
err := a.DigitalWrite("13", 1)
|
||||
@ -151,6 +164,7 @@ func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalReadWriteError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
_, err := a.DigitalRead("13")
|
||||
@ -159,8 +173,11 @@ func TestAdaptorDigitalReadWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorI2c(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 0)
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
@ -174,6 +191,7 @@ func TestAdaptorI2c(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwm(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
err := a.PwmWrite("J12_26", 100)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -188,6 +206,7 @@ func TestAdaptorPwm(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwmPinExportError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
delete(fs.Files, "/sys/class/pwm/pwmchip0/export")
|
||||
|
||||
@ -197,6 +216,7 @@ func TestAdaptorPwmPinExportError(t *testing.T) {
|
||||
|
||||
func TestAdaptorPwmPinEnableError(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
defer cleanTestAdaptor()
|
||||
|
||||
delete(fs.Files, "/sys/class/pwm/pwmchip0/pwm0/enable")
|
||||
|
||||
|
@ -61,7 +61,9 @@ func TestAdaptorFinalize(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
a.DigitalWrite("3", 1)
|
||||
|
||||
@ -81,6 +83,7 @@ func TestAdaptorDigitalIO(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a.DigitalWrite("7", 1)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio216/value"].Contents, "1")
|
||||
@ -106,7 +109,9 @@ func TestAdaptorI2c(t *testing.T) {
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 1)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -128,7 +133,9 @@ func TestAdaptorSPI(t *testing.T) {
|
||||
"/dev/spidev0.1",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
gobottest.Assert(t, a.GetSpiDefaultBus(), 0)
|
||||
gobottest.Assert(t, a.GetSpiDefaultChip(), 0)
|
||||
@ -145,6 +152,7 @@ func TestAdaptorDigitalPinConcurrency(t *testing.T) {
|
||||
|
||||
oldProcs := runtime.GOMAXPROCS(0)
|
||||
runtime.GOMAXPROCS(8)
|
||||
defer runtime.GOMAXPROCS(oldProcs)
|
||||
|
||||
for retry := 0; retry < 20; retry++ {
|
||||
|
||||
@ -162,7 +170,4 @@ func TestAdaptorDigitalPinConcurrency(t *testing.T) {
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
runtime.GOMAXPROCS(oldProcs)
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ func TestPwmPin(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
pin, err := NewPWMPin("32")
|
||||
gobottest.Assert(t, pin.Export(), nil)
|
||||
|
@ -99,7 +99,9 @@ func TestAdaptorFinalize(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
a.DigitalWrite("3", 1)
|
||||
a.PwmWrite("7", 255)
|
||||
@ -112,12 +114,13 @@ func TestAdaptorDigitalPWM(t *testing.T) {
|
||||
a := initTestAdaptor()
|
||||
a.PiBlasterPeriod = 20000000
|
||||
|
||||
gobottest.Assert(t, a.PwmWrite("7", 4), nil)
|
||||
|
||||
fs := sysfs.NewMockFilesystem([]string{
|
||||
"/dev/pi-blaster",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
gobottest.Assert(t, a.PwmWrite("7", 4), nil)
|
||||
|
||||
pin, _ := a.PWMPin("7")
|
||||
period, _ := pin.Period()
|
||||
@ -155,6 +158,7 @@ func TestAdaptorDigitalIO(t *testing.T) {
|
||||
})
|
||||
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
|
||||
a.DigitalWrite("7", 1)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/gpio/gpio4/value"].Contents, "1")
|
||||
@ -180,7 +184,9 @@ func TestAdaptorI2c(t *testing.T) {
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 1)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -202,7 +208,9 @@ func TestAdaptorSPI(t *testing.T) {
|
||||
"/dev/spidev0.1",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
gobottest.Assert(t, a.GetSpiDefaultBus(), 0)
|
||||
gobottest.Assert(t, a.GetSpiDefaultChip(), 0)
|
||||
@ -219,6 +227,7 @@ func TestAdaptorDigitalPinConcurrency(t *testing.T) {
|
||||
|
||||
oldProcs := runtime.GOMAXPROCS(0)
|
||||
runtime.GOMAXPROCS(8)
|
||||
defer runtime.GOMAXPROCS(oldProcs)
|
||||
|
||||
for retry := 0; retry < 20; retry++ {
|
||||
|
||||
@ -236,9 +245,6 @@ func TestAdaptorDigitalPinConcurrency(t *testing.T) {
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
runtime.GOMAXPROCS(oldProcs)
|
||||
|
||||
}
|
||||
|
||||
func TestAdaptorPWMPin(t *testing.T) {
|
||||
|
@ -87,6 +87,10 @@ func initTestTinkerboard(fs *sysfs.MockFilesystem) *Adaptor {
|
||||
return a
|
||||
}
|
||||
|
||||
func cleanTestTinkerboard() {
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
}
|
||||
|
||||
func TestTinkerboardName(t *testing.T) {
|
||||
a := NewAdaptor()
|
||||
gobottest.Assert(t, strings.HasPrefix(a.Name(), "Tinker Board"), true)
|
||||
@ -97,6 +101,7 @@ func TestTinkerboardName(t *testing.T) {
|
||||
func TestTinkerboardDigitalIO(t *testing.T) {
|
||||
fs := gpioFs()
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
a.Connect()
|
||||
|
||||
a.DigitalWrite("7", 1)
|
||||
@ -114,6 +119,7 @@ func TestTinkerboardDigitalWriteError(t *testing.T) {
|
||||
fs := gpioFs()
|
||||
fs.WithWriteError = true
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
err := a.DigitalWrite("7", 1)
|
||||
gobottest.Assert(t, err, errors.New("write error"))
|
||||
@ -123,6 +129,7 @@ func TestTinkerboardDigitalReadWriteError(t *testing.T) {
|
||||
fs := gpioFs()
|
||||
fs.WithWriteError = true
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
_, err := a.DigitalRead("7")
|
||||
gobottest.Assert(t, err, errors.New("write error"))
|
||||
@ -131,6 +138,7 @@ func TestTinkerboardDigitalReadWriteError(t *testing.T) {
|
||||
func TestTinkerboardInvalidPWMPin(t *testing.T) {
|
||||
fs := pwmFs(t)
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
err := a.PwmWrite("666", 42)
|
||||
gobottest.Refute(t, err, nil)
|
||||
@ -148,6 +156,7 @@ func TestTinkerboardInvalidPWMPin(t *testing.T) {
|
||||
func TestTinkerboardPwmWrite(t *testing.T) {
|
||||
fs := pwmFs(t)
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
err := a.PwmWrite("33", 100)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -174,6 +183,7 @@ func TestTinkerboardPwmWriteError(t *testing.T) {
|
||||
fs := pwmFs(t)
|
||||
fs.WithWriteError = true
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
err := a.PwmWrite("33", 100)
|
||||
gobottest.Assert(t, strings.Contains(err.Error(), "write error"), true)
|
||||
@ -183,6 +193,7 @@ func TestTinkerboardPwmWriteReadError(t *testing.T) {
|
||||
fs := pwmFs(t)
|
||||
fs.WithReadError = true
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
err := a.PwmWrite("33", 100)
|
||||
gobottest.Assert(t, strings.Contains(err.Error(), "read error"), true)
|
||||
@ -192,6 +203,7 @@ func TestTinkerboardSetPeriod(t *testing.T) {
|
||||
// arrange
|
||||
fs := pwmFs(t)
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
newPeriod := uint32(2550000)
|
||||
|
||||
// act
|
||||
@ -232,7 +244,9 @@ func TestTinkerboardSetPeriod(t *testing.T) {
|
||||
func TestTinkerboardI2c(t *testing.T) {
|
||||
fs := i2cFs()
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 1)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -259,6 +273,7 @@ func TestTinkerboardGetConnectionInvalidBus(t *testing.T) {
|
||||
func TestTinkerboardFinalizeErrorAfterGPIO(t *testing.T) {
|
||||
fs := gpioFs()
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.DigitalWrite("7", 1), nil)
|
||||
@ -272,6 +287,7 @@ func TestTinkerboardFinalizeErrorAfterGPIO(t *testing.T) {
|
||||
func TestTinkerboardFinalizeErrorAfterPWM(t *testing.T) {
|
||||
fs := pwmFs(t)
|
||||
a := initTestTinkerboard(fs)
|
||||
defer cleanTestTinkerboard()
|
||||
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.PwmWrite("33", 1), nil)
|
||||
|
@ -46,6 +46,10 @@ func initTestUP2Adaptor() (*Adaptor, *sysfs.MockFilesystem) {
|
||||
return a, fs
|
||||
}
|
||||
|
||||
func cleanTestUP2Adaptor() {
|
||||
defer sysfs.SetFilesystem(&sysfs.NativeFilesystem{})
|
||||
}
|
||||
|
||||
func TestUP2AdaptorName(t *testing.T) {
|
||||
a := NewAdaptor()
|
||||
gobottest.Assert(t, strings.HasPrefix(a.Name(), "UP2"), true)
|
||||
@ -55,6 +59,7 @@ func TestUP2AdaptorName(t *testing.T) {
|
||||
|
||||
func TestUP2AdaptorDigitalIO(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
a.Connect()
|
||||
|
||||
a.DigitalWrite("7", 1)
|
||||
@ -76,6 +81,7 @@ func TestUP2AdaptorDigitalIO(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
err := a.DigitalWrite("7", 1)
|
||||
@ -84,6 +90,7 @@ func TestAdaptorDigitalWriteError(t *testing.T) {
|
||||
|
||||
func TestAdaptorDigitalReadWriteError(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
_, err := a.DigitalRead("7")
|
||||
@ -97,6 +104,7 @@ func TestUP2AdaptorI2c(t *testing.T) {
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
sysfs.SetSyscall(&sysfs.MockSyscall{})
|
||||
defer sysfs.SetSyscall(&sysfs.NativeSyscall{})
|
||||
|
||||
con, err := a.GetConnection(0xff, 5)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -126,6 +134,7 @@ func TestAdaptorSPI(t *testing.T) {
|
||||
|
||||
func TestUP2AdaptorInvalidPWMPin(t *testing.T) {
|
||||
a, _ := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
a.Connect()
|
||||
|
||||
err := a.PwmWrite("666", 42)
|
||||
@ -143,6 +152,7 @@ func TestUP2AdaptorInvalidPWMPin(t *testing.T) {
|
||||
|
||||
func TestUP2AdaptorPWM(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
|
||||
err := a.PwmWrite("32", 100)
|
||||
gobottest.Assert(t, err, nil)
|
||||
@ -166,6 +176,7 @@ func TestUP2AdaptorPWM(t *testing.T) {
|
||||
|
||||
func TestUP2AdaptorPwmWriteError(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
fs.WithWriteError = true
|
||||
|
||||
err := a.PwmWrite("32", 100)
|
||||
@ -174,6 +185,7 @@ func TestUP2AdaptorPwmWriteError(t *testing.T) {
|
||||
|
||||
func TestUP2AdaptorPwmReadError(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
fs.WithReadError = true
|
||||
|
||||
err := a.PwmWrite("32", 100)
|
||||
@ -182,17 +194,20 @@ func TestUP2AdaptorPwmReadError(t *testing.T) {
|
||||
|
||||
func TestUP2I2CDefaultBus(t *testing.T) {
|
||||
a, _ := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 5)
|
||||
}
|
||||
|
||||
func TestUP2GetConnectionInvalidBus(t *testing.T) {
|
||||
a, _ := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
_, err := a.GetConnection(0x01, 99)
|
||||
gobottest.Assert(t, err, errors.New("Bus number 99 out of range"))
|
||||
}
|
||||
|
||||
func TestUP2FinalizeErrorAfterGPIO(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.DigitalWrite("7", 1), nil)
|
||||
@ -205,6 +220,7 @@ func TestUP2FinalizeErrorAfterGPIO(t *testing.T) {
|
||||
|
||||
func TestUP2FinalizeErrorAfterPWM(t *testing.T) {
|
||||
a, fs := initTestUP2Adaptor()
|
||||
defer cleanTestUP2Adaptor()
|
||||
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.PwmWrite("32", 1), nil)
|
||||
|
39
sysfs/README.md
Normal file
39
sysfs/README.md
Normal file
@ -0,0 +1,39 @@
|
||||
# sysfs
|
||||
|
||||
## I2C
|
||||
|
||||
### Byte order
|
||||
|
||||
All common libraries (smbus, digispark, firmata, i2cget) read and write I2C data in the order LSByte, MSByte.
|
||||
Often the devices store its bytes in the reverse order and therefor needs to be swapped after reading.
|
||||
|
||||
### Linux syscall implementation
|
||||
|
||||
In general there are different ioctl features for I2C
|
||||
|
||||
* IOCTL I2C_RDWR, needs "I2C_FUNC_I2C"
|
||||
* IOCTL SMBUS, needs "I2C_FUNC_SMBUS.."
|
||||
* SYSFS I/O
|
||||
* call of "i2c_smbus_* methods"
|
||||
|
||||
>The possible functions should be checked before by "I2C_FUNCS".
|
||||
|
||||
for further reading see:
|
||||
|
||||
* https://www.kernel.org/doc/Documentation/i2c/dev-interface
|
||||
* https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/i2c-dev.h#L42
|
||||
* https://stackoverflow.com/questions/9974592/i2c-slave-ioctl-purpose (good for understanding, but there are some small errors in the provided example)
|
||||
|
||||
>Qotation from kernel.org: "If possible, use the provided i2c_smbus_* methods described below instead of issuing direct ioctls." We do not do this at the moment, instead we using the "IOCTL SMBUS".
|
||||
|
||||
Because the syscall needs uintptr in Go, there are some known pitfalls with that. Following documents could be helpful:
|
||||
|
||||
* https://go101.org/article/unsafe.html
|
||||
* https://stackoverflow.com/questions/51187973/how-to-create-an-array-or-a-slice-from-an-array-unsafe-pointer-in-golang
|
||||
* https://stackoverflow.com/questions/59042646/whats-the-difference-between-uint-and-uintptr-in-golang
|
||||
* https://go.dev/play/p/Wd7hWn9Zsu
|
||||
* for go vet false positives, see: https://github.com/golang/go/issues/41205
|
||||
|
||||
Basically by convert to an uintptr, which is than just a number to an object existing at the moment of creation without
|
||||
any other reference, the garbage collector will possible destroy the original object. Therefor uintptr should be avoided
|
||||
as long as possible.
|
@ -1,6 +1,8 @@
|
||||
package sysfs
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkDigitalRead(b *testing.B) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
@ -11,6 +13,8 @@ func BenchmarkDigitalRead(b *testing.B) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewDigitalPin(10)
|
||||
pin.Write(1)
|
||||
|
||||
|
@ -18,6 +18,7 @@ func TestDigitalPin(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewDigitalPin(10, "custom")
|
||||
gobottest.Assert(t, pin.pin, "10")
|
||||
@ -94,6 +95,7 @@ func TestDigitalPinExportError(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewDigitalPin(10, "custom")
|
||||
writeFile = func(File, []byte) (int, error) {
|
||||
@ -113,6 +115,7 @@ func TestDigitalPinUnexportError(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewDigitalPin(10, "custom")
|
||||
writeFile = func(File, []byte) (int, error) {
|
||||
|
@ -30,7 +30,7 @@ const (
|
||||
I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000
|
||||
I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000
|
||||
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000
|
||||
// Transaction types
|
||||
// Transaction types, also declare the transfer size (register and data)
|
||||
I2C_SMBUS_BYTE = 1
|
||||
I2C_SMBUS_BYTE_DATA = 2
|
||||
I2C_SMBUS_WORD_DATA = 3
|
||||
@ -45,7 +45,7 @@ type i2cSmbusIoctlData struct {
|
||||
readWrite byte
|
||||
command byte
|
||||
size uint32
|
||||
data uintptr
|
||||
data unsafe.Pointer
|
||||
}
|
||||
|
||||
type i2cDevice struct {
|
||||
@ -69,12 +69,7 @@ func NewI2cDevice(location string) (d *i2cDevice, err error) {
|
||||
}
|
||||
|
||||
func (d *i2cDevice) queryFunctionality() error {
|
||||
_, _, errno := Syscall(
|
||||
syscall.SYS_IOCTL,
|
||||
d.file.Fd(),
|
||||
I2C_FUNCS,
|
||||
uintptr(unsafe.Pointer(&d.funcs)),
|
||||
)
|
||||
_, _, errno := Syscall(syscall.SYS_IOCTL, d.file, I2C_FUNCS, unsafe.Pointer(&d.funcs))
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("Querying functionality failed with syscall.Errno %v", errno)
|
||||
@ -82,13 +77,10 @@ func (d *i2cDevice) queryFunctionality() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAddress sets the address of the i2c device to use.
|
||||
func (d *i2cDevice) SetAddress(address int) error {
|
||||
_, _, errno := Syscall(
|
||||
syscall.SYS_IOCTL,
|
||||
d.file.Fd(),
|
||||
I2C_SLAVE,
|
||||
uintptr(byte(address)),
|
||||
)
|
||||
// for go vet false positives, see: https://github.com/golang/go/issues/41205
|
||||
_, _, errno := Syscall(syscall.SYS_IOCTL, d.file, I2C_SLAVE, unsafe.Pointer(uintptr(byte(address))))
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("Setting address failed with syscall.Errno %v", errno)
|
||||
@ -96,45 +88,52 @@ func (d *i2cDevice) SetAddress(address int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the character device file.
|
||||
func (d *i2cDevice) Close() error {
|
||||
return d.file.Close()
|
||||
}
|
||||
|
||||
func (d *i2cDevice) ReadByte() (val byte, err error) {
|
||||
// ReadByte reads a byte from the current register of an i2c device.
|
||||
func (d *i2cDevice) ReadByte() (byte, error) {
|
||||
if d.funcs&I2C_FUNC_SMBUS_READ_BYTE == 0 {
|
||||
return 0, fmt.Errorf("SMBus read byte not supported")
|
||||
}
|
||||
|
||||
var data uint8
|
||||
err = d.smbusAccess(I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, uintptr(unsafe.Pointer(&data)))
|
||||
var data uint8 = 0xFC // set value for debugging purposes
|
||||
err := d.smbusAccess(I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, unsafe.Pointer(&data))
|
||||
return data, err
|
||||
}
|
||||
|
||||
// ReadByteData reads a byte from the given register of an i2c device.
|
||||
func (d *i2cDevice) ReadByteData(reg uint8) (val uint8, err error) {
|
||||
if d.funcs&I2C_FUNC_SMBUS_READ_BYTE_DATA == 0 {
|
||||
return 0, fmt.Errorf("SMBus read byte data not supported")
|
||||
}
|
||||
|
||||
var data uint8
|
||||
err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, uintptr(unsafe.Pointer(&data)))
|
||||
var data uint8 = 0xFD // set value for debugging purposes
|
||||
err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data))
|
||||
return data, err
|
||||
}
|
||||
|
||||
// ReadWordData reads a 16 bit value starting from the given register of an i2c device.
|
||||
func (d *i2cDevice) ReadWordData(reg uint8) (val uint16, err error) {
|
||||
if d.funcs&I2C_FUNC_SMBUS_READ_WORD_DATA == 0 {
|
||||
return 0, fmt.Errorf("SMBus read word data not supported")
|
||||
}
|
||||
|
||||
var data uint16
|
||||
err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, uintptr(unsafe.Pointer(&data)))
|
||||
var data uint16 = 0xFFFE // set value for debugging purposes
|
||||
err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data))
|
||||
return data, err
|
||||
}
|
||||
|
||||
// ReadBlockData fills the given buffer with reads starting from the given register of an i2c device.
|
||||
func (d *i2cDevice) ReadBlockData(reg uint8, data []byte) error {
|
||||
if len(data) > 32 {
|
||||
lenWithReg := len(data) + 1
|
||||
if lenWithReg > 33 {
|
||||
return fmt.Errorf("Reading blocks larger than 32 bytes (%v) not supported", len(data))
|
||||
}
|
||||
|
||||
data[0] = 0xFF // set value for debugging purposes
|
||||
if d.funcs&I2C_FUNC_SMBUS_READ_BLOCK_DATA == 0 {
|
||||
if i2cDeviceDebug {
|
||||
log.Printf("SMBus read block data not supported, use fallback\n")
|
||||
@ -142,37 +141,42 @@ func (d *i2cDevice) ReadBlockData(reg uint8, data []byte) error {
|
||||
return d.readBlockDataFallback(reg, data)
|
||||
}
|
||||
|
||||
return d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_BLOCK_DATA, uintptr(unsafe.Pointer(&data)))
|
||||
return d.smbusAccess(I2C_SMBUS_READ, reg, uint32(lenWithReg), unsafe.Pointer(&data[0]))
|
||||
}
|
||||
|
||||
// WriteByte writes the given byte value to the current register of an i2c device.
|
||||
func (d *i2cDevice) WriteByte(val byte) error {
|
||||
if d.funcs&I2C_FUNC_SMBUS_WRITE_BYTE == 0 {
|
||||
return fmt.Errorf("SMBus write byte not supported")
|
||||
}
|
||||
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, uintptr(0))
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, nil)
|
||||
}
|
||||
|
||||
// WriteByteData writes the given byte value to the given register of an i2c device.
|
||||
func (d *i2cDevice) WriteByteData(reg uint8, val uint8) error {
|
||||
if d.funcs&I2C_FUNC_SMBUS_WRITE_BYTE_DATA == 0 {
|
||||
return fmt.Errorf("SMBus write byte data not supported")
|
||||
}
|
||||
|
||||
var data = val
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, uintptr(unsafe.Pointer(&data)))
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data))
|
||||
}
|
||||
|
||||
// WriteWordData writes the given 16 bit value starting from the given register of an i2c device.
|
||||
func (d *i2cDevice) WriteWordData(reg uint8, val uint16) error {
|
||||
if d.funcs&I2C_FUNC_SMBUS_WRITE_WORD_DATA == 0 {
|
||||
return fmt.Errorf("SMBus write word data not supported")
|
||||
}
|
||||
|
||||
var data = val
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, uintptr(unsafe.Pointer(&data)))
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data))
|
||||
}
|
||||
|
||||
// WriteBlockData writes the given buffer starting from the given register of an i2c device.
|
||||
func (d *i2cDevice) WriteBlockData(reg uint8, data []byte) error {
|
||||
if len(data) > 32 {
|
||||
lenWithReg := len(data) + 1
|
||||
if lenWithReg > 33 {
|
||||
return fmt.Errorf("Writing blocks larger than 32 bytes (%v) not supported", len(data))
|
||||
}
|
||||
|
||||
@ -183,7 +187,7 @@ func (d *i2cDevice) WriteBlockData(reg uint8, data []byte) error {
|
||||
return d.writeBlockDataFallback(reg, data)
|
||||
}
|
||||
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BLOCK_DATA, uintptr(unsafe.Pointer(&data)))
|
||||
return d.smbusAccess(I2C_SMBUS_WRITE, reg, uint32(lenWithReg), unsafe.Pointer(&data[0]))
|
||||
}
|
||||
|
||||
// Read implements the io.ReadWriteCloser method by direct I2C read operations.
|
||||
@ -196,20 +200,15 @@ func (d *i2cDevice) Write(b []byte) (n int, err error) {
|
||||
return d.file.Write(b)
|
||||
}
|
||||
|
||||
func (d *i2cDevice) smbusAccess(readWrite byte, command byte, size uint32, data uintptr) error {
|
||||
smbus := &i2cSmbusIoctlData{
|
||||
func (d *i2cDevice) smbusAccess(readWrite byte, command byte, size uint32, dataStart unsafe.Pointer) error {
|
||||
smbus := i2cSmbusIoctlData{
|
||||
readWrite: readWrite,
|
||||
command: command,
|
||||
size: size,
|
||||
data: data,
|
||||
data: dataStart, // the reflected value of unsafePointer equals uintptr(dataStart),
|
||||
}
|
||||
|
||||
_, _, errno := Syscall(
|
||||
syscall.SYS_IOCTL,
|
||||
d.file.Fd(),
|
||||
I2C_SMBUS,
|
||||
uintptr(unsafe.Pointer(smbus)),
|
||||
)
|
||||
_, _, errno := Syscall(syscall.SYS_IOCTL, d.file, I2C_SMBUS, unsafe.Pointer(&smbus))
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("Failed with syscall.Errno %v", errno)
|
||||
|
@ -10,340 +10,507 @@ import (
|
||||
"gobot.io/x/gobot/gobottest"
|
||||
)
|
||||
|
||||
func TestNewI2cDeviceClose(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
const dev = "/dev/i2c-1"
|
||||
|
||||
SetFilesystem(fs)
|
||||
SetSyscall(&MockSyscall{})
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, i.Close(), nil)
|
||||
func initTestI2cDeviceWithMockedSys() (*i2cDevice, *MockSyscall) {
|
||||
SetFilesystem(NewMockFilesystem([]string{dev}))
|
||||
msc := &MockSyscall{}
|
||||
SetSyscall(msc)
|
||||
d, err := NewI2cDevice(dev)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return d, msc
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceQueryFuncError(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
SetSyscall(&MockSyscall{
|
||||
Impl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return 0, 0, 1
|
||||
},
|
||||
})
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, errors.New("Querying functionality failed with syscall.Errno operation not permitted"))
|
||||
func cleanTestI2cDevice() {
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
defer SetSyscall(&NativeSyscall{})
|
||||
}
|
||||
|
||||
func TestNewI2cDevice(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{})
|
||||
SetFilesystem(fs)
|
||||
SetSyscall(&MockSyscall{})
|
||||
|
||||
i, err := NewI2cDevice(os.DevNull)
|
||||
gobottest.Assert(t, err.Error(), " : /dev/null: No such file.")
|
||||
|
||||
fs = NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err = NewI2cDevice("/dev/i2c-1")
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
SetSyscall(&MockSyscall{})
|
||||
|
||||
i, err = NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
gobottest.Assert(t, i.SetAddress(0xff), nil)
|
||||
|
||||
buf := []byte{0x01, 0x02, 0x03}
|
||||
|
||||
n, err := i.Write(buf)
|
||||
|
||||
gobottest.Assert(t, n, len(buf))
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
buf = make([]byte, 4)
|
||||
|
||||
n, err = i.Read(buf)
|
||||
|
||||
gobottest.Assert(t, n, 3)
|
||||
gobottest.Assert(t, err, nil)
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceReadByte(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
i.funcs = I2C_FUNC_SMBUS_READ_BYTE
|
||||
|
||||
val, e := i.ReadByte()
|
||||
gobottest.Assert(t, val, byte(0))
|
||||
gobottest.Assert(t, e, nil)
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceReadByteError(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
SetSyscall(&MockSyscall{
|
||||
Impl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return 0, 0, 1
|
||||
var tests = map[string]struct {
|
||||
dev string
|
||||
wantErr string
|
||||
}{
|
||||
"ok": {
|
||||
dev: dev,
|
||||
},
|
||||
})
|
||||
|
||||
i.SetAddress(0xff)
|
||||
i.funcs = I2C_FUNC_SMBUS_READ_BYTE
|
||||
|
||||
_, e := i.ReadByte()
|
||||
gobottest.Refute(t, e, nil)
|
||||
"null": {
|
||||
dev: os.DevNull,
|
||||
wantErr: " : /dev/null: No such file.",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
SetFilesystem(NewMockFilesystem([]string{dev}))
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
SetSyscall(&MockSyscall{})
|
||||
defer SetSyscall(&NativeSyscall{})
|
||||
// act
|
||||
i, err := NewI2cDevice(tc.dev)
|
||||
var _ i2c.I2cDevice = i
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceReadByteNotSupported(t *testing.T) {
|
||||
SetSyscall(&MockSyscall{})
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
_, err = i.ReadByte()
|
||||
gobottest.Assert(t, err.Error(), "SMBus read byte not supported")
|
||||
func TestNewI2cDeviceQueryFuncError(t *testing.T) {
|
||||
// arrange
|
||||
SetFilesystem(NewMockFilesystem([]string{dev}))
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
SetSyscall(&MockSyscall{Impl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 }})
|
||||
defer SetSyscall(&NativeSyscall{})
|
||||
// act
|
||||
_, err := NewI2cDevice(dev)
|
||||
// assert
|
||||
gobottest.Assert(t, err, errors.New("Querying functionality failed with syscall.Errno operation not permitted"))
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteByte(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
i.funcs = I2C_FUNC_SMBUS_WRITE_BYTE
|
||||
|
||||
e := i.WriteByte(0x01)
|
||||
gobottest.Assert(t, e, nil)
|
||||
func TestClose(t *testing.T) {
|
||||
// arrange
|
||||
d, _ := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
// act & assert
|
||||
gobottest.Assert(t, d.Close(), nil)
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteByteNotSupported(t *testing.T) {
|
||||
SetSyscall(&MockSyscall{})
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
func TestSetAddress(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
// act
|
||||
err := d.SetAddress(0xff)
|
||||
// assert
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
err = i.WriteByte(0x01)
|
||||
gobottest.Assert(t, err.Error(), "SMBus write byte not supported")
|
||||
gobottest.Assert(t, msc.devAddress, uintptr(0xff))
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceReadByteData(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
i.funcs = I2C_FUNC_SMBUS_READ_BYTE_DATA
|
||||
|
||||
v, e := i.ReadByteData(0x01)
|
||||
gobottest.Assert(t, v, byte(0))
|
||||
gobottest.Assert(t, e, nil)
|
||||
func TestWriteRead(t *testing.T) {
|
||||
// arrange
|
||||
d, _ := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
wbuf := []byte{0x01, 0x02, 0x03}
|
||||
rbuf := make([]byte, 4)
|
||||
// act
|
||||
wn, werr := d.Write(wbuf)
|
||||
rn, rerr := d.Read(rbuf)
|
||||
// assert
|
||||
gobottest.Assert(t, werr, nil)
|
||||
gobottest.Assert(t, rerr, nil)
|
||||
gobottest.Assert(t, wn, len(wbuf))
|
||||
gobottest.Assert(t, rn, len(wbuf)) // will read only the written values
|
||||
gobottest.Assert(t, wbuf, rbuf[:len(wbuf)])
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceReadByteDataNotSupported(t *testing.T) {
|
||||
SetSyscall(&MockSyscall{})
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
_, err = i.ReadByteData(0x01)
|
||||
gobottest.Assert(t, err.Error(), "SMBus read byte data not supported")
|
||||
func TestReadByte(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"read_byte_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_BYTE,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_BYTE,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
"error_not_supported": {
|
||||
wantErr: "SMBus read byte not supported",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const want = byte(5)
|
||||
msc.dataSlice = []byte{want}
|
||||
// act
|
||||
got, err := d.ReadByte()
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, got, want)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
|
||||
gobottest.Assert(t, msc.smbus.command, byte(0)) // register is set to 0 in that case
|
||||
gobottest.Assert(t, msc.smbus.size, uint32(I2C_SMBUS_BYTE))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteByteData(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
i.funcs = I2C_FUNC_SMBUS_WRITE_BYTE_DATA
|
||||
|
||||
e := i.WriteByteData(0x01, 0x02)
|
||||
gobottest.Assert(t, e, nil)
|
||||
func TestReadByteData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"read_byte_data_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_BYTE_DATA,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_BYTE_DATA,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
"error_not_supported": {
|
||||
wantErr: "SMBus read byte data not supported",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const (
|
||||
reg = byte(0x01)
|
||||
want = byte(0x02)
|
||||
)
|
||||
msc.dataSlice = []byte{want}
|
||||
// act
|
||||
got, err := d.ReadByteData(reg)
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, got, want)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
|
||||
gobottest.Assert(t, msc.smbus.command, reg)
|
||||
gobottest.Assert(t, msc.smbus.size, uint32(I2C_SMBUS_BYTE_DATA))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteByteDataNotSupported(t *testing.T) {
|
||||
SetSyscall(&MockSyscall{})
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
err = i.WriteByteData(0x01, 0x01)
|
||||
gobottest.Assert(t, err.Error(), "SMBus write byte data not supported")
|
||||
func TestReadWordData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"read_word_data_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_WORD_DATA,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_WORD_DATA,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
"error_not_supported": {
|
||||
wantErr: "SMBus read word data not supported",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const (
|
||||
reg = byte(0x02)
|
||||
msbyte = byte(0xD4)
|
||||
lsbyte = byte(0x31)
|
||||
want = uint16(54321)
|
||||
)
|
||||
// all common drivers read LSByte first
|
||||
msc.dataSlice = []byte{lsbyte, msbyte}
|
||||
// act
|
||||
got, err := d.ReadWordData(reg)
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, got, want)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
|
||||
gobottest.Assert(t, msc.smbus.command, reg)
|
||||
gobottest.Assert(t, msc.smbus.size, uint32(I2C_SMBUS_WORD_DATA))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceReadWordData(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
i.funcs = I2C_FUNC_SMBUS_READ_WORD_DATA
|
||||
|
||||
v, e := i.ReadWordData(0x01)
|
||||
gobottest.Assert(t, v, uint16(0))
|
||||
gobottest.Assert(t, e, nil)
|
||||
func TestReadBlockData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"read_block_data_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_BLOCK_DATA,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_READ_BLOCK_DATA,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
"error_from_used_fallback_if_not_supported": {
|
||||
wantErr: "Read 1 bytes from device by sysfs, expected 3",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const (
|
||||
reg = byte(0x03)
|
||||
wantByte0 = byte(0x11)
|
||||
wantByte1 = byte(0x22)
|
||||
wantByte2 = byte(0x33)
|
||||
)
|
||||
msc.dataSlice = []byte{wantByte0, wantByte1, wantByte2}
|
||||
wantSize := uint32(len(msc.dataSlice) + 1) // register is also part of send data
|
||||
buf := []byte{17, 28, 39}
|
||||
// act
|
||||
err := d.ReadBlockData(reg, buf)
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, buf, msc.dataSlice)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_READ))
|
||||
gobottest.Assert(t, msc.smbus.command, reg)
|
||||
gobottest.Assert(t, msc.smbus.size, wantSize)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceReadWordDataNotSupported(t *testing.T) {
|
||||
SetSyscall(&MockSyscall{})
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
_, err = i.ReadWordData(0x01)
|
||||
gobottest.Assert(t, err.Error(), "SMBus read word data not supported")
|
||||
func TestWriteByte(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"write_byte_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_BYTE,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_BYTE,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
"error_not_supported": {
|
||||
wantErr: "SMBus write byte not supported",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const val = byte(0x44)
|
||||
// act
|
||||
err := d.WriteByte(val)
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
|
||||
gobottest.Assert(t, msc.smbus.command, val) // in byte write, the register/command is used for the value
|
||||
gobottest.Assert(t, msc.smbus.size, uint32(I2C_SMBUS_BYTE))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteWordData(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
i.funcs = I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
||||
|
||||
e := i.WriteWordData(0x01, 0x0102)
|
||||
gobottest.Assert(t, e, nil)
|
||||
func TestWriteByteData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"write_byte_data_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
"error_not_supported": {
|
||||
wantErr: "SMBus write byte data not supported",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const (
|
||||
reg = byte(0x04)
|
||||
val = byte(0x55)
|
||||
)
|
||||
// act
|
||||
err := d.WriteByteData(reg, val)
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
|
||||
gobottest.Assert(t, msc.smbus.command, reg)
|
||||
gobottest.Assert(t, msc.smbus.size, uint32(I2C_SMBUS_BYTE_DATA))
|
||||
gobottest.Assert(t, len(msc.dataSlice), 1)
|
||||
gobottest.Assert(t, msc.dataSlice[0], val)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteWordDataNotSupported(t *testing.T) {
|
||||
SetSyscall(&MockSyscall{})
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
err = i.WriteWordData(0x01, 0x01)
|
||||
gobottest.Assert(t, err.Error(), "SMBus write word data not supported")
|
||||
func TestWriteWordData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"write_word_data_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_WORD_DATA,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_WORD_DATA,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
"error_not_supported": {
|
||||
wantErr: "SMBus write word data not supported",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const (
|
||||
reg = byte(0x05)
|
||||
val = uint16(54321)
|
||||
wantLSByte = byte(0x31)
|
||||
wantMSByte = byte(0xD4)
|
||||
)
|
||||
// act
|
||||
err := d.WriteWordData(reg, val)
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
|
||||
gobottest.Assert(t, msc.smbus.command, reg)
|
||||
gobottest.Assert(t, msc.smbus.size, uint32(I2C_SMBUS_WORD_DATA))
|
||||
gobottest.Assert(t, len(msc.dataSlice), 2)
|
||||
// all common drivers write LSByte first
|
||||
gobottest.Assert(t, msc.dataSlice[0], wantLSByte)
|
||||
gobottest.Assert(t, msc.dataSlice[1], wantMSByte)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteBlockData(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
e := i.WriteBlockData(0x01, []byte{0x01, 0x02, 0x03})
|
||||
gobottest.Assert(t, e, nil)
|
||||
func TestWriteBlockData(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
funcs uint64
|
||||
syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
wantErr string
|
||||
}{
|
||||
"write_word_data_ok": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
|
||||
},
|
||||
"error_syscall": {
|
||||
funcs: I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
|
||||
syscallImpl: func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 1 },
|
||||
wantErr: "Failed with syscall.Errno operation not permitted",
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// arrange
|
||||
d, msc := initTestI2cDeviceWithMockedSys()
|
||||
defer cleanTestI2cDevice()
|
||||
msc.Impl = tc.syscallImpl
|
||||
d.funcs = tc.funcs
|
||||
const (
|
||||
reg = byte(0x06)
|
||||
byte0 = byte(0x66)
|
||||
byte1 = byte(0x77)
|
||||
byte2 = byte(0x88)
|
||||
)
|
||||
data := []byte{byte0, byte1, byte2}
|
||||
wantSize := uint32(len(data) + 1) // register is also part of send data
|
||||
// act
|
||||
err := d.WriteBlockData(reg, data)
|
||||
// assert
|
||||
if tc.wantErr != "" {
|
||||
gobottest.Refute(t, err, nil)
|
||||
gobottest.Assert(t, err.Error(), tc.wantErr)
|
||||
} else {
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, msc.lastFile, d.file)
|
||||
gobottest.Assert(t, msc.lastSignal, uintptr(I2C_SMBUS))
|
||||
gobottest.Assert(t, msc.smbus.readWrite, byte(I2C_SMBUS_WRITE))
|
||||
gobottest.Assert(t, msc.smbus.command, reg)
|
||||
gobottest.Assert(t, msc.smbus.size, wantSize)
|
||||
gobottest.Assert(t, msc.dataSlice, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWriteBlockDataTooMuch(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/dev/i2c-1",
|
||||
})
|
||||
SetFilesystem(fs)
|
||||
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
|
||||
var data []byte
|
||||
data = make([]byte, 33)
|
||||
e := i.WriteBlockData(0x01, data)
|
||||
gobottest.Assert(t, e, errors.New("Writing blocks larger than 32 bytes (33) not supported"))
|
||||
}
|
||||
|
||||
func TestNewI2cDeviceWrite(t *testing.T) {
|
||||
SetSyscall(&MockSyscall{})
|
||||
i, err := NewI2cDevice("/dev/i2c-1")
|
||||
var _ i2c.I2cDevice = i
|
||||
|
||||
gobottest.Assert(t, err, nil)
|
||||
|
||||
i.SetAddress(0xff)
|
||||
buf := []byte{0x01, 0x02, 0x03}
|
||||
|
||||
n, err := i.Write(buf)
|
||||
|
||||
gobottest.Assert(t, n, len(buf))
|
||||
gobottest.Assert(t, err, nil)
|
||||
func TestWriteBlockDataTooMuch(t *testing.T) {
|
||||
// arrange
|
||||
SetFilesystem(NewMockFilesystem([]string{dev}))
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
d, _ := NewI2cDevice(dev)
|
||||
// act
|
||||
err := d.WriteBlockData(0x01, make([]byte, 33))
|
||||
// assert
|
||||
gobottest.Assert(t, err, errors.New("Writing blocks larger than 32 bytes (33) not supported"))
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ func TestPwmPin(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
gobottest.Assert(t, pin.pin, "10")
|
||||
@ -73,6 +74,7 @@ func TestPwmPinAlreadyExported(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.write = func(string, []byte) (int, error) {
|
||||
@ -93,6 +95,7 @@ func TestPwmPinExportError(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.write = func(string, []byte) (int, error) {
|
||||
@ -113,6 +116,7 @@ func TestPwmPinUnxportError(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.write = func(string, []byte) (int, error) {
|
||||
@ -132,6 +136,7 @@ func TestPwmPinPeriodError(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.read = func(string) ([]byte, error) {
|
||||
@ -152,6 +157,7 @@ func TestPwmPinPolarityError(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.read = func(string) ([]byte, error) {
|
||||
@ -172,6 +178,7 @@ func TestPwmPinDutyCycleError(t *testing.T) {
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
defer SetFilesystem(&NativeFilesystem{})
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.read = func(string) ([]byte, error) {
|
||||
|
@ -2,19 +2,27 @@ package sysfs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SystemCaller represents a Syscall
|
||||
// Prevent unsafe call, since go 1.15, see "Pattern 4" in: https://go101.org/article/unsafe.html
|
||||
type SystemCaller interface {
|
||||
Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
Syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err syscall.Errno)
|
||||
}
|
||||
|
||||
// NativeSyscall represents the native Syscall
|
||||
type NativeSyscall struct{}
|
||||
|
||||
// MockSyscall represents the mock Syscall
|
||||
// MockSyscall represents the mock Syscall used for unit tests
|
||||
type MockSyscall struct {
|
||||
Impl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
lastTrap uintptr
|
||||
lastFile File
|
||||
lastSignal uintptr
|
||||
devAddress uintptr
|
||||
smbus *i2cSmbusIoctlData
|
||||
dataSlice []byte
|
||||
Impl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
}
|
||||
|
||||
var sys SystemCaller = &NativeSyscall{}
|
||||
@ -25,19 +33,53 @@ func SetSyscall(s SystemCaller) {
|
||||
}
|
||||
|
||||
// Syscall calls either the NativeSyscall or user defined Syscall
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return sys.Syscall(trap, a1, a2, a3)
|
||||
func Syscall(trap uintptr, f File, a2 uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return sys.Syscall(trap, f, a2, payload)
|
||||
}
|
||||
|
||||
// Syscall calls syscall.Syscall
|
||||
func (sys *NativeSyscall) Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return syscall.Syscall(trap, a1, a2, a3)
|
||||
// Syscall calls the native syscall.Syscall, implements the SystemCaller interface
|
||||
func (sys *NativeSyscall) Syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return syscall.Syscall(trap, f.Fd(), signal, uintptr(payload))
|
||||
}
|
||||
|
||||
// Syscall implements the SystemCaller interface
|
||||
func (sys *MockSyscall) Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
// Syscall calls the user defined implementation, used for tests, implements the SystemCaller interface
|
||||
func (sys *MockSyscall) Syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err syscall.Errno) {
|
||||
sys.lastTrap = trap // points to the used syscall (e.g. "SYS_IOCTL")
|
||||
sys.lastFile = f // a character device file (e.g. file to path "/dev/i2c-1")
|
||||
sys.lastSignal = signal // points to used function type (e.g. I2C_SMBUS, I2C_RDWR)
|
||||
|
||||
if signal == I2C_SLAVE {
|
||||
// in this case the uintptr corresponds the address
|
||||
sys.devAddress = uintptr(payload)
|
||||
}
|
||||
|
||||
if signal == I2C_SMBUS {
|
||||
// set the I2C smbus data object reference to payload and fill with some data
|
||||
sys.smbus = (*i2cSmbusIoctlData)(payload)
|
||||
|
||||
// get the data object payload as byte slice
|
||||
if sys.smbus.readWrite == I2C_SMBUS_WRITE {
|
||||
if sys.smbus.data != nil {
|
||||
sys.dataSlice = unsafe.Slice((*byte)(unsafe.Pointer(sys.smbus.data)), sys.smbus.size-1)
|
||||
}
|
||||
}
|
||||
|
||||
// fill data object with data from given slice to simulate reading
|
||||
if sys.smbus.readWrite == I2C_SMBUS_READ {
|
||||
if sys.dataSlice != nil {
|
||||
dataSize := sys.smbus.size - 1
|
||||
if sys.smbus.size == I2C_SMBUS_BYTE {
|
||||
dataSize = 1
|
||||
}
|
||||
slc := unsafe.Slice((*byte)(unsafe.Pointer(sys.smbus.data)), dataSize)
|
||||
copy(slc, sys.dataSlice)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call mock implementation
|
||||
if sys.Impl != nil {
|
||||
return sys.Impl(trap, a1, a2, a3)
|
||||
return sys.Impl(trap, f.Fd(), signal, uintptr(unsafe.Pointer(payload)))
|
||||
}
|
||||
return 0, 0, 0
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user