gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/l3gd20h_driver_test.go (about) 1 package i2c 2 3 import ( 4 "errors" 5 "strings" 6 "testing" 7 8 "gobot.io/x/gobot/v2" 9 "gobot.io/x/gobot/v2/gobottest" 10 ) 11 12 // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver 13 // and tests all implementations, so no further tests needed here for gobot.Driver interface 14 var _ gobot.Driver = (*HMC6352Driver)(nil) 15 16 func initL3GD20HDriver() (driver *L3GD20HDriver) { 17 driver, _ = initL3GD20HWithStubbedAdaptor() 18 return 19 } 20 21 func initL3GD20HWithStubbedAdaptor() (*L3GD20HDriver, *i2cTestAdaptor) { 22 a := newI2cTestAdaptor() 23 d := NewL3GD20HDriver(a) 24 if err := d.Start(); err != nil { 25 panic(err) 26 } 27 return d, a 28 } 29 30 func TestNewL3GD20HDriver(t *testing.T) { 31 var di interface{} = NewL3GD20HDriver(newI2cTestAdaptor()) 32 d, ok := di.(*L3GD20HDriver) 33 if !ok { 34 t.Errorf("NewL3GD20HDriver() should have returned a *L3GD20HDriver") 35 } 36 gobottest.Refute(t, d.Driver, nil) 37 gobottest.Assert(t, strings.HasPrefix(d.Name(), "L3GD20H"), true) 38 gobottest.Assert(t, d.defaultAddress, 0x6b) 39 gobottest.Assert(t, d.Scale(), L3GD20HScale250dps) 40 } 41 42 func TestL3GD20HOptions(t *testing.T) { 43 // This is a general test, that options are applied in constructor by using the common WithBus() option. 44 // Further tests for options can also be done by call of "WithOption(val)(d)". 45 d := NewL3GD20HDriver(newI2cTestAdaptor(), WithBus(2)) 46 gobottest.Assert(t, d.GetBusOrDefault(1), 2) 47 } 48 49 func TestL3GD20HWithL3GD20HFullScaleRange(t *testing.T) { 50 var tests = map[string]struct { 51 scale L3GD20HScale 52 want uint8 53 }{ 54 "250dps": { 55 scale: L3GD20HScale250dps, 56 want: 0x00, 57 }, 58 "500dps": { 59 scale: L3GD20HScale500dps, 60 want: 0x10, 61 }, 62 "2001dps": { 63 scale: L3GD20HScale2001dps, 64 want: 0x20, 65 }, 66 "2000dps": { 67 scale: L3GD20HScale2000dps, 68 want: 0x30, 69 }, 70 } 71 for name, tc := range tests { 72 t.Run(name, func(t *testing.T) { 73 // arrange 74 d := initL3GD20HDriver() 75 // act 76 WithL3GD20HFullScaleRange(tc.scale)(d) 77 // assert 78 gobottest.Assert(t, d.scale, L3GD20HScale(tc.want)) 79 }) 80 } 81 } 82 83 func TestL3GD20HScale(t *testing.T) { 84 var tests = map[string]struct { 85 scale L3GD20HScale 86 want uint8 87 }{ 88 "250dps": { 89 scale: L3GD20HScale250dps, 90 want: 0x00, 91 }, 92 "500dps": { 93 scale: L3GD20HScale500dps, 94 want: 0x10, 95 }, 96 "2001dps": { 97 scale: L3GD20HScale2001dps, 98 want: 0x20, 99 }, 100 "2000dps": { 101 scale: L3GD20HScale2000dps, 102 want: 0x30, 103 }, 104 } 105 for name, tc := range tests { 106 t.Run(name, func(t *testing.T) { 107 // arrange 108 d := initL3GD20HDriver() 109 // act 110 d.SetScale(tc.scale) 111 // assert 112 gobottest.Assert(t, d.scale, L3GD20HScale(tc.want)) 113 }) 114 } 115 } 116 117 func TestL3GD20HFullScaleRange(t *testing.T) { 118 // sequence to read full scale range 119 // * write control register 4 (0x23) 120 // * read content and filter FS bits (bit 4, bit 5) 121 // 122 // arrange 123 d, a := initL3GD20HWithStubbedAdaptor() 124 a.written = []byte{} // reset values from Start() and previous tests 125 readValue := uint8(0x10) 126 a.i2cReadImpl = func(b []byte) (int, error) { 127 b[0] = readValue 128 return len(b), nil 129 } 130 // act 131 got, err := d.FullScaleRange() 132 // assert 133 gobottest.Assert(t, err, nil) 134 gobottest.Assert(t, len(a.written), 1) 135 gobottest.Assert(t, a.written[0], uint8(0x23)) 136 gobottest.Assert(t, got, readValue) 137 } 138 139 func TestL3GD20HMeasurement(t *testing.T) { 140 // sequence for measurement 141 // note: big endian transfer is configured (LSB in lower address, transferred first) 142 // 143 // * write X-axis angular rate data LSB register (0x28) with auto increment bit set (0xA8) 144 // * read 3 x 2 bytes X, Y, Z data, big-endian (LSB, MSB) 145 // * scale values by configured range (sensitivity = 1/gain) 146 // 147 // data table according to data sheet AN4506 example in table 7, supplemented with FS limit values 148 sensitivity := float32(0.00875) // FS=245 dps 149 var tests = map[string]struct { 150 gyroData []byte 151 wantX float32 152 wantY float32 153 wantZ float32 154 }{ 155 "245_200_100dps": { 156 gyroData: []byte{0x60, 0x6D, 0x49, 0x59, 0xA4, 0x2C}, 157 wantX: 245, 158 wantY: 199.99875, 159 wantZ: 99.995, 160 }, 161 "-100_-200_-245dps": { 162 gyroData: []byte{0x5C, 0xD3, 0xB7, 0xA6, 0xA0, 0x92}, 163 wantX: -99.995, 164 wantY: -199.99875, 165 wantZ: -245, 166 }, 167 "1_0_-1": { 168 gyroData: []byte{0x72, 0x00, 0x00, 0x00, 0x8D, 0xFF}, 169 wantX: 0.9975, 170 wantY: 0, 171 wantZ: -1.00625, 172 }, 173 "raw_range_int16_-32768_0_+32767": { 174 gyroData: []byte{0x00, 0x80, 0x00, 0x00, 0xFF, 0x7F}, 175 wantX: -286.72, 176 wantY: 0, 177 wantZ: 286.71124, 178 }, 179 "raw_8_5_-3": { 180 gyroData: []byte{0x08, 0x00, 0x05, 0x00, 0xFD, 0xFF}, 181 wantX: float32(8) * sensitivity, 182 wantY: float32(5) * sensitivity, 183 wantZ: float32(-3) * sensitivity, 184 }, 185 } 186 187 for name, tc := range tests { 188 t.Run(name, func(t *testing.T) { 189 // arrange 190 d, a := initL3GD20HWithStubbedAdaptor() 191 a.written = []byte{} // reset values from Start() and previous tests 192 a.i2cReadImpl = func(b []byte) (int, error) { 193 copy(b, tc.gyroData) 194 return len(b), nil 195 } 196 // act 197 x, y, z, err := d.XYZ() 198 // assert 199 gobottest.Assert(t, err, nil) 200 gobottest.Assert(t, len(a.written), 1) 201 gobottest.Assert(t, a.written[0], uint8(0xA8)) 202 gobottest.Assert(t, x, tc.wantX) 203 gobottest.Assert(t, y, tc.wantY) 204 gobottest.Assert(t, z, tc.wantZ) 205 }) 206 } 207 } 208 209 func TestL3GD20HMeasurementError(t *testing.T) { 210 d, a := initL3GD20HWithStubbedAdaptor() 211 a.i2cReadImpl = func(b []byte) (int, error) { 212 return 0, errors.New("read error") 213 } 214 215 d.Start() 216 _, _, _, err := d.XYZ() 217 gobottest.Assert(t, err, errors.New("read error")) 218 } 219 220 func TestL3GD20HMeasurementWriteError(t *testing.T) { 221 d, a := initL3GD20HWithStubbedAdaptor() 222 a.i2cWriteImpl = func(b []byte) (int, error) { 223 return 0, errors.New("write error") 224 } 225 _, _, _, err := d.XYZ() 226 gobottest.Assert(t, err, errors.New("write error")) 227 } 228 229 func TestL3GD20H_initialize(t *testing.T) { 230 // sequence for initialization the device on Start() 231 // * write control register 1 (0x20) 232 // * write reset (0x00) 233 // * write control register 1 (0x20) 234 // * prepare register content: 235 // * output data rate for no Low_ODR=100Hz (DR=0x00) 236 // * bandwidth for no Low_ODR=12.5Hz (BW=0x00) 237 // * normal mode and enable all axes (PD=1, X/Y/Z=1) 238 // * write register content (0x0F) 239 // * write control register 4 (0x23) 240 // * prepare register content 241 // * continuous block data update (BDU=0x00) 242 // * use big endian transfer (LSB in lower address, transferred first) (BLE=0x00) 243 // * set full scale selection to configured scale (default=245dps, FS=0x00) 244 // * normal self test (ST=0x00) 245 // * SPI mode to 4 wire (SIM=0x00) 246 // * write register content (0x00) 247 // 248 // all other registers currently untouched 249 // 250 // arrange, act - initialize() must be called on Start() 251 _, a := initL3GD20HWithStubbedAdaptor() 252 // assert 253 gobottest.Assert(t, len(a.written), 6) 254 gobottest.Assert(t, a.written[0], uint8(0x20)) 255 gobottest.Assert(t, a.written[1], uint8(0x00)) 256 gobottest.Assert(t, a.written[2], uint8(0x20)) 257 gobottest.Assert(t, a.written[3], uint8(0x0F)) 258 gobottest.Assert(t, a.written[4], uint8(0x23)) 259 gobottest.Assert(t, a.written[5], uint8(0x00)) 260 }