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 get() bool } // 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 } func (b *bbGPIO) get() bool { b.mu.Lock() defer b.mu.Unlock() return b.state } // 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 } func (b *fakeGPIO) get() bool { b.mu.Lock() defer b.mu.Unlock() return b.state }