P4wnP1_aloa/service/SubSysGpio.go
2018-12-07 00:59:54 +01:00

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()
}
}