mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-17 13:21:50 +01:00
Cleanup, webclient GPIO debounce support
This commit is contained in:
parent
49267489f5
commit
e3c4a9bf97
@ -123,8 +123,6 @@ func (gm *GpioManager) DeployGpioTrigger(in *pb.TriggerGPIOIn) (err error) {
|
||||
p.In(pull, edge)
|
||||
|
||||
debounceDelay := time.Duration(in.DebounceMillis) * time.Millisecond
|
||||
//ToDo: remove next line, as this is a fixed test delay of 100 ms
|
||||
debounceDelay = 100 * time.Millisecond
|
||||
|
||||
go func() {
|
||||
fmt.Println("Starting edge detection for pin " + p.Name())
|
||||
@ -153,102 +151,6 @@ func (gm *GpioManager) DeployGpioTrigger(in *pb.TriggerGPIOIn) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (gm *GpioManager) DeployGpioTriggerOld(in *pb.TriggerGPIOIn) (err error) {
|
||||
if !gm.IsUsable {
|
||||
return EGpioNotAvailable
|
||||
}
|
||||
|
||||
p := gpioreg.ByName(in.GpioName)
|
||||
if p == nil {
|
||||
return EGpioPinInvalid
|
||||
}
|
||||
|
||||
pull := gpio.Float
|
||||
switch in.PullUpDown {
|
||||
case pb.GPIOInPullUpDown_DOWN:
|
||||
pull = gpio.PullDown
|
||||
case pb.GPIOInPullUpDown_UP:
|
||||
pull = gpio.PullUp
|
||||
}
|
||||
|
||||
edge := gpio.BothEdges
|
||||
switch in.GpioInEdge {
|
||||
case pb.GPIOInEdge_FALLING:
|
||||
edge = gpio.FallingEdge
|
||||
case pb.GPIOInEdge_RISING:
|
||||
edge = gpio.RisingEdge
|
||||
}
|
||||
|
||||
// If edge detection is already running, stop it
|
||||
if gm.isEdgeDetecting(p) {
|
||||
gm.stopEdgeDetectionForPin(p)
|
||||
}
|
||||
|
||||
p.In(pull,edge)
|
||||
|
||||
gm.edgeDetectingMutex.Lock()
|
||||
gm.edgeDetecting[p] = true
|
||||
gm.edgeDetectingMutex.Unlock()
|
||||
|
||||
debounceDelay := time.Duration(in.DebounceMillis) * time.Millisecond
|
||||
//ToDo: remove next line, as this is a fixed test delay of 100 ms
|
||||
debounceDelay = 100 *time.Millisecond
|
||||
|
||||
go func() {
|
||||
fmt.Println("Starting edge detection for pin " + p.Name())
|
||||
lastHit := time.Now()
|
||||
for gm.isEdgeDetecting(p) {
|
||||
fmt.Println("Wait for edge " + p.Name() + " ...")
|
||||
waitSuccess := p.WaitForEdge(-1)
|
||||
fmt.Printf("... done wait for edge %s waitSucces: %v\n", p.Name(), waitSuccess)
|
||||
if !waitSuccess {
|
||||
break
|
||||
}
|
||||
now := time.Now()
|
||||
bounce := true
|
||||
sinceLastHit := now.Sub(lastHit)
|
||||
if sinceLastHit > debounceDelay {
|
||||
bounce = false
|
||||
// could do `lastHit = now` if timer only should be reset for "no bounce"
|
||||
}
|
||||
lastHit = now
|
||||
|
||||
//Edge detected, check if still edge detecting before consuming
|
||||
if gm.isEdgeDetecting(p) {
|
||||
switch p.Read() {
|
||||
case gpio.High:
|
||||
fmt.Println("Gpio " + p.Name() + " changed to high")
|
||||
if !bounce {
|
||||
gm.rootSvc.SubSysEvent.Emit(ConstructEventTriggerGpioIn(p.Name(), bool(gpio.High)))
|
||||
} else {
|
||||
fmt.Println("... ignored, as in debounceDelay")
|
||||
}
|
||||
case gpio.Low:
|
||||
fmt.Println("Gpio " + p.Name() + " changed to low")
|
||||
if !bounce {
|
||||
gm.rootSvc.SubSysEvent.Emit(ConstructEventTriggerGpioIn(p.Name(), bool(gpio.Low)))
|
||||
} else {
|
||||
fmt.Println("... ignored, as in debounceDelay")
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
//exit for loop
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println("STOPPED edge detection for pin " + p.Name())
|
||||
gm.edgeDetectingMutex.Lock()
|
||||
delete(gm.edgeDetecting, p)
|
||||
gm.edgeDetectingMutex.Unlock()
|
||||
}()
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
func (gm *GpioManager) FireGpioAction(out *pb.ActionGPIOOut) (err error) {
|
||||
fmt.Println("FireGPIOAction for", out.GpioName)
|
||||
if !gm.IsUsable {
|
||||
@ -273,7 +175,7 @@ func (gm *GpioManager) FireGpioAction(out *pb.ActionGPIOOut) (err error) {
|
||||
fmt.Printf("Setting %s to out level %v...\n", p.Name(), level)
|
||||
|
||||
p.Out(level)
|
||||
fmt.Println("..setting level done")
|
||||
//fmt.Println("..setting level done")
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -289,51 +191,3 @@ func (gm *GpioManager) ResetPins() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
func (gm *GpioManager) isEdgeDetecting(p gpio.PinIO) bool {
|
||||
gm.edgeDetectingMutex.Lock()
|
||||
defer gm.edgeDetectingMutex.Unlock()
|
||||
if _,exists := gm.edgeDetecting[p]; exists && gm.edgeDetecting[p] {
|
||||
fmt.Println("Edge detection for " + p.Name() + " running")
|
||||
return true
|
||||
}
|
||||
fmt.Println("Edge detection for " + p.Name() + " not running")
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
func (gm *GpioManager) stopEdgeDetectionForPin(p gpio.PinIO) {
|
||||
fmt.Println("Stopping edge detection for pin " + p.Name())
|
||||
gm.edgeDetectingMutex.Lock()
|
||||
if _,exists := gm.edgeDetecting[p]; exists {
|
||||
gm.edgeDetecting[p] = false
|
||||
}
|
||||
gm.edgeDetectingMutex.Unlock()
|
||||
|
||||
|
||||
//p.Halt()
|
||||
p.In(gpio.Float, gpio.BothEdges)
|
||||
|
||||
isNotDeleted := func() bool {
|
||||
gm.edgeDetectingMutex.Lock()
|
||||
defer gm.edgeDetectingMutex.Unlock()
|
||||
_,exists := gm.edgeDetecting[p]
|
||||
return exists
|
||||
}
|
||||
|
||||
|
||||
//write high/low till gpio is deleted from map, to assure pending edge detection ended
|
||||
for isNotDeleted() {
|
||||
fmt.Println("... stopping " + p.Name() + " setting PullDown to trigger final edge")
|
||||
p.In(gpio.PullDown, gpio.BothEdges)
|
||||
if isNotDeleted() {
|
||||
fmt.Println("... stopping " + p.Name() + " setting PullUp to trigger final edge")
|
||||
p.In(gpio.PullUp, gpio.BothEdges)
|
||||
}
|
||||
}
|
||||
|
||||
p.In(gpio.Float, gpio.NoEdge)
|
||||
}
|
||||
*/
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"periph.io/x/periph/conn/gpio"
|
||||
"periph.io/x/periph/conn/physic"
|
||||
"time"
|
||||
@ -13,12 +14,12 @@ import (
|
||||
|
||||
var (
|
||||
EEdgeDetectNotRunning = errors.New("edge detection not running")
|
||||
EEdgeDetectAborted = errors.New("edge detection aborted")
|
||||
EEdgeDetectAborted = errors.New("edge detection aborted")
|
||||
)
|
||||
|
||||
type steadyTimeLevel struct {
|
||||
SteadyTime time.Duration
|
||||
Level gpio.Level
|
||||
Level gpio.Level
|
||||
}
|
||||
|
||||
type P4wnp1PinIO struct {
|
||||
@ -30,17 +31,16 @@ type P4wnp1PinIO struct {
|
||||
edgeDetectionMutex *sync.Mutex
|
||||
*/
|
||||
|
||||
edge gpio.Edge
|
||||
pull gpio.Pull
|
||||
edgeDetectionAbort bool
|
||||
edge gpio.Edge
|
||||
pull gpio.Pull
|
||||
edgeDetectionAbort bool
|
||||
edgeDetectionChannel chan steadyTimeLevel //Every time a valid edge is detected, this channel returns the duration since the last valid edge (==steadyTime. could be used for debounce) and the gpio.Level during edge event
|
||||
waitForEdgeStopped bool
|
||||
lastEdgeTime time.Time
|
||||
waitForEdgeStopped bool
|
||||
lastEdgeTime time.Time
|
||||
}
|
||||
|
||||
func (p *P4wnp1PinIO) startEdgeDetection(pull gpio.Pull, edge gpio.Edge, preserveUnconsumed bool) (err error) {
|
||||
fmt.Println("starting edge detection for", p.Name() , "...")
|
||||
|
||||
fmt.Println("starting edge detection for", p.Name(), "...")
|
||||
|
||||
p.lastEdgeTime = time.Now()
|
||||
if preserveUnconsumed {
|
||||
@ -102,7 +102,7 @@ func (p *P4wnp1PinIO) startEdgeDetection(pull gpio.Pull, edge gpio.Edge, preserv
|
||||
|
||||
// Send the steadyTimeLeve along the channel
|
||||
stl := steadyTimeLevel{
|
||||
Level: level,
|
||||
Level: level,
|
||||
SteadyTime: timeSinceLastEdge,
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ func (p *P4wnp1PinIO) startEdgeDetection(pull gpio.Pull, edge gpio.Edge, preserv
|
||||
} else {
|
||||
//pop old stl from channel if needed
|
||||
for len(p.edgeDetectionChannel) > 0 {
|
||||
<- p.edgeDetectionChannel
|
||||
<-p.edgeDetectionChannel
|
||||
}
|
||||
p.edgeDetectionChannel <- stl //put latest stl to channel
|
||||
}
|
||||
@ -130,29 +130,25 @@ func (p *P4wnp1PinIO) startEdgeDetection(pull gpio.Pull, edge gpio.Edge, preserv
|
||||
fmt.Println("... edge detection for", p.Name(), "stopped")
|
||||
}()
|
||||
|
||||
|
||||
fmt.Println("... edge detection for", p.Name(), "started")
|
||||
fmt.Printf("p: %+v\n",p)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *P4wnp1PinIO) isEdgeDetectionRunning() bool {
|
||||
if p.edgeDetectionChannel == nil {
|
||||
fmt.Println("edge detection not running")
|
||||
fmt.Printf("p: %+v\n",p)
|
||||
//fmt.Println("edge detection not running")
|
||||
return false
|
||||
}
|
||||
fmt.Println("edge detection running")
|
||||
//fmt.Println("edge detection running")
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *P4wnp1PinIO) stopEdgeDetection() error {
|
||||
fmt.Println("stopping edge detection for", p.Name(), "...")
|
||||
|
||||
if !p.isEdgeDetectionRunning() {
|
||||
return EEdgeDetectNotRunning
|
||||
}
|
||||
|
||||
fmt.Println("stopping edge detection for", p.Name(), "...")
|
||||
p.edgeDetectionAbort = true
|
||||
|
||||
// hackish approach to end WaitForEdge, by toggling Pull resistors (see comments in startEdgeDetection for details)
|
||||
@ -168,11 +164,9 @@ func (p *P4wnp1PinIO) stopEdgeDetection() error {
|
||||
|
||||
// wait till stop success is indicated
|
||||
if p.edgeDetectionChannel != nil { // if channel still exists
|
||||
<-p.edgeDetectionChannel //wait for close
|
||||
<-p.edgeDetectionChannel //wait for close
|
||||
}
|
||||
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -180,34 +174,34 @@ func (p P4wnp1PinIO) Edge() gpio.Edge {
|
||||
return p.edge
|
||||
}
|
||||
|
||||
|
||||
func (p *P4wnp1PinIO) ExtWaitForEdge(ctx context.Context, debounceDuration time.Duration) (level gpio.Level, err error) {
|
||||
useDebounce := debounceDuration > 0
|
||||
|
||||
for { // the select statement is wrapped into a for loop, to account for edges not fulfilling the debounceDuration criteria
|
||||
select {
|
||||
case steadyTimeLevel,channelOpen := <- p.edgeDetectionChannel:
|
||||
case steadyTimeLevel, channelOpen := <-p.edgeDetectionChannel:
|
||||
//channel closed, so we return error
|
||||
if !channelOpen {
|
||||
return level,EEdgeDetectNotRunning
|
||||
return level, EEdgeDetectNotRunning
|
||||
}
|
||||
if !useDebounce {
|
||||
// no debounce needed, ultimately return the edge change
|
||||
return steadyTimeLevel.Level,nil
|
||||
return steadyTimeLevel.Level, nil
|
||||
} else {
|
||||
// we have to assure that no other edge change event occurs in debounce duration (steady level) before returning
|
||||
if steadyTimeLevel.SteadyTime >= debounceDuration {
|
||||
//detected edge fulfills debounce criteria
|
||||
return steadyTimeLevel.Level,nil
|
||||
return steadyTimeLevel.Level, nil
|
||||
}
|
||||
// else ignore edge
|
||||
fmt.Printf("Ignored detected edge as invalidated by debounce: %v\n", steadyTimeLevel)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return level,EEdgeDetectAborted
|
||||
return level, EEdgeDetectAborted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func (p P4wnp1PinIO) String() string {
|
||||
return p.piPin.String()
|
||||
@ -230,15 +224,16 @@ func (p P4wnp1PinIO) Function() string {
|
||||
}
|
||||
|
||||
func (p *P4wnp1PinIO) In(pull gpio.Pull, edge gpio.Edge) (err error) {
|
||||
fmt.Println("Called In() on ", p.Name())
|
||||
p.stopEdgeDetection()
|
||||
// bring up edgeDetection go routine (again) if needed
|
||||
err = p.piPin.In(pull, edge)
|
||||
if err != nil { return }
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
p.pull = pull
|
||||
p.edge = edge
|
||||
if edge != gpio.NoEdge {
|
||||
p.startEdgeDetection(pull,edge,false) //don't preserve unconsumed events
|
||||
p.startEdgeDetection(pull, edge, false) //don't preserve unconsumed events
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -268,12 +263,9 @@ func (p *P4wnp1PinIO) Out(l gpio.Level) error {
|
||||
func (p *P4wnp1PinIO) PWM(duty gpio.Duty, f physic.Frequency) error {
|
||||
//stop edge detection, if needed
|
||||
p.stopEdgeDetection()
|
||||
return p.piPin.PWM(duty,f)
|
||||
return p.piPin.PWM(duty, f)
|
||||
}
|
||||
|
||||
func NewP4wnp1PinIO(p gpio.PinIO) *P4wnp1PinIO {
|
||||
return &P4wnp1PinIO{piPin: p}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -288,6 +288,7 @@ func InitComponentsTriggerActions() {
|
||||
strTrigger += t.GpioName
|
||||
strTrigger += ": " + gpioInEdgeNames[t.Edge]
|
||||
strTrigger += ", resistor: " + gpioInPullUpDownNames[t.PullUpDown]
|
||||
strTrigger += ", debounce: " + strconv.Itoa(int(t.DebounceMillis)) + "ms"
|
||||
strTrigger += ")"
|
||||
}
|
||||
|
||||
@ -772,6 +773,15 @@ const templateTrigger = `
|
||||
</q-item-tile>
|
||||
</q-item-main>
|
||||
</q-item>
|
||||
<q-item tag="label" v-if="isTriggerGPIOIn">
|
||||
<q-item-main>
|
||||
<q-item-tile label>Debounce duration</q-item-tile>
|
||||
<q-item-tile sublabel>Successive edge events in this duration are ignored</q-item-tile>
|
||||
<q-item-tile>
|
||||
<q-input v-model="ta.TriggerData.DebounceMillis" type="number" suffix="ms" decimals="0" inverted :disable="!ta.IsActive"></q-input>
|
||||
</q-item-tile>
|
||||
</q-item-main>
|
||||
</q-item>
|
||||
|
||||
</q-list>
|
||||
`
|
||||
|
@ -149,6 +149,7 @@ func (dst *jsTriggerAction) fromGo(src *pb.TriggerAction) {
|
||||
dstTrigger.GpioName = srcTrigger.GpioIn.GpioName
|
||||
dstTrigger.Edge = GPIOInEdge(srcTrigger.GpioIn.GpioInEdge)
|
||||
dstTrigger.PullUpDown = GPIOInPullUpDown(srcTrigger.GpioIn.PullUpDown)
|
||||
dstTrigger.DebounceMillis = srcTrigger.GpioIn.DebounceMillis
|
||||
case *pb.TriggerAction_GroupReceive:
|
||||
dst.ChangeTriggerType(TriggerGroupReceive)
|
||||
dstTrigger := &jsTriggerGroupReceive{Object: dst.TriggerData}
|
||||
@ -264,6 +265,7 @@ func (ta *jsTriggerAction) toGo() (res *pb.TriggerAction) {
|
||||
GpioName: triggerData.GpioName,
|
||||
PullUpDown: pb.GPIOInPullUpDown(triggerData.PullUpDown),
|
||||
GpioInEdge: pb.GPIOInEdge(triggerData.Edge),
|
||||
DebounceMillis: triggerData.DebounceMillis,
|
||||
},
|
||||
}
|
||||
case TriggerGroupReceive:
|
||||
@ -383,6 +385,7 @@ func (ta *jsTriggerAction) ChangeTriggerType(newTt triggerType) {
|
||||
d.Edge = GPIOInEdgeRising
|
||||
d.GpioName = ""
|
||||
d.PullUpDown = GPIOInPullUp
|
||||
d.DebounceMillis = 0
|
||||
data = d.Object
|
||||
case TriggerGroupReceive:
|
||||
d := &jsTriggerGroupReceive{Object:O()}
|
||||
@ -508,6 +511,7 @@ type jsTriggerGPIOIn struct {
|
||||
GpioName string `js:"GpioName"`
|
||||
PullUpDown GPIOInPullUpDown `js:"PullUpDown"` //PullUp resistor, pull down otherwise
|
||||
Edge GPIOInEdge `js:"Edge"` // 0 == GPIO.RISING, 1 == GPIO.FALLING, every value > 1 == GPIO.BOTH
|
||||
DebounceMillis int64 `js:"DebounceMillis"`
|
||||
}
|
||||
type GPIOInPullUpDown int
|
||||
const GPIOInPullUp = GPIOInPullUpDown(0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user