tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/mcp23017/multidevice.go (about) 1 package mcp23017 2 3 import "tinygo.org/x/drivers" 4 5 // All is a convenience value that represents all pins high (or all mask bits one). 6 var All = PinSlice{0xffff} 7 8 // Devices holds a slice of devices that can be treated as one 9 // contiguous set of devices. Earlier entries in the slice have 10 // lower-numbered pins, so index 0 holds pins 0-7, index 1 holds 11 // pins 8-15, etc. 12 type Devices []*Device 13 14 // NewI2CDevices returns a Devices slice holding the Device values 15 // for all the given addresses on the given bus. 16 // When more than one bus is in use, create the slice yourself. 17 func NewI2CDevices(bus drivers.I2C, addrs ...uint8) (Devices, error) { 18 devs := make(Devices, len(addrs)) 19 for i, addr := range addrs { 20 dev, err := NewI2C(bus, addr) 21 if err != nil { 22 // TODO return a more informative error. 23 return nil, err 24 } 25 devs[i] = dev 26 } 27 return devs, nil 28 } 29 30 // SetModes sets the pin modes of all the pins on all the devices in devs. 31 // If there are less entries in modes than there are pins, the 32 // last entry is replicated to all of them (or PinMode(0) if modes 33 // is empty). 34 func (devs Devices) SetModes(modes []PinMode) error { 35 var defaultModes []PinMode 36 if len(modes) > 0 { 37 defaultModes = modes[len(modes)-1:] 38 } 39 for i, dev := range devs { 40 pinStart := i * PinCount 41 var devModes []PinMode 42 if pinStart < len(modes) { 43 devModes = modes[pinStart:] 44 } else { 45 devModes = defaultModes 46 } 47 if err := dev.SetModes(devModes); err != nil { 48 return err 49 } 50 } 51 return nil 52 } 53 54 // GetModes gets the pin modes from the devices. 55 // It's OK if modes isn't the same length as all the pins: 56 // extra entries will be left unchanged. 57 func (devs Devices) GetModes(modes []PinMode) error { 58 for i, dev := range devs { 59 pinStart := i * PinCount 60 if pinStart >= len(modes) { 61 break 62 } 63 if err := dev.GetModes(modes[pinStart:]); err != nil { 64 return err 65 } 66 } 67 return nil 68 } 69 70 // Pin returns the pin for the given number. 71 func (devs Devices) Pin(pin int) Pin { 72 if pin < 0 || pin >= len(devs)*PinCount { 73 panic("pin out of range") 74 } 75 return devs[pin/PinCount].Pin(pin % PinCount) 76 } 77 78 // GetPins returns pin values for all the pins. 79 func (devs Devices) GetPins(pins PinSlice) error { 80 for i, dev := range devs { 81 if i >= len(pins) { 82 break 83 } 84 devPins, err := dev.GetPins() 85 if err != nil { 86 return err 87 } 88 pins[i] = devPins 89 } 90 return nil 91 } 92 93 // SetPins sets all the pins for which mask is high 94 // to their respective values in pins. 95 // 96 // That is, it does the equivalent of: 97 // 98 // for i := 0; i < PinCount*len(devs); i++ { 99 // if mask.Get(i) { 100 // d.Pin(i).Set(pins.Get(i)) 101 // } 102 // } 103 func (devs Devices) SetPins(pins, mask PinSlice) error { 104 defaultPins := pins.extra() 105 defaultMask := mask.extra() 106 for i, dev := range devs { 107 devPins := defaultPins 108 if i < len(pins) { 109 devPins = pins[i] 110 } 111 devMask := defaultMask 112 if i < len(mask) { 113 devMask = mask[i] 114 } 115 if err := dev.SetPins(devPins, devMask); err != nil { 116 return err 117 } 118 } 119 return nil 120 } 121 122 // TogglePins inverts the values on all pins for 123 // which mask is high. 124 func (devs Devices) TogglePins(mask PinSlice) error { 125 defaultMask := mask.extra() 126 for i, dev := range devs { 127 devMask := defaultMask 128 if i < len(mask) { 129 devMask = mask[i] 130 } 131 if err := dev.TogglePins(devMask); err != nil { 132 return err 133 } 134 } 135 return nil 136 } 137 138 // PinSlice represents an arbitrary nunber of pins, each element corresponding 139 // to the pins for one device. The value of the highest numbered pin in the 140 // slice is extended to all other pins beyond the end of the slice. 141 type PinSlice []Pins 142 143 // Get returns the value for the given pin. If the length of pins is too short 144 // for the pin number, the value of the highest available pin is returned. 145 // That is, the highest numbered pin in the last element of pins 146 // is effectively replicated to all other elements. 147 // 148 // This means that PinSlice{} means "all pins high" and 149 // PinSlice{0xffff} means "all pins low". 150 func (pins PinSlice) Get(i int) bool { 151 if len(pins) == 0 || i < 0 { 152 return false 153 } 154 if i >= len(pins)*PinCount { 155 return pins[len(pins)-1].Get(PinCount - 1) 156 } 157 return pins[i/PinCount].Get(i % PinCount) 158 } 159 160 // Set sets the value for the given pin. 161 func (pins PinSlice) Set(i int, value bool) { 162 pins[i/PinCount].Set(i%PinCount, value) 163 } 164 165 // High is short for p.Set(pin, true). 166 func (pins PinSlice) High(pin int) { 167 pins[pin/PinCount].High(pin % PinCount) 168 } 169 170 // High is short for p.Set(pin, false). 171 func (pins PinSlice) Low(pin int) { 172 pins[pin/PinCount].Low(pin % PinCount) 173 } 174 175 // Toggle inverts the value of the given pin. 176 func (pins PinSlice) Toggle(pin int) { 177 pins[pin/PinCount].Toggle(pin % PinCount) 178 } 179 180 // Ensure checks that pins has enough space to store 181 // at least length pins. If it does, it returns pins unchanged. 182 // Otherwise, it returns pins with elements appended as needed, 183 // populating additonal elements by replicating the 184 // highest pin (mirroring the behavior of PinSlice.Get). 185 func (pins PinSlice) Ensure(length int) PinSlice { 186 if length == 0 { 187 return pins 188 } 189 n := length/PinCount + 1 190 if len(pins) >= n { 191 return pins 192 } 193 // TODO we could potentially make use of additional 194 // extra capacity in pins when available instead 195 // of allocating a new slice always. 196 newPins := make(PinSlice, n) 197 copy(newPins, pins) 198 if extend := pins.extra(); extend != 0 { 199 for i := len(pins); i < n; i++ { 200 newPins[i] = extend 201 } 202 } 203 return newPins 204 } 205 206 // extra returns the value of implied extra elements beyond 207 // the end of pins. 208 func (pins PinSlice) extra() Pins { 209 if len(pins) == 0 || !pins[len(pins)-1].Get(PinCount-1) { 210 return 0 211 } 212 return ^Pins(0) 213 }