82 lines
2.1 KiB
Go
82 lines
2.1 KiB
Go
|
package system
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
func startEdgePolling(
|
||
|
pinLabel string,
|
||
|
pinReadFunc func() (int, error),
|
||
|
pollInterval time.Duration,
|
||
|
wantedEdge int,
|
||
|
eventHandler func(offset int, t time.Duration, et string, sn uint32, lsn uint32),
|
||
|
quitChan chan struct{},
|
||
|
) error {
|
||
|
if eventHandler == nil {
|
||
|
return fmt.Errorf("an event handler is mandatory for edge polling")
|
||
|
}
|
||
|
if quitChan == nil {
|
||
|
return fmt.Errorf("the quit channel is mandatory for edge polling")
|
||
|
}
|
||
|
|
||
|
const allEdges = "all"
|
||
|
|
||
|
triggerEventOn := "none"
|
||
|
switch wantedEdge {
|
||
|
case digitalPinEventOnFallingEdge:
|
||
|
triggerEventOn = DigitalPinEventFallingEdge
|
||
|
case digitalPinEventOnRisingEdge:
|
||
|
triggerEventOn = DigitalPinEventRisingEdge
|
||
|
case digitalPinEventOnBothEdges:
|
||
|
triggerEventOn = allEdges
|
||
|
default:
|
||
|
return fmt.Errorf("unsupported edge type %d for edge polling", wantedEdge)
|
||
|
}
|
||
|
|
||
|
wg := sync.WaitGroup{}
|
||
|
wg.Add(1)
|
||
|
|
||
|
go func() {
|
||
|
var oldState int
|
||
|
var readStart time.Time
|
||
|
var firstLoopDone bool
|
||
|
for {
|
||
|
select {
|
||
|
case <-quitChan:
|
||
|
return
|
||
|
default:
|
||
|
// note: pure reading takes between 30us and 1ms on rasperry Pi1, typically 50us, with sysfs also 500us
|
||
|
// can happen, so we use the time stamp before start of reading to reduce random duration offset
|
||
|
readStart = time.Now()
|
||
|
readValue, err := pinReadFunc()
|
||
|
if err != nil {
|
||
|
fmt.Printf("edge polling error occurred while reading the pin %s: %v", pinLabel, err)
|
||
|
readValue = oldState // keep the value
|
||
|
}
|
||
|
if readValue != oldState {
|
||
|
detectedEdge := DigitalPinEventRisingEdge
|
||
|
if readValue < oldState {
|
||
|
detectedEdge = DigitalPinEventFallingEdge
|
||
|
}
|
||
|
if firstLoopDone && (triggerEventOn == allEdges || triggerEventOn == detectedEdge) {
|
||
|
eventHandler(0, time.Duration(readStart.UnixNano()), detectedEdge, 0, 0)
|
||
|
}
|
||
|
oldState = readValue
|
||
|
}
|
||
|
// the real poll interval is increased by the reading time, see also note above
|
||
|
// negative or zero duration causes no sleep
|
||
|
time.Sleep(pollInterval - time.Since(readStart))
|
||
|
if !firstLoopDone {
|
||
|
wg.Done()
|
||
|
firstLoopDone = true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
wg.Wait()
|
||
|
return nil
|
||
|
}
|