2024-09-25 21:28:57 +00:00
|
|
|
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
|
2024-10-26 17:42:35 +00:00
|
|
|
get() bool
|
2024-09-25 21:28:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2024-10-26 17:42:35 +00:00
|
|
|
func (b *bbGPIO) get() bool {
|
|
|
|
b.mu.Lock()
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
return b.state
|
|
|
|
}
|
|
|
|
|
2024-09-25 21:28:57 +00:00
|
|
|
// 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
|
|
|
|
}
|
2024-10-26 17:42:35 +00:00
|
|
|
|
|
|
|
func (b *fakeGPIO) get() bool {
|
|
|
|
b.mu.Lock()
|
|
|
|
defer b.mu.Unlock()
|
|
|
|
return b.state
|
|
|
|
}
|