diff --git a/examples/makeybutton/main.go b/examples/makeybutton/main.go index 53e3434..d92ff80 100644 --- a/examples/makeybutton/main.go +++ b/examples/makeybutton/main.go @@ -9,7 +9,7 @@ import ( var ( led machine.Pin = machine.LED - button machine.Pin = machine.BUTTON + button machine.Pin = machine.D10 key *makeybutton.Button ) @@ -25,6 +25,7 @@ func main() { case makeybutton.Released: led.Low() } - time.Sleep(100 * time.Millisecond) + // the more frequent the more responsive + time.Sleep(50 * time.Millisecond) } } diff --git a/makeybutton/buffer.go b/makeybutton/buffer.go index 65a38c7..0a10791 100644 --- a/makeybutton/buffer.go +++ b/makeybutton/buffer.go @@ -1,11 +1,17 @@ package makeybutton -const bufferSize = 6 +const ( + bufferSize = 3 + maxSumAllowed = 4 +) // Buffer is a buffer to keep track of the most recent readings for a button. +// in bit form. type Buffer struct { - readings [bufferSize]bool - index int + data [bufferSize]byte + byteCounter int + bitCounter int + sum int } // NewBuffer returns a new buffer. @@ -13,34 +19,47 @@ func NewBuffer() *Buffer { return &Buffer{} } -// Used returns how many bytes in buffer have been used. -func (b *Buffer) Used() int { - return b.index +// Sum returns the sum of all measurements +func (b *Buffer) Sum() int { + return b.sum } -// Put stores a boolean in the buffer. -func (b *Buffer) Put(val bool) bool { - b.index++ - if b.index >= bufferSize { - b.index = 0 +// Put stores a boolean button state into the buffer. +func (b *Buffer) Put(val bool) { + currentMeasurement, oldestMeasurement := b.updateData(val) + b.updateCounters() + + if currentMeasurement != 0 && b.sum < maxSumAllowed { + b.sum++ } - b.readings[b.index] = val - - return true + if oldestMeasurement != 0 && b.sum > 0 { + b.sum-- + } } -// Avg returns the "average" of all the readings in the buffer, by -// treating a true as 1 and a false as -1. -func (b *Buffer) Avg() int { - avg := 0 - for i := 0; i < bufferSize; i++ { - if b.readings[i] { - avg += 1 - } else { - avg -= 1 +func (b *Buffer) updateData(val bool) (byte, byte) { + currentByte := b.data[b.byteCounter] + oldestMeasurement := (currentByte >> b.bitCounter) & 0x01 + + if val { + currentByte |= (1 << b.bitCounter) + } else { + currentByte &= ^(1 << b.bitCounter) + } + + b.data[b.byteCounter] = currentByte + + return (currentByte >> b.bitCounter) & 0x01, oldestMeasurement +} + +func (b *Buffer) updateCounters() { + b.bitCounter++ + if b.bitCounter == 8 { + b.bitCounter = 0 + b.byteCounter++ + if b.byteCounter == bufferSize { + b.byteCounter = 0 } } - - return avg } diff --git a/makeybutton/button.go b/makeybutton/button.go index 74023df..69d3340 100644 --- a/makeybutton/button.go +++ b/makeybutton/button.go @@ -4,6 +4,8 @@ // Inspired by the amazing MakeyMakey // https://makeymakey.com/ // +// This code is a reinterpretation of +// https://github.com/sparkfun/MaKeyMaKey/blob/master/firmware/Arduino/makey_makey/makey_makey.ino package makeybutton import ( @@ -11,6 +13,11 @@ import ( "time" ) +var ( + pressThreshold int = 1 + releaseThreshold int = 0 +) + // ButtonState represents the state of a MakeyButton. type ButtonState int @@ -33,6 +40,7 @@ const ( type Button struct { pin machine.Pin state ButtonState + pressed bool readings *Buffer HighMeansPressed bool } @@ -49,7 +57,7 @@ func NewButton(pin machine.Pin) *Button { // Configure configures the Makey Button pin to have the correct settings to detect touches. func (b *Button) Configure() error { - // Note that we have to first turn on the pullup, and then turn off the pullup, + // Note that on AVR we have to first turn on the pullup, and then turn off the pullup, // in order for the pin to be properly floating. b.pin.Configure(machine.PinConfig{Mode: machine.PinInputPullup}) time.Sleep(10 * time.Millisecond) @@ -62,30 +70,36 @@ func (b *Button) Configure() error { // Get returns a ButtonEvent based on the most recent state of the button, // and if it has changed by being pressed or released. func (b *Button) Get() ButtonEvent { - // if pin is pulled up, a low value means the key is pressed - pressed := !b.pin.Get() - if b.HighMeansPressed { - // otherwise, a high value means the key is pressed - pressed = !pressed - } + b.update() - avg := b.readings.Avg() - b.readings.Put(pressed) - - switch { - case pressed && avg > -1*bufferSize+2: - if b.state == Press { - return NotChanged - } - - b.state = Press - return Pressed - case !pressed: - if b.state == Press { + if b.pressed { + // the button had previously been pressed, + // but now appears to have been released. + if b.readings.Sum() <= releaseThreshold { + b.pressed = false b.state = Release return Released } + } else { + // the button had previously not been pressed, + // but now appears to have been pressed. + if b.readings.Sum() >= pressThreshold { + b.pressed = true + b.state = Press + return Pressed + } } return NotChanged } + +func (b *Button) update() { + // if pin is pulled up, a low value means the key is pressed + press := !b.pin.Get() + if b.HighMeansPressed { + // otherwise, a high value means the key is pressed + press = !press + } + + b.readings.Put(press) +}