An open API service indexing awesome lists of open source software.

https://github.com/eyelight/bouncer

bouncer is a button input handler library supporting press-lengths of different durations, and debouncing
https://github.com/eyelight/bouncer

Last synced: 5 months ago
JSON representation

bouncer is a button input handler library supporting press-lengths of different durations, and debouncing

Awesome Lists containing this project

README

          

# Bouncer
Bouncer is a button input handler package for use with [TinyGo](https://tinygo.org/) on arm microcontrollers. It supports systick-based debouncing of button input and recognizes button-press-lengths of different durations

Bouncer assumes you are using long-lived goroutines which listen for updates on a long-lived channel. At the end of a buttonDown -> buttonUp sequence, a Bouncer recognizes the duration of the press and sends this information to interested subscribers. When setting up your Bouncer(s), you can add an output channel for each of your interested subscribers.

### `New`
- Pass an unconfigured pin here (Configure will reconfigure it to InputPullup anyway)
- With `...outs` you'll add one or more channels on which the bouncer will publish `PressLength` events to your interested goroutines.

### `Configure`
A custom duration for short, long, & extra long presses can be set in a `BouncerConfig` struct. To override default values, pass this to Configure, or pass an empty `BouncerConfig` to keep default values. The bouncer's pin is set to InputPullup

In `Configure`, a function becomes the button's pin interrupt handler, firing on `PinRising` & `PinFalling`, sending the button's pin state to the Bouncer's `isrChan` channel, which is consumed by `RecognizeAndPublish`

### `RecognizeAndPublish`

This is the button-press-length recognizer & publisher goroutine.
- The function blocks on communication from one of two channels
- `tickerCh` – a systick from the `SysTick_Handler` was received from the relay
- `isrChan` – a button interrupt event was received
- Initially, `RecognizeAndPublish` is looking for a buttonDown event, and will ignore both systicks & buttonUp interrupts.
- After the first buttonDown event arrives, the time is noted for later evaluation, and the function begins to increment `ticks` whenever a SysTick is received on `tickerCh`.
- At this point, the function begins to expect buttonUp events; buttonDown events are ignored.
- Upon the first debounced buttonUp event, the time is subtracted from the buttonDown time, resulting in a buttonDown duration. This duration is compared to the set of `PressLength` durations, thereby becoming recognized.
- The resulting `PressLength` is published to all output channels

## Some plumbing in `main` to set up your SysTick_Handler
A systick is a machine-level event to which we can attach our own handler. Since this is global in nature, it doesn't belong in this package; instead, you must set up a "SysTick_Handler" yourself and allow your Bouncer to consume its channel, indirectly through a relay (`Debounce`) in order to fan-out the ticks to multiple bouncers. You'll set up the system timer, define your Systick handler, set up your bouncers, and then call Debounce to begin debouncing.

### First, set up the timer

In your `init` or `main`, set up a timer set to an interval of your desired debounce duration. The following will fire 10 times per second, obtaining a ~100ms debounce threshold; a higher denominator (shorter duration) may be more appropriate, perhaps 40 -> 25ms. It's up to you.

```golang
func launchSystick() {
err := arm.SetupSystemTimer(machine.CPUFrequency() / 10)
if err != nil {
println("error launching systick timer!")
}
println("launched systick timer...")
}
```

### Next, our systick handling function

SysTick_Handler is attached to a function using the go macro `//go:export SysTick_Handler`. The function should simply `select` and send to a struct channel with a buffer of 1.

One interesting thing about this is that you never need to call it; you only define it and the macro will call it under the hood for you – as many times per second as the call to `arm.SetupSystemTimer` above.

```golang
//go:export SysTick_Handler
func handleSystick() {
select {
case tickCh <- struct{}{}:
default:
}
}
```

### `Debounce` – Starting (Multiple) Bouncers
Call Debounce in order to begin relaying the systicks to all bouncers you've set up. Pass it the channel to which your SysTick_Handler is sending.

```golang
go bouncer.Debounce(tickCh)
```

Subscribing bouncers to the relay is done internally by the package – simply call the package-level function `Relay` as a goroutine and pass it the same channel `tickCh` produced by our systick handler. Do not consume `tickCh` in more than 1 place.