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 }