261 lines
7.0 KiB
Go
261 lines
7.0 KiB
Go
package i2c
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gobot.io/x/gobot/v2"
|
|
"gobot.io/x/gobot/v2/gobottest"
|
|
)
|
|
|
|
// this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver
|
|
// and tests all implementations, so no further tests needed here for gobot.Driver interface
|
|
var _ gobot.Driver = (*HMC6352Driver)(nil)
|
|
|
|
func initL3GD20HDriver() (driver *L3GD20HDriver) {
|
|
driver, _ = initL3GD20HWithStubbedAdaptor()
|
|
return
|
|
}
|
|
|
|
func initL3GD20HWithStubbedAdaptor() (*L3GD20HDriver, *i2cTestAdaptor) {
|
|
a := newI2cTestAdaptor()
|
|
d := NewL3GD20HDriver(a)
|
|
if err := d.Start(); err != nil {
|
|
panic(err)
|
|
}
|
|
return d, a
|
|
}
|
|
|
|
func TestNewL3GD20HDriver(t *testing.T) {
|
|
var di interface{} = NewL3GD20HDriver(newI2cTestAdaptor())
|
|
d, ok := di.(*L3GD20HDriver)
|
|
if !ok {
|
|
t.Errorf("NewL3GD20HDriver() should have returned a *L3GD20HDriver")
|
|
}
|
|
gobottest.Refute(t, d.Driver, nil)
|
|
gobottest.Assert(t, strings.HasPrefix(d.Name(), "L3GD20H"), true)
|
|
gobottest.Assert(t, d.defaultAddress, 0x6b)
|
|
gobottest.Assert(t, d.Scale(), L3GD20HScale250dps)
|
|
}
|
|
|
|
func TestL3GD20HOptions(t *testing.T) {
|
|
// This is a general test, that options are applied in constructor by using the common WithBus() option.
|
|
// Further tests for options can also be done by call of "WithOption(val)(d)".
|
|
d := NewL3GD20HDriver(newI2cTestAdaptor(), WithBus(2))
|
|
gobottest.Assert(t, d.GetBusOrDefault(1), 2)
|
|
}
|
|
|
|
func TestL3GD20HWithL3GD20HFullScaleRange(t *testing.T) {
|
|
var tests = map[string]struct {
|
|
scale L3GD20HScale
|
|
want uint8
|
|
}{
|
|
"250dps": {
|
|
scale: L3GD20HScale250dps,
|
|
want: 0x00,
|
|
},
|
|
"500dps": {
|
|
scale: L3GD20HScale500dps,
|
|
want: 0x10,
|
|
},
|
|
"2001dps": {
|
|
scale: L3GD20HScale2001dps,
|
|
want: 0x20,
|
|
},
|
|
"2000dps": {
|
|
scale: L3GD20HScale2000dps,
|
|
want: 0x30,
|
|
},
|
|
}
|
|
for name, tc := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
// arrange
|
|
d := initL3GD20HDriver()
|
|
// act
|
|
WithL3GD20HFullScaleRange(tc.scale)(d)
|
|
// assert
|
|
gobottest.Assert(t, d.scale, L3GD20HScale(tc.want))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestL3GD20HScale(t *testing.T) {
|
|
var tests = map[string]struct {
|
|
scale L3GD20HScale
|
|
want uint8
|
|
}{
|
|
"250dps": {
|
|
scale: L3GD20HScale250dps,
|
|
want: 0x00,
|
|
},
|
|
"500dps": {
|
|
scale: L3GD20HScale500dps,
|
|
want: 0x10,
|
|
},
|
|
"2001dps": {
|
|
scale: L3GD20HScale2001dps,
|
|
want: 0x20,
|
|
},
|
|
"2000dps": {
|
|
scale: L3GD20HScale2000dps,
|
|
want: 0x30,
|
|
},
|
|
}
|
|
for name, tc := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
// arrange
|
|
d := initL3GD20HDriver()
|
|
// act
|
|
d.SetScale(tc.scale)
|
|
// assert
|
|
gobottest.Assert(t, d.scale, L3GD20HScale(tc.want))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestL3GD20HFullScaleRange(t *testing.T) {
|
|
// sequence to read full scale range
|
|
// * write control register 4 (0x23)
|
|
// * read content and filter FS bits (bit 4, bit 5)
|
|
//
|
|
// arrange
|
|
d, a := initL3GD20HWithStubbedAdaptor()
|
|
a.written = []byte{} // reset values from Start() and previous tests
|
|
readValue := uint8(0x10)
|
|
a.i2cReadImpl = func(b []byte) (int, error) {
|
|
b[0] = readValue
|
|
return len(b), nil
|
|
}
|
|
// act
|
|
got, err := d.FullScaleRange()
|
|
// assert
|
|
gobottest.Assert(t, err, nil)
|
|
gobottest.Assert(t, len(a.written), 1)
|
|
gobottest.Assert(t, a.written[0], uint8(0x23))
|
|
gobottest.Assert(t, got, readValue)
|
|
}
|
|
|
|
func TestL3GD20HMeasurement(t *testing.T) {
|
|
// sequence for measurement
|
|
// note: big endian transfer is configured (LSB in lower address, transferred first)
|
|
//
|
|
// * write X-axis angular rate data LSB register (0x28) with auto increment bit set (0xA8)
|
|
// * read 3 x 2 bytes X, Y, Z data, big-endian (LSB, MSB)
|
|
// * scale values by configured range (sensitivity = 1/gain)
|
|
//
|
|
// data table according to data sheet AN4506 example in table 7, supplemented with FS limit values
|
|
sensitivity := float32(0.00875) // FS=245 dps
|
|
var tests = map[string]struct {
|
|
gyroData []byte
|
|
wantX float32
|
|
wantY float32
|
|
wantZ float32
|
|
}{
|
|
"245_200_100dps": {
|
|
gyroData: []byte{0x60, 0x6D, 0x49, 0x59, 0xA4, 0x2C},
|
|
wantX: 245,
|
|
wantY: 199.99875,
|
|
wantZ: 99.995,
|
|
},
|
|
"-100_-200_-245dps": {
|
|
gyroData: []byte{0x5C, 0xD3, 0xB7, 0xA6, 0xA0, 0x92},
|
|
wantX: -99.995,
|
|
wantY: -199.99875,
|
|
wantZ: -245,
|
|
},
|
|
"1_0_-1": {
|
|
gyroData: []byte{0x72, 0x00, 0x00, 0x00, 0x8D, 0xFF},
|
|
wantX: 0.9975,
|
|
wantY: 0,
|
|
wantZ: -1.00625,
|
|
},
|
|
"raw_range_int16_-32768_0_+32767": {
|
|
gyroData: []byte{0x00, 0x80, 0x00, 0x00, 0xFF, 0x7F},
|
|
wantX: -286.72,
|
|
wantY: 0,
|
|
wantZ: 286.71124,
|
|
},
|
|
"raw_8_5_-3": {
|
|
gyroData: []byte{0x08, 0x00, 0x05, 0x00, 0xFD, 0xFF},
|
|
wantX: float32(8) * sensitivity,
|
|
wantY: float32(5) * sensitivity,
|
|
wantZ: float32(-3) * sensitivity,
|
|
},
|
|
}
|
|
|
|
for name, tc := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
// arrange
|
|
d, a := initL3GD20HWithStubbedAdaptor()
|
|
a.written = []byte{} // reset values from Start() and previous tests
|
|
a.i2cReadImpl = func(b []byte) (int, error) {
|
|
copy(b, tc.gyroData)
|
|
return len(b), nil
|
|
}
|
|
// act
|
|
x, y, z, err := d.XYZ()
|
|
// assert
|
|
gobottest.Assert(t, err, nil)
|
|
gobottest.Assert(t, len(a.written), 1)
|
|
gobottest.Assert(t, a.written[0], uint8(0xA8))
|
|
gobottest.Assert(t, x, tc.wantX)
|
|
gobottest.Assert(t, y, tc.wantY)
|
|
gobottest.Assert(t, z, tc.wantZ)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestL3GD20HMeasurementError(t *testing.T) {
|
|
d, a := initL3GD20HWithStubbedAdaptor()
|
|
a.i2cReadImpl = func(b []byte) (int, error) {
|
|
return 0, errors.New("read error")
|
|
}
|
|
|
|
_ = d.Start()
|
|
_, _, _, err := d.XYZ()
|
|
gobottest.Assert(t, err, errors.New("read error"))
|
|
}
|
|
|
|
func TestL3GD20HMeasurementWriteError(t *testing.T) {
|
|
d, a := initL3GD20HWithStubbedAdaptor()
|
|
a.i2cWriteImpl = func(b []byte) (int, error) {
|
|
return 0, errors.New("write error")
|
|
}
|
|
_, _, _, err := d.XYZ()
|
|
gobottest.Assert(t, err, errors.New("write error"))
|
|
}
|
|
|
|
func TestL3GD20H_initialize(t *testing.T) {
|
|
// sequence for initialization the device on Start()
|
|
// * write control register 1 (0x20)
|
|
// * write reset (0x00)
|
|
// * write control register 1 (0x20)
|
|
// * prepare register content:
|
|
// * output data rate for no Low_ODR=100Hz (DR=0x00)
|
|
// * bandwidth for no Low_ODR=12.5Hz (BW=0x00)
|
|
// * normal mode and enable all axes (PD=1, X/Y/Z=1)
|
|
// * write register content (0x0F)
|
|
// * write control register 4 (0x23)
|
|
// * prepare register content
|
|
// * continuous block data update (BDU=0x00)
|
|
// * use big endian transfer (LSB in lower address, transferred first) (BLE=0x00)
|
|
// * set full scale selection to configured scale (default=245dps, FS=0x00)
|
|
// * normal self test (ST=0x00)
|
|
// * SPI mode to 4 wire (SIM=0x00)
|
|
// * write register content (0x00)
|
|
//
|
|
// all other registers currently untouched
|
|
//
|
|
// arrange, act - initialize() must be called on Start()
|
|
_, a := initL3GD20HWithStubbedAdaptor()
|
|
// assert
|
|
gobottest.Assert(t, len(a.written), 6)
|
|
gobottest.Assert(t, a.written[0], uint8(0x20))
|
|
gobottest.Assert(t, a.written[1], uint8(0x00))
|
|
gobottest.Assert(t, a.written[2], uint8(0x20))
|
|
gobottest.Assert(t, a.written[3], uint8(0x0F))
|
|
gobottest.Assert(t, a.written[4], uint8(0x23))
|
|
gobottest.Assert(t, a.written[5], uint8(0x00))
|
|
}
|