Skip to content

Commit 0c89cf5

Browse files
committed
refactor(rpiplatform): migrate from go-rpio to periph.io for GPIO/SPI
1 parent 63db7e1 commit 0c89cf5

3 files changed

Lines changed: 69 additions & 27 deletions

File tree

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ require (
1111
github.com/gordonklaus/portaudio v0.0.0-20250206071425-98a94950218b
1212
github.com/nathan-osman/go-sunrise v1.1.0
1313
github.com/rivo/tview v0.0.0-20250625164341-a4a78f1e05cb
14-
github.com/stianeikeland/go-rpio/v4 v4.6.0
1514
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792
1615
gopkg.in/yaml.v3 v3.0.1
16+
periph.io/x/conn/v3 v3.7.2
17+
periph.io/x/host/v3 v3.8.5
1718
)
1819

1920
require (

go.sum

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JX
1111
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
1212
github.com/gordonklaus/portaudio v0.0.0-20250206071425-98a94950218b h1:WEuQWBxelOGHA6z9lABqaMLMrfwVyMdN3UgRLT+YUPo=
1313
github.com/gordonklaus/portaudio v0.0.0-20250206071425-98a94950218b/go.mod h1:esZFQEUwqC+l76f2R8bIWSwXMaPbp79PppwZ1eJhFco=
14+
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
15+
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
1416
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
1517
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
1618
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
@@ -25,8 +27,6 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
2527
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
2628
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
2729
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
28-
github.com/stianeikeland/go-rpio/v4 v4.6.0 h1:eAJgtw3jTtvn/CqwbC82ntcS+dtzUTgo5qlZKe677EY=
29-
github.com/stianeikeland/go-rpio/v4 v4.6.0/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o=
3030
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
3131
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
3232
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -103,3 +103,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
103103
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
104104
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
105105
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
106+
periph.io/x/conn/v3 v3.7.2 h1:qt9dE6XGP5ljbFnCKRJ9OOCoiOyBGlw7JZgoi72zZ1s=
107+
periph.io/x/conn/v3 v3.7.2/go.mod h1:Ao0b4sFRo4QOx6c1tROJU1fLJN1hUIYggjOrkIVnpGg=
108+
periph.io/x/host/v3 v3.8.5 h1:g4g5xE1XZtDiGl1UAJaUur1aT7uNiFLMkyMEiZ7IHII=
109+
periph.io/x/host/v3 v3.8.5/go.mod h1:hPq8dISZIc+UNfWoRj+bPH3XEBQqJPdFdx218W92mdc=

platform/rpiplatform.go

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,22 @@ import (
88
"sync"
99
"time"
1010

11-
"github.com/stianeikeland/go-rpio/v4"
1211
"lautenbacher.net/goleds/config"
1312
"lautenbacher.net/goleds/producer"
1413
"lautenbacher.net/goleds/util"
14+
"periph.io/x/conn/v3/gpio"
15+
"periph.io/x/conn/v3/gpio/gpioreg"
16+
"periph.io/x/conn/v3/physic"
17+
"periph.io/x/conn/v3/spi"
18+
"periph.io/x/conn/v3/spi/spireg"
19+
"periph.io/x/host/v3"
1520
)
1621

1722
type RaspberryPiPlatform struct {
1823
*AbstractPlatform
1924
ledDriver ledDriver
25+
spiPort spi.PortCloser
26+
spiConn spi.Conn
2027
spiMutex sync.Mutex
2128
spimultiplexcfg map[string]gpiocfg
2229
sensorViewer *SensorViewer
@@ -26,8 +33,8 @@ type RaspberryPiPlatform struct {
2633
}
2734

2835
type gpiocfg struct {
29-
low []rpio.Pin
30-
high []rpio.Pin
36+
low []gpio.PinIO
37+
high []gpio.PinIO
3138
}
3239

3340
func NewRaspberryPiPlatform(conf *config.Config) *RaspberryPiPlatform {
@@ -55,29 +62,45 @@ func (s *RaspberryPiPlatform) Start(pool *sync.Pool) error {
5562
s.segments = parseDisplaySegments(s.config.Hardware.Display)
5663

5764
slog.Info("Initialise GPIO and Spi...")
58-
if err := rpio.Open(); err != nil {
59-
return fmt.Errorf("failed to open rpio: %w", err)
65+
if _, err := host.Init(); err != nil {
66+
return fmt.Errorf("failed to init periph: %w", err)
6067
}
61-
if err := rpio.SpiBegin(rpio.Spi0); err != nil {
62-
return fmt.Errorf("failed to begin spi: %w", err)
68+
69+
var err error
70+
s.spiPort, err = spireg.Open("")
71+
if err != nil {
72+
return fmt.Errorf("failed to open spi: %w", err)
6373
}
6474

65-
rpio.SpiSpeed(s.config.Hardware.SPIFrequency)
75+
s.spiConn, err = s.spiPort.Connect(physic.Frequency(s.config.Hardware.SPIFrequency)*physic.Hertz, spi.Mode0, 8)
76+
if err != nil {
77+
return fmt.Errorf("failed to connect to spi device: %w", err)
78+
}
6679

6780
s.spimultiplexcfg = make(map[string]gpiocfg, len(s.config.Hardware.SpiMultiplexGPIO))
6881

6982
for key, cfg := range s.config.Hardware.SpiMultiplexGPIO {
70-
low := make([]rpio.Pin, 0, len(cfg.Low))
71-
high := make([]rpio.Pin, 0, len(cfg.High))
72-
for _, pin := range cfg.Low {
73-
rpiopin := rpio.Pin(pin)
74-
rpiopin.Output()
75-
low = append(low, rpiopin)
83+
low := make([]gpio.PinIO, 0, len(cfg.Low))
84+
high := make([]gpio.PinIO, 0, len(cfg.High))
85+
for _, pinName := range cfg.Low {
86+
pin := gpioreg.ByName(fmt.Sprintf("GPIO%d", pinName))
87+
if pin == nil {
88+
return fmt.Errorf("failed to find pin %d", pinName)
89+
}
90+
if err := pin.Out(gpio.Low); err != nil {
91+
return fmt.Errorf("failed to set pin %d to output: %w", pinName, err)
92+
}
93+
low = append(low, pin)
7694
}
77-
for _, pin := range cfg.High {
78-
rpiopin := rpio.Pin(pin)
79-
rpiopin.Output()
80-
high = append(high, rpiopin)
95+
for _, pinName := range cfg.High {
96+
pin := gpioreg.ByName(fmt.Sprintf("GPIO%d", pinName))
97+
if pin == nil {
98+
return fmt.Errorf("failed to find pin %d", pinName)
99+
}
100+
if err := pin.Out(gpio.High); err != nil {
101+
return fmt.Errorf("failed to set pin %d to output: %w", pinName, err)
102+
}
103+
high = append(high, pin)
81104
}
82105
s.spimultiplexcfg[key] = gpiocfg{
83106
low: low,
@@ -122,10 +145,22 @@ func (s *RaspberryPiPlatform) Stop() {
122145
s.sensorWg.Wait()
123146

124147
// Now, safely close hardware
125-
rpio.SpiEnd(rpio.Spi0)
126-
if err := rpio.Close(); err != nil {
127-
slog.Error("Error closing rpio", "error", err)
148+
if s.spiPort != nil {
149+
if err := s.spiPort.Close(); err != nil {
150+
slog.Error("Error closing spi port", "error", err)
151+
}
152+
s.spiPort = nil
153+
}
154+
155+
for _, cfg := range s.spimultiplexcfg {
156+
for _, pin := range cfg.low {
157+
pin.Halt()
158+
}
159+
for _, pin := range cfg.high {
160+
pin.Halt()
161+
}
128162
}
163+
s.spimultiplexcfg = nil
129164

130165
// If there is a SensorViewer TUI, close it.
131166
if s.sensorViewer != nil {
@@ -153,13 +188,15 @@ func (s *RaspberryPiPlatform) spiExchangeMultiplex(index string, data []byte) []
153188
// The existence of the key is guaranteed by the config validation at startup.
154189
cfg := s.spimultiplexcfg[index]
155190
for _, pin := range cfg.low {
156-
pin.Low()
191+
pin.Out(gpio.Low)
157192
}
158193
for _, pin := range cfg.high {
159-
pin.High()
194+
pin.Out(gpio.High)
160195
}
161196

162-
rpio.SpiExchange(data)
197+
if err := s.spiConn.Tx(data, data); err != nil {
198+
slog.Error("spi transaction failed", "error", err)
199+
}
163200
return data
164201
}
165202

0 commit comments

Comments
 (0)