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

     1  // Package makeybutton providers a driver for a button that can be triggered
     2  // by anything that is conductive by using an ultra high value resistor.
     3  //
     4  // Inspired by the amazing MakeyMakey
     5  // https://makeymakey.com/
     6  //
     7  // This code is a reinterpretation of
     8  // https://github.com/sparkfun/MaKeyMaKey/blob/master/firmware/Arduino/makey_makey/makey_makey.ino
     9  package makeybutton
    10  
    11  import (
    12  	"machine"
    13  	"time"
    14  )
    15  
    16  var (
    17  	pressThreshold   int = 1
    18  	releaseThreshold int = 0
    19  )
    20  
    21  // ButtonState represents the state of a MakeyButton.
    22  type ButtonState int
    23  
    24  const (
    25  	NeverPressed ButtonState = 0
    26  	Press                    = 1
    27  	Release                  = 2
    28  )
    29  
    30  // ButtonEvent represents when the state of a Button changes.
    31  type ButtonEvent int
    32  
    33  const (
    34  	NotChanged ButtonEvent = 0
    35  	Pressed                = 1
    36  	Released               = 2
    37  )
    38  
    39  // Button is a "button"-like device that acts like a MakeyMakey.
    40  type Button struct {
    41  	pin              machine.Pin
    42  	state            ButtonState
    43  	pressed          bool
    44  	readings         *Buffer
    45  	HighMeansPressed bool
    46  }
    47  
    48  // NewButton creates a new Button.
    49  func NewButton(pin machine.Pin) *Button {
    50  	return &Button{
    51  		pin:              pin,
    52  		state:            NeverPressed,
    53  		readings:         NewBuffer(),
    54  		HighMeansPressed: false,
    55  	}
    56  }
    57  
    58  // Configure configures the Makey Button pin to have the correct settings to detect touches.
    59  func (b *Button) Configure() error {
    60  	// Note that on AVR we have to first turn on the pullup, and then turn off the pullup,
    61  	// in order for the pin to be properly floating.
    62  	b.pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
    63  	time.Sleep(10 * time.Millisecond)
    64  	b.pin.Configure(machine.PinConfig{Mode: machine.PinInput})
    65  	b.pin.Set(false)
    66  
    67  	return nil
    68  }
    69  
    70  // Get returns a ButtonEvent based on the most recent state of the button,
    71  // and if it has changed by being pressed or released.
    72  func (b *Button) Get() ButtonEvent {
    73  	b.update()
    74  
    75  	if b.pressed {
    76  		// the button had previously been pressed,
    77  		// but now appears to have been released.
    78  		if b.readings.Sum() <= releaseThreshold {
    79  			b.pressed = false
    80  			b.state = Release
    81  			return Released
    82  		}
    83  	} else {
    84  		// the button had previously not been pressed,
    85  		// but now appears to have been pressed.
    86  		if b.readings.Sum() >= pressThreshold {
    87  			b.pressed = true
    88  			b.state = Press
    89  			return Pressed
    90  		}
    91  	}
    92  
    93  	return NotChanged
    94  }
    95  
    96  func (b *Button) update() {
    97  	// if pin is pulled up, a low value means the key is pressed
    98  	press := !b.pin.Get()
    99  	if b.HighMeansPressed {
   100  		// otherwise, a high value means the key is pressed
   101  		press = !press
   102  	}
   103  
   104  	b.readings.Put(press)
   105  }