jeol-t330a/succbone/succd/gpio.go

93 lines
2.1 KiB
Go
Raw Permalink Normal View History

package main
import (
"fmt"
"os"
"sync"
"k8s.io/klog"
)
// gpio is an abstract GPIO output.
type gpio interface {
// set returns the GPIO value. The meaning of the logic level is
// implementation-dependent.
set(state bool) error
}
// bbGPIO implements gpio using BeagleBone's built-in GPIO pins.
//
// The value of a GPIO is logically non-inverted: false is 0V, true is 3.3V.
//
// The GPIO can be repeatedly set to the same value without performance penalty
// - only level changes are actually written to hardware registers.
type bbGPIO struct {
path string
mu sync.Mutex
state bool
}
// newBBGPIO returns a BeagleBone GPIO for a given GPIO number.
//
// See the following for GPIO pin numbers ('GPIO NO.' column):
//
// https://vadl.github.io/images/bbb/P8Header.png
// https://vadl.github.io/images/bbb/P9Header.png
func newBBGPIO(num int, value bool) (*bbGPIO, error) {
path := fmt.Sprintf("/sys/class/gpio/gpio%d", num)
if _, err := os.Stat(path); err != nil {
return nil, fmt.Errorf("could not access: %w", err)
}
pathDir := path + "/direction"
if err := os.WriteFile(pathDir, []byte("out"), 0); err != nil {
return nil, fmt.Errorf("could not set direction: %w", err)
}
pathValue := path + "/value"
res := &bbGPIO{
path: pathValue,
}
if err := res.set(value); err != nil {
return nil, fmt.Errorf("when setting initial value: %w", err)
}
return res, nil
}
func (b *bbGPIO) set(state bool) error {
b.mu.Lock()
defer b.mu.Unlock()
if state && !b.state {
if err := os.WriteFile(b.path, []byte("1"), 0); err != nil {
return fmt.Errorf("could not turn on: %w", err)
}
} else if !state && b.state {
if err := os.WriteFile(b.path, []byte("0"), 0); err != nil {
return fmt.Errorf("could not turn off: %w", err)
}
}
b.state = state
return nil
}
// fakeGPIO implements a GPIO that logs state changes.
type fakeGPIO struct {
desc string
mu sync.Mutex
state bool
}
func (b *fakeGPIO) set(state bool) error {
b.mu.Lock()
defer b.mu.Unlock()
if state && !b.state {
klog.Infof("%s on", b.desc)
} else if !state && b.state {
klog.Infof("%s off", b.desc)
}
b.state = state
return nil
}