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  }