mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
1bb1b621c6
Signed-off-by: deadprogram <ron@hybridgroup.com>
212 lines
5.5 KiB
Go
212 lines
5.5 KiB
Go
package mcp23017
|
|
|
|
// All is a convenience value that represents all pins high (or all mask bits one).
|
|
var All = PinSlice{0xffff}
|
|
|
|
// Devices holds a slice of devices that can be treated as one
|
|
// contiguous set of devices. Earlier entries in the slice have
|
|
// lower-numbered pins, so index 0 holds pins 0-7, index 1 holds
|
|
// pins 8-15, etc.
|
|
type Devices []*Device
|
|
|
|
// NewI2CDevices returns a Devices slice holding the Device values
|
|
// for all the given addresses on the given bus.
|
|
// When more than one bus is in use, create the slice yourself.
|
|
func NewI2CDevices(bus I2C, addrs ...uint8) (Devices, error) {
|
|
devs := make(Devices, len(addrs))
|
|
for i, addr := range addrs {
|
|
dev, err := NewI2C(bus, addr)
|
|
if err != nil {
|
|
// TODO return a more informative error.
|
|
return nil, err
|
|
}
|
|
devs[i] = dev
|
|
}
|
|
return devs, nil
|
|
}
|
|
|
|
// SetModes sets the pin modes of all the pins on all the devices in devs.
|
|
// If there are less entries in modes than there are pins, the
|
|
// last entry is replicated to all of them (or PinMode(0) if modes
|
|
// is empty).
|
|
func (devs Devices) SetModes(modes []PinMode) error {
|
|
var defaultModes []PinMode
|
|
if len(modes) > 0 {
|
|
defaultModes = modes[len(modes)-1:]
|
|
}
|
|
for i, dev := range devs {
|
|
pinStart := i * PinCount
|
|
var devModes []PinMode
|
|
if pinStart < len(modes) {
|
|
devModes = modes[pinStart:]
|
|
} else {
|
|
devModes = defaultModes
|
|
}
|
|
if err := dev.SetModes(devModes); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetModes gets the pin modes from the devices.
|
|
// It's OK if modes isn't the same length as all the pins:
|
|
// extra entries will be left unchanged.
|
|
func (devs Devices) GetModes(modes []PinMode) error {
|
|
for i, dev := range devs {
|
|
pinStart := i * PinCount
|
|
if pinStart >= len(modes) {
|
|
break
|
|
}
|
|
if err := dev.GetModes(modes[pinStart:]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Pin returns the pin for the given number.
|
|
func (devs Devices) Pin(pin int) Pin {
|
|
if pin < 0 || pin >= len(devs)*PinCount {
|
|
panic("pin out of range")
|
|
}
|
|
return devs[pin/PinCount].Pin(pin % PinCount)
|
|
}
|
|
|
|
// GetPins returns pin values for all the pins.
|
|
func (devs Devices) GetPins(pins PinSlice) error {
|
|
for i, dev := range devs {
|
|
if i >= len(pins) {
|
|
break
|
|
}
|
|
devPins, err := dev.GetPins()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
pins[i] = devPins
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetPins sets all the pins for which mask is high
|
|
// to their respective values in pins.
|
|
//
|
|
// That is, it does the equivalent of:
|
|
//
|
|
// for i := 0; i < PinCount*len(devs); i++ {
|
|
// if mask.Get(i) {
|
|
// d.Pin(i).Set(pins.Get(i))
|
|
// }
|
|
// }
|
|
func (devs Devices) SetPins(pins, mask PinSlice) error {
|
|
defaultPins := pins.extra()
|
|
defaultMask := mask.extra()
|
|
for i, dev := range devs {
|
|
devPins := defaultPins
|
|
if i < len(pins) {
|
|
devPins = pins[i]
|
|
}
|
|
devMask := defaultMask
|
|
if i < len(mask) {
|
|
devMask = mask[i]
|
|
}
|
|
if err := dev.SetPins(devPins, devMask); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TogglePins inverts the values on all pins for
|
|
// which mask is high.
|
|
func (devs Devices) TogglePins(mask PinSlice) error {
|
|
defaultMask := mask.extra()
|
|
for i, dev := range devs {
|
|
devMask := defaultMask
|
|
if i < len(mask) {
|
|
devMask = mask[i]
|
|
}
|
|
if err := dev.TogglePins(devMask); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PinSlice represents an arbitrary nunber of pins, each element corresponding
|
|
// to the pins for one device. The value of the highest numbered pin in the
|
|
// slice is extended to all other pins beyond the end of the slice.
|
|
type PinSlice []Pins
|
|
|
|
// Get returns the value for the given pin. If the length of pins is too short
|
|
// for the pin number, the value of the highest available pin is returned.
|
|
// That is, the highest numbered pin in the last element of pins
|
|
// is effectively replicated to all other elements.
|
|
//
|
|
// This means that PinSlice{} means "all pins high" and
|
|
// PinSlice{0xffff} means "all pins low".
|
|
func (pins PinSlice) Get(i int) bool {
|
|
if len(pins) == 0 || i < 0 {
|
|
return false
|
|
}
|
|
if i >= len(pins)*PinCount {
|
|
return pins[len(pins)-1].Get(PinCount - 1)
|
|
}
|
|
return pins[i/PinCount].Get(i % PinCount)
|
|
}
|
|
|
|
// Set sets the value for the given pin.
|
|
func (pins PinSlice) Set(i int, value bool) {
|
|
pins[i/PinCount].Set(i%PinCount, value)
|
|
}
|
|
|
|
// High is short for p.Set(pin, true).
|
|
func (pins PinSlice) High(pin int) {
|
|
pins[pin/PinCount].High(pin % PinCount)
|
|
}
|
|
|
|
// High is short for p.Set(pin, false).
|
|
func (pins PinSlice) Low(pin int) {
|
|
pins[pin/PinCount].Low(pin % PinCount)
|
|
}
|
|
|
|
// Toggle inverts the value of the given pin.
|
|
func (pins PinSlice) Toggle(pin int) {
|
|
pins[pin/PinCount].Toggle(pin % PinCount)
|
|
}
|
|
|
|
// Ensure checks that pins has enough space to store
|
|
// at least length pins. If it does, it returns pins unchanged.
|
|
// Otherwise, it returns pins with elements appended as needed,
|
|
// populating additonal elements by replicating the
|
|
// highest pin (mirroring the behavior of PinSlice.Get).
|
|
func (pins PinSlice) Ensure(length int) PinSlice {
|
|
if length == 0 {
|
|
return pins
|
|
}
|
|
n := length/PinCount + 1
|
|
if len(pins) >= n {
|
|
return pins
|
|
}
|
|
// TODO we could potentially make use of additional
|
|
// extra capacity in pins when available instead
|
|
// of allocating a new slice always.
|
|
newPins := make(PinSlice, n)
|
|
copy(newPins, pins)
|
|
if extend := pins.extra(); extend != 0 {
|
|
for i := len(pins); i < n; i++ {
|
|
newPins[i] = extend
|
|
}
|
|
}
|
|
return newPins
|
|
}
|
|
|
|
// extra returns the value of implied extra elements beyond
|
|
// the end of pins.
|
|
func (pins PinSlice) extra() Pins {
|
|
if len(pins) == 0 || !pins[len(pins)-1].Get(PinCount-1) {
|
|
return 0
|
|
}
|
|
return ^Pins(0)
|
|
}
|