tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/mcp23017/device_test.go (about)

     1  package mcp23017
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	qt "github.com/frankban/quicktest"
     8  
     9  	"tinygo.org/x/drivers/tester"
    10  )
    11  
    12  func TestGetPins(t *testing.T) {
    13  	c := qt.New(t)
    14  	bus := tester.NewI2CBus(c)
    15  	fdev := newDevice(bus, 0x20)
    16  	fdev.Registers[rGPIO] = 0b10101100
    17  	fdev.Registers[rGPIO|portB] = 0b01010011
    18  	dev, err := NewI2C(bus, 0x20)
    19  	c.Assert(err, qt.IsNil)
    20  	pins, err := dev.GetPins()
    21  	c.Assert(err, qt.IsNil)
    22  	c.Assert(pins, qt.Equals, Pins(0b01010011_10101100))
    23  }
    24  
    25  func TestSetPins(t *testing.T) {
    26  	c := qt.New(t)
    27  	bus := tester.NewI2CBus(c)
    28  	fdev := newDevice(bus, 0x20)
    29  	fdev.Registers[rGPIO] = 0b00001111
    30  	fdev.Registers[rGPIO|portB] = 0b11110000
    31  	dev, err := NewI2C(bus, 0x20)
    32  	c.Assert(err, qt.IsNil)
    33  	pins, err := dev.GetPins()
    34  	c.Assert(err, qt.IsNil)
    35  	c.Assert(pins, qt.Equals, Pins(0b11110000_00001111))
    36  
    37  	err = dev.SetPins(0b01100000_00110000, 0b10101010_01010101)
    38  	c.Assert(err, qt.IsNil)
    39  	pins, err = dev.GetPins()
    40  	c.Assert(err, qt.IsNil)
    41  	c.Assert(pins, qt.Equals, Pins(0b01110000_0001_1010))
    42  
    43  	// The logic uses the cached value of the pins rather than
    44  	// reading it from the registers each time.
    45  	fdev.Registers[rGPIO] = 0
    46  	fdev.Registers[rGPIO|portB] = 0
    47  
    48  	err = dev.SetPins(0b01000000_00110000, 0b01100000_00000000)
    49  	c.Assert(err, qt.IsNil)
    50  	pins, err = dev.GetPins()
    51  	c.Assert(err, qt.IsNil)
    52  	c.Assert(pins, qt.Equals, Pins(0b01010000_00011010))
    53  }
    54  
    55  func TestTogglePins(t *testing.T) {
    56  	c := qt.New(t)
    57  	bus := tester.NewI2CBus(c)
    58  	fdev := newDevice(bus, 0x20)
    59  	fdev.Registers[rGPIO] = 0b00001111
    60  	fdev.Registers[rGPIO|portB] = 0b11110000
    61  	dev, err := NewI2C(bus, 0x20)
    62  	c.Assert(err, qt.IsNil)
    63  	pins, err := dev.GetPins()
    64  	c.Assert(err, qt.IsNil)
    65  	c.Assert(pins, qt.Equals, Pins(0b11110000_00001111))
    66  
    67  	err = dev.TogglePins(0b10101010_01010101)
    68  	c.Assert(err, qt.IsNil)
    69  	pins, err = dev.GetPins()
    70  	c.Assert(err, qt.IsNil)
    71  	c.Assert(pins, qt.Equals, Pins(0b01011010_01011010))
    72  }
    73  
    74  func TestSetGetModes(t *testing.T) {
    75  	c := qt.New(t)
    76  	bus := tester.NewI2CBus(c)
    77  	fdev := newDevice(bus, 0x20)
    78  	dev, err := NewI2C(bus, 0x20)
    79  	c.Assert(err, qt.IsNil)
    80  	// Calling SetModes with less items in than there are
    81  	// pins should use the last item for all the unspecified ones.
    82  	err = dev.SetModes([]PinMode{Input | Invert, Output})
    83  	c.Assert(err, qt.IsNil)
    84  	c.Assert(fdev.Registers[rIODIR], qt.Equals, uint8(0b00000001))
    85  	c.Assert(fdev.Registers[rIOPOL], qt.Equals, uint8(0b00000001))
    86  	c.Assert(fdev.Registers[rGPPU], qt.Equals, uint8(0))
    87  
    88  	modes := make([]PinMode, 17)
    89  	err = dev.GetModes(modes)
    90  	c.Assert(err, qt.IsNil)
    91  	c.Assert(modes[0], qt.Equals, Input|Invert)
    92  	for i, m := range modes[1:16] {
    93  		c.Assert(m, qt.Equals, Output, qt.Commentf("index %d", i))
    94  	}
    95  	c.Assert(modes[16], qt.Equals, PinMode(0))
    96  
    97  	// Using an empty slice should reset all the modes to the initial state.
    98  	err = dev.SetModes(nil)
    99  	c.Assert(err, qt.IsNil)
   100  	c.Assert(fdev.Registers[rIODIR], qt.Equals, uint8(0b11111111))
   101  	c.Assert(fdev.Registers[rIOPOL], qt.Equals, uint8(0))
   102  	c.Assert(fdev.Registers[rGPPU], qt.Equals, uint8(0))
   103  }
   104  
   105  func TestPinSetGet(t *testing.T) {
   106  	c := qt.New(t)
   107  	bus := tester.NewI2CBus(c)
   108  	fdev := newDevice(bus, 0x20)
   109  	dev, err := NewI2C(bus, 0x20)
   110  	c.Assert(err, qt.IsNil)
   111  	pin := dev.Pin(1)
   112  	v, err := pin.Get()
   113  	c.Assert(err, qt.Equals, nil)
   114  	c.Assert(v, qt.Equals, false)
   115  	err = pin.Set(true)
   116  	c.Assert(err, qt.Equals, nil)
   117  	c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0b10))
   118  	v, err = pin.Get()
   119  	c.Assert(err, qt.Equals, nil)
   120  	c.Assert(v, qt.Equals, true)
   121  	err = pin.Set(false)
   122  	c.Assert(err, qt.Equals, nil)
   123  	c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0))
   124  	err = pin.High()
   125  	c.Assert(err, qt.Equals, nil)
   126  	c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0b10))
   127  	err = pin.Low()
   128  	c.Assert(err, qt.Equals, nil)
   129  	c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0))
   130  }
   131  
   132  func TestPinToggle(t *testing.T) {
   133  	c := qt.New(t)
   134  	bus := tester.NewI2CBus(c)
   135  	fdev := newDevice(bus, 0x20)
   136  	dev, err := NewI2C(bus, 0x20)
   137  	c.Assert(err, qt.IsNil)
   138  	pin := dev.Pin(1)
   139  	v, err := pin.Get()
   140  	c.Assert(err, qt.Equals, nil)
   141  	c.Assert(v, qt.Equals, false)
   142  	err = pin.Toggle()
   143  	c.Assert(err, qt.Equals, nil)
   144  	c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0b10))
   145  	err = pin.Toggle()
   146  	c.Assert(err, qt.Equals, nil)
   147  	c.Assert(fdev.Registers[rGPIO], qt.Equals, uint8(0))
   148  }
   149  
   150  func TestPinMode(t *testing.T) {
   151  	c := qt.New(t)
   152  	bus := tester.NewI2CBus(c)
   153  	fdev := newDevice(bus, 0x20)
   154  	dev, err := NewI2C(bus, 0x20)
   155  	c.Assert(err, qt.IsNil)
   156  	pin := dev.Pin(1)
   157  	mode, err := pin.GetMode()
   158  	c.Assert(err, qt.IsNil)
   159  	c.Assert(mode, qt.Equals, PinMode(0))
   160  	c.Assert(mode&Direction, qt.Equals, Input)
   161  
   162  	err = pin.SetMode(Input | Pullup | Invert)
   163  	c.Assert(err, qt.IsNil)
   164  	c.Assert(fdev.Registers[rIODIR], qt.Equals, uint8(0b11111111))
   165  	c.Assert(fdev.Registers[rIOPOL], qt.Equals, uint8(0b10))
   166  	c.Assert(fdev.Registers[rGPPU], qt.Equals, uint8(0b10))
   167  
   168  	mode, err = pin.GetMode()
   169  	c.Assert(err, qt.IsNil)
   170  	c.Assert(mode, qt.Equals, Input|Pullup|Invert)
   171  
   172  	// Set another pin to output.
   173  	err = dev.Pin(2).SetMode(Output)
   174  	c.Assert(err, qt.IsNil)
   175  	c.Assert(fdev.Registers[rIODIR], qt.Equals, uint8(0b11111011))
   176  	c.Assert(fdev.Registers[rIOPOL], qt.Equals, uint8(0b10))
   177  	c.Assert(fdev.Registers[rGPPU], qt.Equals, uint8(0b10))
   178  
   179  	// Check that changing a pin in port B works too.
   180  	err = dev.Pin(8).SetMode(Output)
   181  	c.Assert(err, qt.IsNil)
   182  	c.Assert(fdev.Registers[rIODIR], qt.Equals, uint8(0b11111011))
   183  	c.Assert(fdev.Registers[rIODIR|portB], qt.Equals, uint8(0b11111110))
   184  	c.Assert(fdev.Registers[rIOPOL], qt.Equals, uint8(0b10))
   185  	c.Assert(fdev.Registers[rIOPOL|portB], qt.Equals, uint8(0))
   186  	c.Assert(fdev.Registers[rGPPU], qt.Equals, uint8(0b10))
   187  	c.Assert(fdev.Registers[rGPPU|portB], qt.Equals, uint8(0))
   188  }
   189  
   190  func TestPins(t *testing.T) {
   191  	c := qt.New(t)
   192  	var p Pins
   193  	p.Set(1, true)
   194  	c.Assert(p, qt.Equals, Pins(0b10))
   195  	c.Assert(p.Get(1), qt.Equals, true)
   196  	c.Assert(p.Get(0), qt.Equals, false)
   197  	c.Assert(p.Get(16), qt.Equals, false)
   198  	p.High(2)
   199  	c.Assert(p, qt.Equals, Pins(0b110))
   200  	p.Low(1)
   201  	c.Assert(p, qt.Equals, Pins(0b100))
   202  }
   203  
   204  func TestInitWithError(t *testing.T) {
   205  	c := qt.New(t)
   206  	bus := tester.NewI2CBus(c)
   207  	fdev := newDevice(bus, 0x20)
   208  	fdev.Err = fmt.Errorf("some error")
   209  	dev, err := NewI2C(bus, 0x20)
   210  	c.Assert(err, qt.ErrorMatches, `cannot initialize mcp23017 device at 0x20: some error`)
   211  	c.Assert(dev, qt.IsNil)
   212  }
   213  
   214  func newDevice(bus *tester.I2CBus, addr uint8) *tester.I2CDevice8 {
   215  	fdev := bus.NewDevice(addr)
   216  	// IODIRA and IODIRB are all ones by default.
   217  	fdev.Registers[rIODIR] = 0xff
   218  	fdev.Registers[rIODIR|portB] = 0xff
   219  	return fdev
   220  }