wolbodge/devices/libgpiod.go
2025-03-22 14:27:28 +01:00

100 lines
1.7 KiB
Go

package devices
import (
"fmt"
"os/exec"
"sync"
"time"
)
// TODO: Do not use subprocesses here, they are unreliable, provide hidden dependencies and are a common target for vulnerabilities.
func NewLibgpiod(gpiochip string, powerButtonPin int, powerLEDPin int) Device {
device := &libgpiod{
gpiochip: gpiochip,
powerButtonPin: powerButtonPin,
powerLEDPin: powerLEDPin,
lock: sync.Mutex{},
}
return device
}
type libgpiod struct {
gpiochip string
powerButtonPin int
powerLEDPin int
lock sync.Mutex
}
func (d *libgpiod) Status() (bool, error) {
d.lock.Lock()
defer d.lock.Unlock()
status, err := d.read(d.powerLEDPin)
if err != nil {
return false, err
}
return status, nil
}
func (d *libgpiod) PushPowerButton() error {
d.lock.Lock()
defer d.lock.Unlock()
err := d.write(d.powerButtonPin, 1)
if err != nil {
return err
}
time.Sleep(2 * time.Second)
err = d.write(d.powerButtonPin, 0)
if err != nil {
return err
}
return nil
}
func (d *libgpiod) write(pin int, value int) error {
cmd := exec.Command(
"env", "sh", "-c",
fmt.Sprintf("gpioset %s %d=%d", d.gpiochip, pin, value),
)
outRaw, err := cmd.Output()
if err != nil {
return err
}
out := string(outRaw)
if out == "" {
return nil
}
return fmt.Errorf("unexpected command output: %s", err)
}
func (d *libgpiod) read(pin int) (bool, error) {
cmd := exec.Command(
"env", "sh", "-c",
fmt.Sprintf("gpioget --bias pull-down %s %d", d.gpiochip, pin),
)
outRaw, err := cmd.Output()
if err != nil {
return false, err
}
out := string(outRaw)
switch out {
case "0\n":
return false, nil
case "1\n":
return true, nil
default:
return false, fmt.Errorf("unexpected command output: %s", out)
}
}