mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-17 13:21:50 +01:00
194 lines
4.1 KiB
Go
194 lines
4.1 KiB
Go
// +build linux
|
|
|
|
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/mame82/P4wnP1_aloa/service/pgpio"
|
|
"periph.io/x/periph"
|
|
"periph.io/x/periph/conn/gpio"
|
|
"periph.io/x/periph/conn/gpio/gpioreg"
|
|
"periph.io/x/periph/conn/pin/pinreg"
|
|
"periph.io/x/periph/host"
|
|
"periph.io/x/periph/host/rpi"
|
|
"sync"
|
|
"time"
|
|
"errors"
|
|
pb "github.com/mame82/P4wnP1_aloa/proto"
|
|
)
|
|
|
|
var (
|
|
EGpioNotAvailable = errors.New("sub system GPIO not available")
|
|
EGpioPinInvalid = errors.New("invalid GPIO pin")
|
|
)
|
|
|
|
type GpioManager struct {
|
|
availableGpioPins []*pgpio.P4wnp1PinIO
|
|
availableGpioPinsMap map[string]*pgpio.P4wnp1PinIO
|
|
availableGpioNames []string
|
|
|
|
rootSvc *Service
|
|
|
|
edgeDetectingMutex *sync.Mutex
|
|
edgeDetecting map[gpio.PinIO]bool
|
|
|
|
IsUsable bool
|
|
|
|
*periph.State
|
|
}
|
|
|
|
func (gm *GpioManager) Start() {
|
|
|
|
}
|
|
|
|
func (gm *GpioManager) Stop() {
|
|
}
|
|
|
|
func NewGpioManager(rootSvc *Service) (res *GpioManager) {
|
|
gm := &GpioManager{
|
|
rootSvc: rootSvc,
|
|
}
|
|
state, err := host.Init()
|
|
if err != nil {
|
|
gm.IsUsable = false
|
|
return
|
|
}
|
|
|
|
gm.State = state
|
|
gm.IsUsable = rpi.Present()
|
|
|
|
gm.availableGpioPinsMap = make(map[string]*pgpio.P4wnp1PinIO)
|
|
gpios := gpioreg.All()
|
|
for _, g := range gpios {
|
|
if pinreg.IsConnected(g) {
|
|
ppin := pgpio.NewP4wnp1PinIO(g)
|
|
gm.availableGpioPins = append(gm.availableGpioPins, ppin)
|
|
gm.availableGpioPinsMap[g.Name()] = ppin
|
|
gm.availableGpioNames = append(gm.availableGpioNames, g.Name())
|
|
}
|
|
}
|
|
|
|
|
|
gm.edgeDetecting = make(map[gpio.PinIO]bool)
|
|
gm.edgeDetectingMutex = &sync.Mutex{}
|
|
|
|
return gm
|
|
}
|
|
|
|
func (gm *GpioManager) GetAvailableGpios() (res []*pgpio.P4wnp1PinIO, err error) {
|
|
if gm.IsUsable {
|
|
return gm.availableGpioPins, nil
|
|
}
|
|
return res, EGpioNotAvailable
|
|
}
|
|
|
|
func (gm *GpioManager) GetAvailableGpioNames() (res []string, err error) {
|
|
if gm.IsUsable {
|
|
return gm.availableGpioNames, nil
|
|
}
|
|
return res, EGpioNotAvailable
|
|
}
|
|
|
|
|
|
|
|
func (gm *GpioManager) DeployGpioTrigger(in *pb.TriggerGPIOIn) (err error) {
|
|
if !gm.IsUsable {
|
|
return EGpioNotAvailable
|
|
}
|
|
|
|
p,present := gm.availableGpioPinsMap[in.GpioName]
|
|
if !present {
|
|
return EGpioPinInvalid
|
|
}
|
|
|
|
fmt.Printf("Deploying trigger for GPIO: %+v\n", p)
|
|
|
|
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
|
|
}
|
|
|
|
p.In(pull, edge)
|
|
|
|
debounceDelay := time.Duration(in.DebounceMillis) * time.Millisecond
|
|
|
|
go func() {
|
|
fmt.Println("Starting edge detection for pin " + p.Name())
|
|
detectErr := error(nil)
|
|
for detectErr == nil {
|
|
var detectedLevel gpio.Level
|
|
detectedLevel,detectErr = p.ExtWaitForEdge(context.Background(), debounceDelay)
|
|
|
|
fmt.Printf("... done wait for edge %s level: %v\n", p.Name(), detectedLevel)
|
|
|
|
//Edge detected, check if still edge detecting before consuming
|
|
|
|
switch detectedLevel {
|
|
case gpio.High:
|
|
fmt.Println("Gpio " + p.Name() + " changed to high")
|
|
gm.rootSvc.SubSysEvent.Emit(ConstructEventTriggerGpioIn(p.Name(), bool(gpio.High)))
|
|
|
|
case gpio.Low:
|
|
fmt.Println("Gpio " + p.Name() + " changed to low")
|
|
gm.rootSvc.SubSysEvent.Emit(ConstructEventTriggerGpioIn(p.Name(), bool(gpio.Low)))
|
|
}
|
|
}
|
|
fmt.Println("!!!! STOPPED edge loop for pin " + p.Name())
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (gm *GpioManager) FireGpioAction(out *pb.ActionGPIOOut) (err error) {
|
|
fmt.Println("FireGPIOAction for", out.GpioName)
|
|
if !gm.IsUsable {
|
|
return EGpioNotAvailable
|
|
}
|
|
|
|
p,present := gm.availableGpioPinsMap[out.GpioName]
|
|
if !present {
|
|
return EGpioPinInvalid
|
|
}
|
|
|
|
level := gpio.Low
|
|
switch out.Value {
|
|
case pb.GPIOOutValue_HIGH:
|
|
level = gpio.High
|
|
case pb.GPIOOutValue_TOGGLE:
|
|
if p.Read() == gpio.Low {
|
|
level = gpio.High
|
|
}
|
|
}
|
|
|
|
fmt.Printf("Setting %s to out level %v...\n", p.Name(), level)
|
|
|
|
p.Out(level)
|
|
//fmt.Println("..setting level done")
|
|
|
|
return nil
|
|
}
|
|
|
|
func (gm *GpioManager) ResetPins() {
|
|
fmt.Println("Resetting all pins")
|
|
for _, pin := range gm.availableGpioPins {
|
|
if pin.Edge() != gpio.NoEdge {
|
|
pin.In(gpio.Float, gpio.NoEdge)
|
|
}
|
|
fmt.Println("... halting pin " + pin.Name())
|
|
pin.Halt()
|
|
}
|
|
|
|
}
|