diff --git a/plugin/gpio_linux.go b/plugin/gpio_linux.go index 8329e5ae5..851496677 100644 --- a/plugin/gpio_linux.go +++ b/plugin/gpio_linux.go @@ -17,13 +17,15 @@ func init() { type gpio struct { mu sync.Mutex + typ GpioType pin rpio.Pin } // NewGpioPluginFromConfig creates a GPIO provider func NewGpioPluginFromConfig(ctx context.Context, other map[string]any) (Plugin, error) { var cc struct { - Pin int + Type GpioType + Pin int } if err := util.DecodeOther(other, &cc); err != nil { @@ -31,6 +33,7 @@ func NewGpioPluginFromConfig(ctx context.Context, other map[string]any) (Plugin, } p := &gpio{ + typ: cc.Type, pin: rpio.Pin(cc.Pin), } @@ -40,7 +43,14 @@ func NewGpioPluginFromConfig(ctx context.Context, other map[string]any) (Plugin, } defer rpio.Close() - p.pin.Input() + switch cc.Type { + case GpioTypeRead: + p.pin.Input() + case GpioTypeWrite: + p.pin.Output() + default: + return nil, fmt.Errorf("invalid type: %s", cc.Type) + } return p, nil } @@ -49,6 +59,10 @@ var _ BoolGetter = (*gpio)(nil) // BoolGetter returns GPIO pin active func (p *gpio) BoolGetter() (func() (bool, error), error) { + if p.typ != GpioTypeRead { + return nil, fmt.Errorf("invalid gpio type: %s", p.typ) + } + return func() (bool, error) { p.mu.Lock() defer p.mu.Unlock() @@ -61,3 +75,27 @@ func (p *gpio) BoolGetter() (func() (bool, error), error) { return p.pin.Read() != rpio.Low, nil }, nil } + +var _ BoolSetter = (*gpio)(nil) + +// BoolSetter returns GPIO pin active +func (p *gpio) BoolSetter(_ string) (func(bool) error, error) { + if p.typ != GpioTypeWrite { + return nil, fmt.Errorf("invalid gpio type: %s", p.typ) + } + + return func(b bool) error { + p.mu.Lock() + defer p.mu.Unlock() + + if err := rpio.Open(); err != nil { + return fmt.Errorf("failed to open GPIO: %w", err) + } + defer rpio.Close() + + val := map[bool]rpio.State{false: rpio.Low, true: rpio.High}[b] + p.pin.Write(val) + + return nil + }, nil +} diff --git a/plugin/gpiotype.go b/plugin/gpiotype.go new file mode 100644 index 000000000..3fd9ca970 --- /dev/null +++ b/plugin/gpiotype.go @@ -0,0 +1,9 @@ +package plugin + +type GpioType int + +//go:generate go tool enumer -type GpioType -trimprefix GpioType -transform=lower -text +const ( + GpioTypeRead GpioType = iota + GpioTypeWrite +) diff --git a/plugin/gpiotype_enumer.go b/plugin/gpiotype_enumer.go new file mode 100644 index 000000000..f0a0a7a55 --- /dev/null +++ b/plugin/gpiotype_enumer.go @@ -0,0 +1,90 @@ +// Code generated by "enumer -type GpioType -trimprefix GpioType -transform=lower -text"; DO NOT EDIT. + +package plugin + +import ( + "fmt" + "strings" +) + +const _GpioTypeName = "readwrite" + +var _GpioTypeIndex = [...]uint8{0, 4, 9} + +const _GpioTypeLowerName = "readwrite" + +func (i GpioType) String() string { + if i < 0 || i >= GpioType(len(_GpioTypeIndex)-1) { + return fmt.Sprintf("GpioType(%d)", i) + } + return _GpioTypeName[_GpioTypeIndex[i]:_GpioTypeIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _GpioTypeNoOp() { + var x [1]struct{} + _ = x[GpioTypeRead-(0)] + _ = x[GpioTypeWrite-(1)] +} + +var _GpioTypeValues = []GpioType{GpioTypeRead, GpioTypeWrite} + +var _GpioTypeNameToValueMap = map[string]GpioType{ + _GpioTypeName[0:4]: GpioTypeRead, + _GpioTypeLowerName[0:4]: GpioTypeRead, + _GpioTypeName[4:9]: GpioTypeWrite, + _GpioTypeLowerName[4:9]: GpioTypeWrite, +} + +var _GpioTypeNames = []string{ + _GpioTypeName[0:4], + _GpioTypeName[4:9], +} + +// GpioTypeString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func GpioTypeString(s string) (GpioType, error) { + if val, ok := _GpioTypeNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _GpioTypeNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to GpioType values", s) +} + +// GpioTypeValues returns all values of the enum +func GpioTypeValues() []GpioType { + return _GpioTypeValues +} + +// GpioTypeStrings returns a slice of all String values of the enum +func GpioTypeStrings() []string { + strs := make([]string, len(_GpioTypeNames)) + copy(strs, _GpioTypeNames) + return strs +} + +// IsAGpioType returns "true" if the value is listed in the enum definition. "false" otherwise +func (i GpioType) IsAGpioType() bool { + for _, v := range _GpioTypeValues { + if i == v { + return true + } + } + return false +} + +// MarshalText implements the encoding.TextMarshaler interface for GpioType +func (i GpioType) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for GpioType +func (i *GpioType) UnmarshalText(text []byte) error { + var err error + *i, err = GpioTypeString(string(text)) + return err +}