mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-24 13:48:49 +08:00
361 lines
10 KiB
Go
361 lines
10 KiB
Go
//go:build libusb
|
|
// +build libusb
|
|
|
|
//nolint:forcetypeassert // ok here
|
|
package digispark
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"gobot.io/x/gobot/v2/drivers/i2c"
|
|
)
|
|
|
|
const (
|
|
availableI2cAddress = 0x40
|
|
maxUint8 = ^uint8(0)
|
|
)
|
|
|
|
var (
|
|
_ i2c.Connector = (*Adaptor)(nil)
|
|
i2cData = []byte{5, 4, 3, 2, 1, 0}
|
|
)
|
|
|
|
type i2cMock struct {
|
|
duration uint
|
|
direction uint8
|
|
dataWritten []byte
|
|
writeStartWasSend bool
|
|
writeStopWasSend bool
|
|
readStartWasSend bool
|
|
readStopWasSend bool
|
|
}
|
|
|
|
func initTestAdaptorI2c() *Adaptor {
|
|
a := NewAdaptor()
|
|
a.connect = func(a *Adaptor) error { return nil }
|
|
a.littleWire = new(i2cMock)
|
|
return a
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cGetI2cConnection(t *testing.T) {
|
|
// arrange
|
|
var c i2c.Connection
|
|
var err error
|
|
a := initTestAdaptorI2c()
|
|
|
|
// act
|
|
c, err = a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, c)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cGetI2cConnectionFailWithInvalidBus(t *testing.T) {
|
|
// arrange
|
|
a := initTestAdaptorI2c()
|
|
|
|
// act
|
|
c, err := a.GetI2cConnection(0x40, 1)
|
|
|
|
// assert
|
|
require.ErrorContains(t, err, "Invalid bus number 1, only 0 is supported")
|
|
assert.Nil(t, c)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cStartFailWithWrongAddress(t *testing.T) {
|
|
// arrange
|
|
data := []byte{0, 1, 2, 3, 4}
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(0x39, a.DefaultI2cBus())
|
|
|
|
// act
|
|
count, err := c.Write(data)
|
|
|
|
// assert
|
|
assert.Equal(t, 0, count)
|
|
require.ErrorContains(t, err, fmt.Sprintf("Invalid address, only %d is supported", availableI2cAddress))
|
|
assert.Equal(t, maxUint8, a.littleWire.(*i2cMock).direction)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cWrite(t *testing.T) {
|
|
// arrange
|
|
data := []byte{0, 1, 2, 3, 4}
|
|
dataLen := len(data)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
count, err := c.Write(data)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, dataLen, count)
|
|
assert.Equal(t, data, a.littleWire.(*i2cMock).dataWritten)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cWriteByte(t *testing.T) {
|
|
// arrange
|
|
data := byte(0x02)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
err := c.WriteByte(data)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, []byte{data}, a.littleWire.(*i2cMock).dataWritten)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cWriteByteData(t *testing.T) {
|
|
// arrange
|
|
reg := uint8(0x03)
|
|
data := byte(0x09)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
err := c.WriteByteData(reg, data)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, []byte{reg, data}, a.littleWire.(*i2cMock).dataWritten)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cWriteWordData(t *testing.T) {
|
|
// arrange
|
|
reg := uint8(0x04)
|
|
data := uint16(0x0508)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
err := c.WriteWordData(reg, data)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, []byte{reg, 0x08, 0x05}, a.littleWire.(*i2cMock).dataWritten)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cWriteBlockData(t *testing.T) {
|
|
// arrange
|
|
reg := uint8(0x05)
|
|
data := []byte{0x80, 0x81, 0x82}
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
err := c.WriteBlockData(reg, data)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(0), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, append([]byte{reg}, data...), a.littleWire.(*i2cMock).dataWritten)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.False(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cRead(t *testing.T) {
|
|
// arrange
|
|
data := []byte{0, 1, 2, 3, 4}
|
|
dataLen := len(data)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
count, err := c.Read(data)
|
|
|
|
// assert
|
|
assert.Equal(t, dataLen, count)
|
|
require.NoError(t, err)
|
|
assert.False(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, i2cData[:dataLen], data)
|
|
assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cReadByte(t *testing.T) {
|
|
// arrange
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
data, err := c.ReadByte()
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.False(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, i2cData[0], data)
|
|
assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cReadByteData(t *testing.T) {
|
|
// arrange
|
|
reg := uint8(0x04)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
data, err := c.ReadByteData(reg)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, []byte{reg}, a.littleWire.(*i2cMock).dataWritten)
|
|
assert.Equal(t, i2cData[0], data)
|
|
assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cReadWordData(t *testing.T) {
|
|
// arrange
|
|
reg := uint8(0x05)
|
|
// 2 bytes of i2cData are used swapped
|
|
expectedValue := uint16(0x0405)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
data, err := c.ReadWordData(reg)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, []byte{reg}, a.littleWire.(*i2cMock).dataWritten)
|
|
assert.Equal(t, expectedValue, data)
|
|
assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cReadBlockData(t *testing.T) {
|
|
// arrange
|
|
reg := uint8(0x05)
|
|
data := []byte{0, 0, 0, 0, 0}
|
|
dataLen := len(data)
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
err := c.ReadBlockData(reg, data)
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.True(t, a.littleWire.(*i2cMock).writeStartWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStartWasSend)
|
|
assert.Equal(t, uint8(1), a.littleWire.(*i2cMock).direction)
|
|
assert.Equal(t, []byte{reg}, a.littleWire.(*i2cMock).dataWritten)
|
|
assert.Equal(t, i2cData[:dataLen], data)
|
|
assert.False(t, a.littleWire.(*i2cMock).writeStopWasSend)
|
|
assert.True(t, a.littleWire.(*i2cMock).readStopWasSend)
|
|
}
|
|
|
|
func TestDigisparkAdaptorI2cUpdateDelay(t *testing.T) {
|
|
// arrange
|
|
a := initTestAdaptorI2c()
|
|
c, _ := a.GetI2cConnection(availableI2cAddress, a.DefaultI2cBus())
|
|
|
|
// act
|
|
err := c.(*digisparkI2cConnection).UpdateDelay(uint(100))
|
|
|
|
// assert
|
|
require.NoError(t, err)
|
|
assert.Equal(t, uint(100), a.littleWire.(*i2cMock).duration)
|
|
}
|
|
|
|
// setup mock for i2c tests
|
|
func (l *i2cMock) i2cInit() error {
|
|
l.direction = maxUint8
|
|
return l.error()
|
|
}
|
|
|
|
func (l *i2cMock) i2cStart(address7bit uint8, direction uint8) error {
|
|
if address7bit != availableI2cAddress {
|
|
return fmt.Errorf("Invalid address, only %d is supported", availableI2cAddress)
|
|
}
|
|
if err := l.error(); err != nil {
|
|
return err
|
|
}
|
|
l.direction = direction
|
|
if direction == 1 {
|
|
l.readStartWasSend = true
|
|
} else {
|
|
l.writeStartWasSend = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (l *i2cMock) i2cWrite(sendBuffer []byte, length int, endWithStop uint8) error {
|
|
l.dataWritten = append(l.dataWritten, sendBuffer...)
|
|
if endWithStop > 0 {
|
|
l.writeStopWasSend = true
|
|
}
|
|
return l.error()
|
|
}
|
|
|
|
func (l *i2cMock) i2cRead(readBuffer []byte, length int, endWithStop uint8) error {
|
|
if len(readBuffer) < length {
|
|
length = len(readBuffer)
|
|
}
|
|
if len(i2cData) < length {
|
|
length = len(i2cData)
|
|
}
|
|
copy(readBuffer[:length], i2cData[:length])
|
|
|
|
if endWithStop > 0 {
|
|
l.readStopWasSend = true
|
|
}
|
|
return l.error()
|
|
}
|
|
|
|
func (l *i2cMock) i2cUpdateDelay(duration uint) error {
|
|
l.duration = duration
|
|
return l.error()
|
|
}
|
|
|
|
// GPIO, PWM and servo functions unused in this test scenarios
|
|
func (l *i2cMock) digitalWrite(pin uint8, state uint8) error { return nil }
|
|
func (l *i2cMock) pinMode(pin uint8, mode uint8) error { return nil }
|
|
func (l *i2cMock) pwmInit() error { return nil }
|
|
func (l *i2cMock) pwmStop() error { return nil }
|
|
func (l *i2cMock) pwmUpdateCompare(channelA uint8, channelB uint8) error { return nil }
|
|
func (l *i2cMock) pwmUpdatePrescaler(value uint) error { return nil }
|
|
func (l *i2cMock) servoInit() error { return nil }
|
|
func (l *i2cMock) servoUpdateLocation(locationA uint8, locationB uint8) error { return nil }
|
|
func (l *i2cMock) error() error { return nil }
|