mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-11-15 08:32:06 +01:00
Cleanup, webclient GPIO debounce support
This commit is contained in:
@@ -123,8 +123,6 @@ func (gm *GpioManager) DeployGpioTrigger(in *pb.TriggerGPIOIn) (err error) {
|
|||||||
p.In(pull, edge)
|
p.In(pull, edge)
|
||||||
|
|
||||||
debounceDelay := time.Duration(in.DebounceMillis) * time.Millisecond
|
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() {
|
go func() {
|
||||||
fmt.Println("Starting edge detection for pin " + p.Name())
|
fmt.Println("Starting edge detection for pin " + p.Name())
|
||||||
@@ -153,102 +151,6 @@ func (gm *GpioManager) DeployGpioTrigger(in *pb.TriggerGPIOIn) (err error) {
|
|||||||
return nil
|
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) {
|
func (gm *GpioManager) FireGpioAction(out *pb.ActionGPIOOut) (err error) {
|
||||||
fmt.Println("FireGPIOAction for", out.GpioName)
|
fmt.Println("FireGPIOAction for", out.GpioName)
|
||||||
if !gm.IsUsable {
|
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)
|
fmt.Printf("Setting %s to out level %v...\n", p.Name(), level)
|
||||||
|
|
||||||
p.Out(level)
|
p.Out(level)
|
||||||
fmt.Println("..setting level done")
|
//fmt.Println("..setting level done")
|
||||||
|
|
||||||
return nil
|
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"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"periph.io/x/periph/conn/gpio"
|
"periph.io/x/periph/conn/gpio"
|
||||||
"periph.io/x/periph/conn/physic"
|
"periph.io/x/periph/conn/physic"
|
||||||
"time"
|
"time"
|
||||||
@@ -39,8 +40,7 @@ type P4wnp1PinIO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *P4wnp1PinIO) startEdgeDetection(pull gpio.Pull, edge gpio.Edge, preserveUnconsumed bool) (err error) {
|
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()
|
p.lastEdgeTime = time.Now()
|
||||||
if preserveUnconsumed {
|
if preserveUnconsumed {
|
||||||
@@ -114,7 +114,7 @@ func (p *P4wnp1PinIO) startEdgeDetection(pull gpio.Pull, edge gpio.Edge, preserv
|
|||||||
} else {
|
} else {
|
||||||
//pop old stl from channel if needed
|
//pop old stl from channel if needed
|
||||||
for len(p.edgeDetectionChannel) > 0 {
|
for len(p.edgeDetectionChannel) > 0 {
|
||||||
<- p.edgeDetectionChannel
|
<-p.edgeDetectionChannel
|
||||||
}
|
}
|
||||||
p.edgeDetectionChannel <- stl //put latest stl to channel
|
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(), "stopped")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
||||||
fmt.Println("... edge detection for", p.Name(), "started")
|
fmt.Println("... edge detection for", p.Name(), "started")
|
||||||
fmt.Printf("p: %+v\n",p)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *P4wnp1PinIO) isEdgeDetectionRunning() bool {
|
func (p *P4wnp1PinIO) isEdgeDetectionRunning() bool {
|
||||||
if p.edgeDetectionChannel == nil {
|
if p.edgeDetectionChannel == nil {
|
||||||
fmt.Println("edge detection not running")
|
//fmt.Println("edge detection not running")
|
||||||
fmt.Printf("p: %+v\n",p)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
fmt.Println("edge detection running")
|
//fmt.Println("edge detection running")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *P4wnp1PinIO) stopEdgeDetection() error {
|
func (p *P4wnp1PinIO) stopEdgeDetection() error {
|
||||||
fmt.Println("stopping edge detection for", p.Name(), "...")
|
|
||||||
|
|
||||||
if !p.isEdgeDetectionRunning() {
|
if !p.isEdgeDetectionRunning() {
|
||||||
return EEdgeDetectNotRunning
|
return EEdgeDetectNotRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("stopping edge detection for", p.Name(), "...")
|
||||||
p.edgeDetectionAbort = true
|
p.edgeDetectionAbort = true
|
||||||
|
|
||||||
// hackish approach to end WaitForEdge, by toggling Pull resistors (see comments in startEdgeDetection for details)
|
// hackish approach to end WaitForEdge, by toggling Pull resistors (see comments in startEdgeDetection for details)
|
||||||
@@ -171,8 +167,6 @@ func (p *P4wnp1PinIO) stopEdgeDetection() error {
|
|||||||
<-p.edgeDetectionChannel //wait for close
|
<-p.edgeDetectionChannel //wait for close
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,34 +174,34 @@ func (p P4wnp1PinIO) Edge() gpio.Edge {
|
|||||||
return p.edge
|
return p.edge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *P4wnp1PinIO) ExtWaitForEdge(ctx context.Context, debounceDuration time.Duration) (level gpio.Level, err error) {
|
func (p *P4wnp1PinIO) ExtWaitForEdge(ctx context.Context, debounceDuration time.Duration) (level gpio.Level, err error) {
|
||||||
useDebounce := debounceDuration > 0
|
useDebounce := debounceDuration > 0
|
||||||
|
|
||||||
for { // the select statement is wrapped into a for loop, to account for edges not fulfilling the debounceDuration criteria
|
for { // the select statement is wrapped into a for loop, to account for edges not fulfilling the debounceDuration criteria
|
||||||
select {
|
select {
|
||||||
case steadyTimeLevel,channelOpen := <- p.edgeDetectionChannel:
|
case steadyTimeLevel, channelOpen := <-p.edgeDetectionChannel:
|
||||||
//channel closed, so we return error
|
//channel closed, so we return error
|
||||||
if !channelOpen {
|
if !channelOpen {
|
||||||
return level,EEdgeDetectNotRunning
|
return level, EEdgeDetectNotRunning
|
||||||
}
|
}
|
||||||
if !useDebounce {
|
if !useDebounce {
|
||||||
// no debounce needed, ultimately return the edge change
|
// no debounce needed, ultimately return the edge change
|
||||||
return steadyTimeLevel.Level,nil
|
return steadyTimeLevel.Level, nil
|
||||||
} else {
|
} else {
|
||||||
// we have to assure that no other edge change event occurs in debounce duration (steady level) before returning
|
// we have to assure that no other edge change event occurs in debounce duration (steady level) before returning
|
||||||
if steadyTimeLevel.SteadyTime >= debounceDuration {
|
if steadyTimeLevel.SteadyTime >= debounceDuration {
|
||||||
//detected edge fulfills debounce criteria
|
//detected edge fulfills debounce criteria
|
||||||
return steadyTimeLevel.Level,nil
|
return steadyTimeLevel.Level, nil
|
||||||
}
|
}
|
||||||
// else ignore edge
|
// else ignore edge
|
||||||
fmt.Printf("Ignored detected edge as invalidated by debounce: %v\n", steadyTimeLevel)
|
fmt.Printf("Ignored detected edge as invalidated by debounce: %v\n", steadyTimeLevel)
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return level,EEdgeDetectAborted
|
return level, EEdgeDetectAborted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
func (p P4wnp1PinIO) String() string {
|
func (p P4wnp1PinIO) String() string {
|
||||||
return p.piPin.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) {
|
func (p *P4wnp1PinIO) In(pull gpio.Pull, edge gpio.Edge) (err error) {
|
||||||
fmt.Println("Called In() on ", p.Name())
|
|
||||||
p.stopEdgeDetection()
|
p.stopEdgeDetection()
|
||||||
// bring up edgeDetection go routine (again) if needed
|
// bring up edgeDetection go routine (again) if needed
|
||||||
err = p.piPin.In(pull, edge)
|
err = p.piPin.In(pull, edge)
|
||||||
if err != nil { return }
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
p.pull = pull
|
p.pull = pull
|
||||||
p.edge = edge
|
p.edge = edge
|
||||||
if edge != gpio.NoEdge {
|
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
|
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 {
|
func (p *P4wnp1PinIO) PWM(duty gpio.Duty, f physic.Frequency) error {
|
||||||
//stop edge detection, if needed
|
//stop edge detection, if needed
|
||||||
p.stopEdgeDetection()
|
p.stopEdgeDetection()
|
||||||
return p.piPin.PWM(duty,f)
|
return p.piPin.PWM(duty, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewP4wnp1PinIO(p gpio.PinIO) *P4wnp1PinIO {
|
func NewP4wnp1PinIO(p gpio.PinIO) *P4wnp1PinIO {
|
||||||
return &P4wnp1PinIO{piPin: p}
|
return &P4wnp1PinIO{piPin: p}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -288,6 +288,7 @@ func InitComponentsTriggerActions() {
|
|||||||
strTrigger += t.GpioName
|
strTrigger += t.GpioName
|
||||||
strTrigger += ": " + gpioInEdgeNames[t.Edge]
|
strTrigger += ": " + gpioInEdgeNames[t.Edge]
|
||||||
strTrigger += ", resistor: " + gpioInPullUpDownNames[t.PullUpDown]
|
strTrigger += ", resistor: " + gpioInPullUpDownNames[t.PullUpDown]
|
||||||
|
strTrigger += ", debounce: " + strconv.Itoa(int(t.DebounceMillis)) + "ms"
|
||||||
strTrigger += ")"
|
strTrigger += ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,6 +773,15 @@ const templateTrigger = `
|
|||||||
</q-item-tile>
|
</q-item-tile>
|
||||||
</q-item-main>
|
</q-item-main>
|
||||||
</q-item>
|
</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>
|
</q-list>
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ func (dst *jsTriggerAction) fromGo(src *pb.TriggerAction) {
|
|||||||
dstTrigger.GpioName = srcTrigger.GpioIn.GpioName
|
dstTrigger.GpioName = srcTrigger.GpioIn.GpioName
|
||||||
dstTrigger.Edge = GPIOInEdge(srcTrigger.GpioIn.GpioInEdge)
|
dstTrigger.Edge = GPIOInEdge(srcTrigger.GpioIn.GpioInEdge)
|
||||||
dstTrigger.PullUpDown = GPIOInPullUpDown(srcTrigger.GpioIn.PullUpDown)
|
dstTrigger.PullUpDown = GPIOInPullUpDown(srcTrigger.GpioIn.PullUpDown)
|
||||||
|
dstTrigger.DebounceMillis = srcTrigger.GpioIn.DebounceMillis
|
||||||
case *pb.TriggerAction_GroupReceive:
|
case *pb.TriggerAction_GroupReceive:
|
||||||
dst.ChangeTriggerType(TriggerGroupReceive)
|
dst.ChangeTriggerType(TriggerGroupReceive)
|
||||||
dstTrigger := &jsTriggerGroupReceive{Object: dst.TriggerData}
|
dstTrigger := &jsTriggerGroupReceive{Object: dst.TriggerData}
|
||||||
@@ -264,6 +265,7 @@ func (ta *jsTriggerAction) toGo() (res *pb.TriggerAction) {
|
|||||||
GpioName: triggerData.GpioName,
|
GpioName: triggerData.GpioName,
|
||||||
PullUpDown: pb.GPIOInPullUpDown(triggerData.PullUpDown),
|
PullUpDown: pb.GPIOInPullUpDown(triggerData.PullUpDown),
|
||||||
GpioInEdge: pb.GPIOInEdge(triggerData.Edge),
|
GpioInEdge: pb.GPIOInEdge(triggerData.Edge),
|
||||||
|
DebounceMillis: triggerData.DebounceMillis,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case TriggerGroupReceive:
|
case TriggerGroupReceive:
|
||||||
@@ -383,6 +385,7 @@ func (ta *jsTriggerAction) ChangeTriggerType(newTt triggerType) {
|
|||||||
d.Edge = GPIOInEdgeRising
|
d.Edge = GPIOInEdgeRising
|
||||||
d.GpioName = ""
|
d.GpioName = ""
|
||||||
d.PullUpDown = GPIOInPullUp
|
d.PullUpDown = GPIOInPullUp
|
||||||
|
d.DebounceMillis = 0
|
||||||
data = d.Object
|
data = d.Object
|
||||||
case TriggerGroupReceive:
|
case TriggerGroupReceive:
|
||||||
d := &jsTriggerGroupReceive{Object:O()}
|
d := &jsTriggerGroupReceive{Object:O()}
|
||||||
@@ -508,6 +511,7 @@ type jsTriggerGPIOIn struct {
|
|||||||
GpioName string `js:"GpioName"`
|
GpioName string `js:"GpioName"`
|
||||||
PullUpDown GPIOInPullUpDown `js:"PullUpDown"` //PullUp resistor, pull down otherwise
|
PullUpDown GPIOInPullUpDown `js:"PullUpDown"` //PullUp resistor, pull down otherwise
|
||||||
Edge GPIOInEdge `js:"Edge"` // 0 == GPIO.RISING, 1 == GPIO.FALLING, every value > 1 == GPIO.BOTH
|
Edge GPIOInEdge `js:"Edge"` // 0 == GPIO.RISING, 1 == GPIO.FALLING, every value > 1 == GPIO.BOTH
|
||||||
|
DebounceMillis int64 `js:"DebounceMillis"`
|
||||||
}
|
}
|
||||||
type GPIOInPullUpDown int
|
type GPIOInPullUpDown int
|
||||||
const GPIOInPullUp = GPIOInPullUpDown(0)
|
const GPIOInPullUp = GPIOInPullUpDown(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user