A quick and dirty implementation
This commit is contained in:
parent
3682810e27
commit
f6e9c70eb3
352 changed files with 242881 additions and 0 deletions
68
light/rpi/basic_light.go
Normal file
68
light/rpi/basic_light.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
package rpi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/warthog618/gpiod"
|
||||
)
|
||||
|
||||
// BasicLight is a BasicLight implementation for the Raspberry Pi
|
||||
type BasicLight struct {
|
||||
pin int
|
||||
line *gpiod.Line
|
||||
manager *Manager
|
||||
isOn bool
|
||||
isOnLock sync.Mutex
|
||||
}
|
||||
|
||||
// On turns on the light
|
||||
func (bl *BasicLight) On() error {
|
||||
bl.isOnLock.Lock()
|
||||
defer bl.isOnLock.Unlock()
|
||||
|
||||
if bl.isOn {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := bl.line.SetValue(0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set pin %d to low (on): %w", bl.pin, err)
|
||||
}
|
||||
|
||||
bl.isOn = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Off turns off the light
|
||||
func (bl *BasicLight) Off() error {
|
||||
bl.isOnLock.Lock()
|
||||
defer bl.isOnLock.Unlock()
|
||||
|
||||
if !bl.isOn {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := bl.line.SetValue(1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set pin %d to high (on): %w", bl.pin, err)
|
||||
}
|
||||
|
||||
bl.isOn = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// State of whether the light is on or off
|
||||
func (bl *BasicLight) State() (isOn bool, err error) {
|
||||
bl.isOnLock.Lock()
|
||||
defer bl.isOnLock.Unlock()
|
||||
|
||||
return bl.isOn, nil
|
||||
}
|
||||
|
||||
// Close underlying open connection
|
||||
func (bl *BasicLight) Close() error {
|
||||
return bl.manager.closeLine(bl.pin)
|
||||
}
|
121
light/rpi/manager.go
Normal file
121
light/rpi/manager.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package rpi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/warthog618/gpiod"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultChipName to try to use if one is not provided
|
||||
DefaultChipName = "gpiochip0"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrLineAlreadyRequested denotes that the requested line is not available because it has already been requested and not Closed
|
||||
ErrLineAlreadyRequested = errors.New("line has already been requested")
|
||||
|
||||
// ErrLineNotRequested denotes that the given line cannot be acted on because it was not previously requested
|
||||
ErrLineNotRequested = errors.New("line was not previously requested")
|
||||
)
|
||||
|
||||
// ManagerConfig configuration for a Manager
|
||||
type ManagerConfig struct {
|
||||
ChipName string
|
||||
}
|
||||
|
||||
// GetChipName from the config
|
||||
func (mc *ManagerConfig) GetChipName() string {
|
||||
if mc.ChipName == "" {
|
||||
return DefaultChipName
|
||||
}
|
||||
|
||||
return mc.ChipName
|
||||
}
|
||||
|
||||
// Manager for overarching raspberry pi GPIO management
|
||||
type Manager struct {
|
||||
config *ManagerConfig
|
||||
chip *gpiod.Chip
|
||||
lines map[int]*gpiod.Line
|
||||
linesLock sync.Mutex
|
||||
}
|
||||
|
||||
// NewManager creates a new Manager instance for the given config
|
||||
func NewManager(config ManagerConfig) (*Manager, error) {
|
||||
chip, err := gpiod.NewChip(config.GetChipName())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open GPIO chip %s: %w", config.GetChipName(), err)
|
||||
}
|
||||
|
||||
return &Manager{
|
||||
config: &config,
|
||||
chip: chip,
|
||||
lines: make(map[int]*gpiod.Line),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetBasicLight for the given pin if available
|
||||
func (m *Manager) GetBasicLight(pin int) (*BasicLight, error) {
|
||||
line, err := m.requestLine(pin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BasicLight{
|
||||
pin: pin,
|
||||
line: line,
|
||||
manager: m,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Manager) requestLine(pin int) (*gpiod.Line, error) {
|
||||
m.linesLock.Lock()
|
||||
defer m.linesLock.Unlock()
|
||||
|
||||
_, exists := m.lines[pin]
|
||||
if exists {
|
||||
return nil, fmt.Errorf("%w pin %d", ErrLineAlreadyRequested, pin)
|
||||
}
|
||||
|
||||
line, err := m.chip.RequestLine(pin, gpiod.AsOutput(0))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to request line for pin %d: %w", pin, err)
|
||||
}
|
||||
|
||||
m.lines[pin] = line
|
||||
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (m *Manager) closeLine(pin int) error {
|
||||
m.linesLock.Lock()
|
||||
defer m.linesLock.Unlock()
|
||||
|
||||
return m.closeLineHelper(pin)
|
||||
}
|
||||
|
||||
func (m *Manager) closeLineHelper(pin int) error {
|
||||
line := m.lines[pin]
|
||||
if line == nil {
|
||||
return fmt.Errorf("%w pin %d", ErrLineNotRequested, pin)
|
||||
}
|
||||
|
||||
delete(m.lines, pin)
|
||||
|
||||
return line.Close()
|
||||
}
|
||||
|
||||
// Close this Manager and all of its associated lines
|
||||
func (m *Manager) Close() error {
|
||||
m.linesLock.Lock()
|
||||
defer m.linesLock.Unlock()
|
||||
|
||||
for pin := range m.lines {
|
||||
m.closeLineHelper(pin)
|
||||
}
|
||||
|
||||
return m.chip.Close()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue