Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gpioutil.Debounce not actually implemented #5

Open
2 of 4 tasks
lutzky opened this issue Jul 26, 2021 · 14 comments
Open
2 of 4 tasks

gpioutil.Debounce not actually implemented #5

lutzky opened this issue Jul 26, 2021 · 14 comments

Comments

@lutzky
Copy link
Contributor

lutzky commented Jul 26, 2021

Apologies if I'm misreading. I have implemented manual debouncing and denoising for my own project, before realizing that gpioutil.Debounce exists. It would provide a cleaner API to do the same thing, so I looked into switching to using it. However, observing the current version of debounce.go, it appears that:

(I've tried to keep the checkbox entries in actual tasks, so they can be used with Task lists).

Am I missing something? I think, at least, that the documentation should clarify the state of this code.

Side-note: While I was aware of the importance of debouncing, denoising was newer to me, and I found out about it the annoying way (I have phantom GPIO "button presses" about every 8 hours; super annoying to debug). Once Debounce is implemented correctly, it's probably worth mentioning in the documentation of WaitForEdge.

@maruel
Copy link
Member

maruel commented Jul 26, 2021

There's historical reasons for this. 3 years ago I started looking at options to recreate the conn package as I don't feel the current interfaces are optimal. Then go modules were forced and I spent all my free time on splitting the repositories into real go packages.

You can find a bit more at:

Because of the uncertainty with how the GPIO functions would look like, I didn't spend time to fix the Debounce code when I carried it over from experimental at https://github.com/google/periph/tree/main/experimental/conn/gpio/gpioutil when I removed experimental when I created the new repositories. There's more at https://periph.io/news/2020/a_new_start/.

So that was a lot of words and links to say that help would be very appreciated.

@lutzky
Copy link
Contributor Author

lutzky commented Jul 26, 2021

OK, at the very least I'll do the doc warning.

@lutzky
Copy link
Contributor Author

lutzky commented Jul 26, 2021

Could you please hit the "Convert to issue" button on those tasks? (That should make it link up nicely and I can reference that in the pull request)

@maruel
Copy link
Member

maruel commented Jul 26, 2021

#TIL

@lutzky
Copy link
Contributor Author

lutzky commented Jul 26, 2021

After #10:
So, to clarify, should the conn package be considered stable enough for it to be worth actually implementing this now (I mean, it's been 3 years)? Or is v4 right around the corner (...and then v4 needs an implementation of this)?

@maruel
Copy link
Member

maruel commented Jul 26, 2021

I started multiple changes for v4 but given my current work workload it's unlikely for me to have a v4 in the next year.

@lutzky
Copy link
Contributor Author

lutzky commented Jul 27, 2021

Understood. So after the docfix is in, I'll see if I can take a whack at implementing the logic for v3.

@lutzky
Copy link
Contributor Author

lutzky commented Aug 13, 2021

Looking at the current documentation, the Read method is also documented as being affected by debouncing:

// Read implements gpio.PinIO.
//
// It is the smoothed out value from the underlying gpio.PinIO.
func (d *debounced) Read() gpio.Level {

This is significantly more complicated to implement than the WaitForEdge variant, which would boil down to something like this:

func (d *debounced) WaitForEdge(timeout time.Duration) bool {
  prev := d.PinIO.Read()
  for {
    if !d.PinIO.WaitForEdge(timeout) {
      return false
    }
    time.Sleep(d.denoise)
    if d.PinIO.Read() != prev {
      return true
    }
  }
}

Looking around, there's a C library called pigpio which has a set_glitch_filter that seems to have similar functionality, and indeed only applies to their equivalent for WaitForEdge (although the implementation seems more complicated).

Getting this to work for Read as well is... tricky? I mean, I guess it could do this:

func (d *debounced) Read() gpio.Level {
  for {
    prev := d.PinIO.Read()
    time.Sleep(d.denoise)
    if d.PinIO.Read() == prev {
      return prev
    }
  }
}

Is that what you had in mind?

@maruel
Copy link
Member

maruel commented Aug 14, 2021

My thinking was to save one read if the last read occurred within d.denoise, but in hindsight I'm not sure it was a good idea.

@lutzky
Copy link
Contributor Author

lutzky commented Aug 15, 2021

I'm not sure how that would work... and I don't think it can work in the case of "user calls Read just once". Am I missing something?

@maruel
Copy link
Member

maruel commented Aug 16, 2021

hence my "I'm not sure it was a good idea" :)

@lutzky
Copy link
Contributor Author

lutzky commented Aug 16, 2021

Fair enough 😅
What do you think of my proposal?

@maruel
Copy link
Member

maruel commented Aug 16, 2021

lgtm

@lutzky
Copy link
Contributor Author

lutzky commented Aug 16, 2021

Alright, started on this in #12, LMK what you think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants