Skip to content

Commit

Permalink
[RSDK-2782] Remove Periph GPIO from genericlinux boards (viamrobotics…
Browse files Browse the repository at this point in the history
…#2603)

The only board that was still using this was the nanopi, which has been relegated over to https://github.com/viam-labs/periph_board. I believe the only folks using that board were Peter L and Bee Ring, who already know about this change, and it has always been marked as experimental and not guaranteed to work.
  • Loading branch information
penguinland authored Jul 10, 2023
1 parent bf95924 commit 8049512
Show file tree
Hide file tree
Showing 12 changed files with 47 additions and 341 deletions.
3 changes: 1 addition & 2 deletions components/board/beaglebone/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ func init() {
golog.Global().Debugw("error getting beaglebone GPIO board mapping", "error", err)
}

// The false on this line means we're not using Periph. This lets us enable hardware PWM pins.
genericlinux.RegisterBoard(modelName, gpioMappings, false)
genericlinux.RegisterBoard(modelName, gpioMappings)
}
125 changes: 13 additions & 112 deletions components/board/genericlinux/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,14 @@ import (
commonpb "go.viam.com/api/common/v1"
pb "go.viam.com/api/component/board/v1"
goutils "go.viam.com/utils"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"periph.io/x/conn/v3/physic"

"go.viam.com/rdk/components/board"
"go.viam.com/rdk/grpc"
"go.viam.com/rdk/resource"
)

// RegisterBoard registers a sysfs based board of the given model.
func RegisterBoard(modelName string, gpioMappings map[int]GPIOBoardMapping, usePeriphGpio bool) {
func RegisterBoard(modelName string, gpioMappings map[int]GPIOBoardMapping) {
resource.RegisterComponent(
board.API,
resource.DefaultModelFamily.WithModel(modelName),
Expand All @@ -39,7 +36,7 @@ func RegisterBoard(modelName string, gpioMappings map[int]GPIOBoardMapping, useP
conf resource.Config,
logger golog.Logger,
) (board.Board, error) {
return newBoard(ctx, conf, gpioMappings, usePeriphGpio, logger)
return newBoard(ctx, conf, gpioMappings, logger)
},
})
}
Expand All @@ -48,22 +45,18 @@ func newBoard(
ctx context.Context,
conf resource.Config,
gpioMappings map[int]GPIOBoardMapping,
usePeriphGpio bool,
logger golog.Logger,
) (board.Board, error) {
cancelCtx, cancelFunc := context.WithCancel(context.Background())
b := sysfsBoard{
Named: conf.ResourceName().AsNamed(),
usePeriphGpio: usePeriphGpio,
gpioMappings: gpioMappings,
logger: logger,
cancelCtx: cancelCtx,
cancelFunc: cancelFunc,

spis: map[string]*spiBus{},
analogs: map[string]*wrappedAnalog{},
// this is not yet modified during reconfiguration but maybe should be
pwms: map[string]pwmSetting{},
Named: conf.ResourceName().AsNamed(),
gpioMappings: gpioMappings,
logger: logger,
cancelCtx: cancelCtx,
cancelFunc: cancelFunc,

spis: map[string]*spiBus{},
analogs: map[string]*wrappedAnalog{},
i2cs: map[string]*I2cBus{},
gpios: map[string]*gpioPin{},
interrupts: map[string]*digitalInterrupt{},
Expand Down Expand Up @@ -237,16 +230,8 @@ func findNewDigIntConfig(
}

func (b *sysfsBoard) reconfigureInterrupts(newConf *Config) error {
if b.usePeriphGpio {
if len(newConf.DigitalInterrupts) != 0 {
return errors.New("digital interrupts on Periph GPIO pins are not yet supported")
}
return nil // No digital interrupts to reconfigure.
}

// If we get here, we need to reconfigure b.interrupts. Any pin that already exists in the
// right configuration should just be copied over; closing and re-opening it risks losing its
// state.
// Any pin that already exists in the right configuration should just be copied over; closing
// and re-opening it risks losing its state.
newInterrupts := make(map[string]*digitalInterrupt, len(newConf.DigitalInterrupts))

// Reuse any old interrupts that have new configs
Expand Down Expand Up @@ -362,12 +347,9 @@ type sysfsBoard struct {
gpioMappings map[int]GPIOBoardMapping
spis map[string]*spiBus
analogs map[string]*wrappedAnalog
pwms map[string]pwmSetting
i2cs map[string]*I2cBus
logger golog.Logger

usePeriphGpio bool
// These next two are only used for non-periph.io pins
gpios map[string]*gpioPin
interrupts map[string]*digitalInterrupt

Expand All @@ -376,11 +358,6 @@ type sysfsBoard struct {
activeBackgroundWorkers sync.WaitGroup
}

type pwmSetting struct {
dutyCycle gpio.Duty
frequency physic.Frequency
}

func (b *sysfsBoard) SPIByName(name string) (board.SPI, bool) {
s, ok := b.spis[name]
return s, ok
Expand All @@ -397,10 +374,6 @@ func (b *sysfsBoard) AnalogReaderByName(name string) (board.AnalogReader, bool)
}

func (b *sysfsBoard) DigitalInterruptByName(name string) (board.DigitalInterrupt, bool) {
if b.usePeriphGpio {
return nil, false // Digital interrupts aren't supported.
}

b.mu.Lock()
defer b.mu.Unlock()

Expand Down Expand Up @@ -491,86 +464,19 @@ func (b *sysfsBoard) GPIOPinNames() []string {
return names
}

func (b *sysfsBoard) getGPIOLine(hwPin string) (gpio.PinIO, error) {
pinName := hwPin

pin := gpioreg.ByName(pinName)
if pin == nil {
return nil, errors.Errorf("no global pin found for %q", pinName)
}
return pin, nil
}

func (b *sysfsBoard) GPIOPinByName(pinName string) (board.GPIOPin, error) {
if b.usePeriphGpio {
return b.periphGPIOPinByName(pinName)
}
// Otherwise, the pins are stored in b.gpios.
if pin, ok := b.gpios[pinName]; ok {
return pin, nil
}

// check if pin is a digital interrupt
// Check if pin is a digital interrupt: those can still be used as inputs.
if interrupt, interruptOk := b.interrupts[pinName]; interruptOk {
return &gpioInterruptWrapperPin{*interrupt}, nil
}

return nil, errors.Errorf("cannot find GPIO for unknown pin: %s", pinName)
}

func (b *sysfsBoard) periphGPIOPinByName(pinName string) (board.GPIOPin, error) {
pin, err := b.getGPIOLine(pinName)
hwPWMSupported := false
if err != nil {
return nil, err
}

return periphGpioPin{b, pin, pinName, hwPWMSupported}, nil
}

// expects to already have lock acquired.
func (b *sysfsBoard) startSoftwarePWMLoop(gp periphGpioPin) {
b.activeBackgroundWorkers.Add(1)
goutils.ManagedGo(func() {
b.softwarePWMLoop(b.cancelCtx, gp)
}, b.activeBackgroundWorkers.Done)
}

func (b *sysfsBoard) softwarePWMLoop(ctx context.Context, gp periphGpioPin) {
for {
cont := func() bool {
b.mu.RLock()
defer b.mu.RUnlock()
pwmSetting, ok := b.pwms[gp.pinName]
if !ok {
b.logger.Debug("pwm setting deleted; stopping")
return false
}

if err := gp.set(true); err != nil {
b.logger.Errorw("error setting pin", "pin_name", gp.pinName, "error", err)
return true
}
onPeriod := time.Duration(
int64((float64(pwmSetting.dutyCycle) / float64(gpio.DutyMax)) * float64(pwmSetting.frequency.Period())),
)
if !goutils.SelectContextOrWait(ctx, onPeriod) {
return false
}
if err := gp.set(false); err != nil {
b.logger.Errorw("error setting pin", "pin_name", gp.pinName, "error", err)
return true
}
offPeriod := pwmSetting.frequency.Period() - onPeriod

return goutils.SelectContextOrWait(ctx, offPeriod)
}()
if !cont {
return
}
}
}

func (b *sysfsBoard) Status(ctx context.Context, extra map[string]interface{}) (*commonpb.BoardStatus, error) {
return &commonpb.BoardStatus{}, nil
}
Expand All @@ -589,11 +495,6 @@ func (b *sysfsBoard) Close(ctx context.Context) error {
b.mu.Unlock()
b.activeBackgroundWorkers.Wait()

// For non-Periph boards, shut down all our open pins so we don't leak file descriptors
if b.usePeriphGpio {
return nil
}

var err error
for _, pin := range b.gpios {
err = multierr.Combine(err, pin.Close())
Expand Down
2 changes: 1 addition & 1 deletion components/board/genericlinux/board_nonlinux.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

// RegisterBoard would register a sysfs based board of the given model. However, this one never
// creates a board, and instead returns errors about making a Linux board on a non-Linux OS.
func RegisterBoard(modelName string, gpioMappings map[int]GPIOBoardMapping, usePeriphGpio bool) {
func RegisterBoard(modelName string, gpioMappings map[int]GPIOBoardMapping) {
resource.RegisterComponent(
board.API,
resource.DefaultModelFamily.WithModel(modelName),
Expand Down
Loading

0 comments on commit 8049512

Please sign in to comment.