Skip to content

Commit 5fb9350

Browse files
authored
PinInput+PinOutput HAL (#753, reloaded) (#795)
* first commit: add HAL and uc8151 driver demo * unexport drivers.PinOutput/Input HAL * fix non-tinygo pin config build * change of heart * docs: corrected some comments that were not changed at the same time as recent renaming
1 parent 297ad41 commit 5fb9350

File tree

7 files changed

+232
-17
lines changed

7 files changed

+232
-17
lines changed

internal/legacy/pinconfig.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package legacy
2+
3+
import (
4+
"errors"
5+
6+
"tinygo.org/x/drivers/internal/pin"
7+
)
8+
9+
// The pingconfig group of files serve to abstract away
10+
// pin configuration calls on the machine.Pin type.
11+
// It was observed this way of developing drivers was
12+
// non-portable and unusable on "big" Go projects so
13+
// future projects should NOT configure pins in driver code.
14+
// Users must configure pins before passing them as arguments
15+
// to drivers.
16+
17+
// ConfigurePinOut is a legacy function used to configure pins as outputs.
18+
//
19+
// Deprecated: Do not configure pins in drivers.
20+
// This is a legacy feature and should only be used by drivers that
21+
// previously configured pins in initialization to avoid breaking users.
22+
func ConfigurePinOut(po pin.Output) {
23+
configurePinOut(po)
24+
}
25+
26+
// ConfigurePinInput is a legacy function used to configure pins as inputs.
27+
//
28+
// Deprecated: Do not configure pins in drivers.
29+
// This is a legacy feature and should only be used by drivers that
30+
// previously configured pins in initialization to avoid breaking users.
31+
func ConfigurePinInputPulldown(pi pin.Input) {
32+
configurePinInputPulldown(pi)
33+
}
34+
35+
// ConfigurePinInput is a legacy function used to configure pins as inputs.
36+
//
37+
// Deprecated: Do not configure pins in drivers.
38+
// This is a legacy feature and should only be used by drivers that
39+
// previously configured pins in initialization to avoid breaking users.
40+
func ConfigurePinInput(pi pin.Input) {
41+
configurePinInput(pi)
42+
}
43+
44+
// ConfigurePinInput is a legacy function used to configure pins as inputs.
45+
//
46+
// Deprecated: Do not configure pins in drivers.
47+
// This is a legacy feature and should only be used by drivers that
48+
// previously configured pins in initialization to avoid breaking users.
49+
func ConfigurePinInputPullup(pi pin.Input) {
50+
configurePinInputPullup(pi)
51+
}
52+
53+
// PinIsNoPin returns true if the argument is a machine.Pin type and is the machine.NoPin predeclared type.
54+
//
55+
// Deprecated: Drivers do not require pin knowledge from now on.
56+
func PinIsNoPin(pin any) bool {
57+
return pinIsNoPin(pin)
58+
}
59+
60+
var (
61+
ErrConfigBeforeInstantiated = errors.New("device must be instantiated with New before calling Configure method")
62+
)

internal/legacy/pinconfig_go.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build !tinygo
2+
3+
package legacy
4+
5+
import "tinygo.org/x/drivers/internal/pin"
6+
7+
// This file compiles for non-tinygo builds
8+
// for use with "big" or "upstream" Go where
9+
// there is no machine package.
10+
11+
func configurePinOut(p pin.Output) {}
12+
func configurePinInput(p pin.Input) {}
13+
func configurePinInputPulldown(p pin.Input) {}
14+
func configurePinInputPullup(p pin.Input) {}
15+
func pinIsNoPin(a any) bool { return false }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//go:build baremetal && fe310
2+
3+
package legacy
4+
5+
import "machine"
6+
7+
const (
8+
pulldown = machine.PinInput
9+
pullup = machine.PinInput
10+
)

internal/legacy/pinconfig_pulls.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:build baremetal && !fe310
2+
3+
package legacy
4+
5+
import "machine"
6+
7+
// If you are getting a build error here you then we missed adding
8+
// your CPU build tag to the list of CPUs that do not have pulldown/pullups.
9+
// Add it above and in pinhal_nopulls! You should also add a smoketest for it :)
10+
const (
11+
pulldown = machine.PinInputPulldown
12+
pullup = machine.PinInputPullup
13+
)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//go:build baremetal
2+
3+
package legacy
4+
5+
import (
6+
"machine"
7+
8+
"tinygo.org/x/drivers/internal/pin"
9+
)
10+
11+
func configurePinOut(po pin.Output) {
12+
configurePin(po, machine.PinOutput)
13+
}
14+
15+
func configurePinInputPulldown(pi pin.Input) {
16+
configurePin(pi, pulldown) // some chips do not have pull down, in which case pulldown==machine.PinInput.
17+
}
18+
19+
func configurePinInput(pi pin.Input) {
20+
configurePin(pi, machine.PinInput)
21+
}
22+
23+
func configurePinInputPullup(pi pin.Input) {
24+
configurePin(pi, pullup) // some chips do not have pull up, in which case pullup==machine.PinInput.
25+
}
26+
27+
func pinIsNoPin(a any) bool {
28+
p, ok := a.(machine.Pin)
29+
return ok && p == machine.NoPin
30+
}
31+
32+
func configurePin(p any, mode machine.PinMode) {
33+
machinePin, ok := p.(machine.Pin)
34+
if ok {
35+
machinePin.Configure(machine.PinConfig{Mode: mode})
36+
}
37+
}

internal/pin/internalpin.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// package pin implements a TinyGo Pin HAL.
2+
// It serves to eliminate machine.Pin from driver constructors
3+
// so that drivers can be used in "big" Go projects where
4+
// there is no machine package.
5+
// This file contains both function and interface-style Pin HAL definitions.
6+
package pin
7+
8+
// OutputFunc is hardware abstraction for a pin which outputs a
9+
// digital signal (high or low level).
10+
//
11+
// // Code conversion demo: from machine.Pin to pin.OutputFunc
12+
// led := machine.LED
13+
// led.Configure(machine.PinConfig{Mode: machine.Output})
14+
// var pin pin.OutputFunc = led.Set // Going from a machine.Pin to a pin.OutputFunc
15+
//
16+
// This is an alternative to [Output] which is an interface type.
17+
type OutputFunc func(level bool)
18+
19+
// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true).
20+
func (setPin OutputFunc) High() {
21+
setPin(true)
22+
}
23+
24+
// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false).
25+
func (setPin OutputFunc) Low() {
26+
setPin(false)
27+
}
28+
29+
// InputFunc is hardware abstraction for a pin which receives a
30+
// digital signal and reads it (high or low level).
31+
//
32+
// // Code conversion demo: from machine.Pin to pin.InputFunc
33+
// input := machine.LED
34+
// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.Input
35+
// var pin pin.InputFunc = input.Get // Going from a machine.Pin to a pin.InputFunc
36+
//
37+
// This is an alternative to [Input] which is an interface type.
38+
type InputFunc func() (level bool)
39+
40+
// // Below is an example on how to define a input/output pin HAL for a
41+
// // pin that must switch between input and output mode:
42+
//
43+
// var pinIsOutput bool
44+
// var po PinOutputFunc = func(b bool) {
45+
// if !pinIsOutput {
46+
// pin.Configure(outputMode)
47+
// pinIsOutput = true
48+
// }
49+
// pin.Set(b)
50+
// }
51+
//
52+
// var pi PinInputFunc = func() bool {
53+
// if pinIsOutput {
54+
// pin.Configure(inputMode)
55+
// pinIsOutput = false
56+
// }
57+
// return pin.Get()
58+
// }
59+
60+
// Output interface represents a pin hardware abstraction layer for a pin that can output a digital signal.
61+
//
62+
// This is an alternative to [OutputFunc] abstraction which is a function type.
63+
type Output interface {
64+
Set(level bool)
65+
}
66+
67+
// Input interface represents a pin hardware abstraction layer for a pin that can read a digital signal.
68+
//
69+
// This is an alternative to [InputFunc] abstraction which is a function type.
70+
type Input interface {
71+
Get() (level bool)
72+
}

uc8151/uc8151.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ package uc8151 // import "tinygo.org/x/drivers/uc8151"
88
import (
99
"errors"
1010
"image/color"
11-
"machine"
1211
"time"
1312

1413
"tinygo.org/x/drivers"
14+
"tinygo.org/x/drivers/internal/legacy"
15+
"tinygo.org/x/drivers/internal/pin"
1516
"tinygo.org/x/drivers/pixel"
1617
)
1718

@@ -31,10 +32,10 @@ type Config struct {
3132

3233
type Device struct {
3334
bus drivers.SPI
34-
cs machine.Pin
35-
dc machine.Pin
36-
rst machine.Pin
37-
busy machine.Pin
35+
cs pin.OutputFunc
36+
dc pin.OutputFunc
37+
rst pin.OutputFunc
38+
isBusy pin.InputFunc
3839
width int16
3940
height int16
4041
buffer []uint8
@@ -49,17 +50,22 @@ type Device struct {
4950
type Speed uint8
5051

5152
// New returns a new uc8151 driver. Pass in a fully configured SPI bus.
52-
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
53-
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
54-
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
55-
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
56-
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
53+
// Pins passed in must be configured beforehand.
54+
func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device {
55+
// For backwards compatibility.
56+
// This driver used to configure pins,
57+
// so leave in to not break users.
58+
// May be removed in future so try not to depend on it!
59+
legacy.ConfigurePinOut(csPin)
60+
legacy.ConfigurePinOut(dcPin)
61+
legacy.ConfigurePinOut(rstPin)
62+
legacy.ConfigurePinInput(busyPin)
5763
return Device{
58-
bus: bus,
59-
cs: csPin,
60-
dc: dcPin,
61-
rst: rstPin,
62-
busy: busyPin,
64+
bus: bus,
65+
cs: csPin.Set,
66+
dc: dcPin.Set,
67+
rst: rstPin.Set,
68+
isBusy: busyPin.Get,
6369
}
6470
}
6571

@@ -313,14 +319,14 @@ func (d *Device) ClearDisplay() {
313319

314320
// WaitUntilIdle waits until the display is ready
315321
func (d *Device) WaitUntilIdle() {
316-
for !d.busy.Get() {
322+
for !d.isBusy() {
317323
time.Sleep(10 * time.Millisecond)
318324
}
319325
}
320326

321327
// IsBusy returns the busy status of the display
322328
func (d *Device) IsBusy() bool {
323-
return d.busy.Get()
329+
return d.isBusy()
324330
}
325331

326332
// ClearBuffer sets the buffer to 0xFF (white)

0 commit comments

Comments
 (0)