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  }