From 457e1e5dc25f33c537eccc8bfc518009807b6067 Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Mon, 29 Sep 2025 19:16:15 -0300 Subject: [PATCH 1/5] first commit: add HAL and uc8151 driver demo --- internal/legacy/pinconfig.go | 62 ++++++++++++++++++++++++++++ internal/legacy/pinconfig_go.go | 15 +++++++ internal/legacy/pinconfig_nopulls.go | 10 +++++ internal/legacy/pinconfig_pulls.go | 13 ++++++ internal/legacy/pinconfig_tinygo.go | 37 +++++++++++++++++ internal/pin/internalpin.go | 28 +++++++++++++ pin.go | 60 +++++++++++++++++++++++++++ uc8151/uc8151.go | 40 ++++++++++-------- 8 files changed, 248 insertions(+), 17 deletions(-) create mode 100644 internal/legacy/pinconfig.go create mode 100644 internal/legacy/pinconfig_go.go create mode 100644 internal/legacy/pinconfig_nopulls.go create mode 100644 internal/legacy/pinconfig_pulls.go create mode 100644 internal/legacy/pinconfig_tinygo.go create mode 100644 internal/pin/internalpin.go create mode 100644 pin.go diff --git a/internal/legacy/pinconfig.go b/internal/legacy/pinconfig.go new file mode 100644 index 000000000..d9d805ffe --- /dev/null +++ b/internal/legacy/pinconfig.go @@ -0,0 +1,62 @@ +package legacy + +import ( + "errors" + + "tinygo.org/x/drivers/internal/pin" +) + +// The pingconfig group of files serve to abstract away +// pin configuration calls on the machine.Pin type. +// It was observed this way of developing drivers was +// non-portable and unusable on "big" Go projects so +// future projects should NOT configure pins in driver code. +// Users must configure pins before passing them as arguments +// to drivers. + +// ConfigurePinOut is a legacy function used to configure pins as outputs. +// +// Deprecated: Do not configure pins in drivers. +// This is a legacy feature and should only be used by drivers that +// previously configured pins in initialization to avoid breaking users. +func ConfigurePinOut(po pin.Output) { + configurePinOut(po) +} + +// ConfigurePinInput is a legacy function used to configure pins as inputs. +// +// Deprecated: Do not configure pins in drivers. +// This is a legacy feature and should only be used by drivers that +// previously configured pins in initialization to avoid breaking users. +func ConfigurePinInputPulldown(pi pin.Input) { + configurePinInputPulldown(pi) +} + +// ConfigurePinInput is a legacy function used to configure pins as inputs. +// +// Deprecated: Do not configure pins in drivers. +// This is a legacy feature and should only be used by drivers that +// previously configured pins in initialization to avoid breaking users. +func ConfigurePinInput(pi pin.Input) { + configurePinInput(pi) +} + +// ConfigurePinInput is a legacy function used to configure pins as inputs. +// +// Deprecated: Do not configure pins in drivers. +// This is a legacy feature and should only be used by drivers that +// previously configured pins in initialization to avoid breaking users. +func ConfigurePinInputPullup(pi pin.Input) { + configurePinInputPullup(pi) +} + +// PinIsNoPin returns true if the argument is a machine.Pin type and is the machine.NoPin predeclared type. +// +// Deprecated: Drivers do not require pin knowledge from now on. +func PinIsNoPin(pin any) bool { + return pinIsNoPin(pin) +} + +var ( + ErrConfigBeforeInstantiated = errors.New("device must be instantiated with New before calling Configure method") +) diff --git a/internal/legacy/pinconfig_go.go b/internal/legacy/pinconfig_go.go new file mode 100644 index 000000000..3a7096ba7 --- /dev/null +++ b/internal/legacy/pinconfig_go.go @@ -0,0 +1,15 @@ +//go:build !tinygo + +package legacy + +import "tinygo.org/x/drivers/internal/pin" + +// This file compiles for non-tinygo builds +// for use with "big" or "upstream" Go where +// there is no machine package. + +func configurePinOut(p pin.Output) {} +func configurePinInput(p pin.Input) {} +func configurePinInputPulldown(p pin.Input) {} +func configurePinInputPullup(p pin.Input) {} +func pinIsNoPin(a any) bool { return false } diff --git a/internal/legacy/pinconfig_nopulls.go b/internal/legacy/pinconfig_nopulls.go new file mode 100644 index 000000000..1fc61389d --- /dev/null +++ b/internal/legacy/pinconfig_nopulls.go @@ -0,0 +1,10 @@ +//go:build baremetal && fe310 + +package legacy + +import "machine" + +const ( + pulldown = machine.PinInput + pullup = machine.PinInput +) diff --git a/internal/legacy/pinconfig_pulls.go b/internal/legacy/pinconfig_pulls.go new file mode 100644 index 000000000..d7e88c658 --- /dev/null +++ b/internal/legacy/pinconfig_pulls.go @@ -0,0 +1,13 @@ +//go:build baremetal && !fe310 + +package legacy + +import "machine" + +// If you are getting a build error here you then we missed adding +// your CPU build tag to the list of CPUs that do not have pulldown/pullups. +// Add it above and in pinhal_nopulls! You should also add a smoketest for it :) +const ( + pulldown = machine.PinInputPulldown + pullup = machine.PinInputPullup +) diff --git a/internal/legacy/pinconfig_tinygo.go b/internal/legacy/pinconfig_tinygo.go new file mode 100644 index 000000000..d0068b2c8 --- /dev/null +++ b/internal/legacy/pinconfig_tinygo.go @@ -0,0 +1,37 @@ +//go:build baremetal + +package legacy + +import ( + "machine" + + "tinygo.org/x/drivers/internal/pin" +) + +func configurePinOut(po pin.Output) { + configurePin(po, machine.PinOutput) +} + +func configurePinInputPulldown(pi pin.Input) { + configurePin(pi, pulldown) // some chips do not have pull down, in which case pulldown==machine.PinInput. +} + +func configurePinInput(pi pin.Input) { + configurePin(pi, machine.PinInput) +} + +func configurePinInputPullup(pi pin.Input) { + configurePin(pi, pullup) // some chips do not have pull up, in which case pullup==machine.PinInput. +} + +func pinIsNoPin(a any) bool { + p, ok := a.(machine.Pin) + return ok && p == machine.NoPin +} + +func configurePin(p any, mode machine.PinMode) { + machinePin, ok := p.(machine.Pin) + if ok { + machinePin.Configure(machine.PinConfig{Mode: mode}) + } +} diff --git a/internal/pin/internalpin.go b/internal/pin/internalpin.go new file mode 100644 index 000000000..083d3a294 --- /dev/null +++ b/internal/pin/internalpin.go @@ -0,0 +1,28 @@ +package pin + +import "tinygo.org/x/drivers" + +// This file contains interface-style Pin HAL definition. +// It serves to eliminate machine.Pin from driver constructors +// so that drivers can be used in "big" Go projects where +// there is no machine package. + +// Here to aid relevant documentation links of [drivers.PinOutput] and [drivers.PinInput]. +var _ drivers.PinOutput + +// Output represents a pin hardware abstraction layer for a pin that can output a digital signal. +// +// This is an alternative to [drivers.PinOutput] abstraction which is a function type and has +// not been standardized as of yet as a standard HAL in the drivers package, +// [discussion ongoing here]. +// +// [discussion ongoing here]: https://github.com/orgs/tinygo-org/discussions/5043 +type Output interface { + Set(level bool) +} + +// Input represents a pin hardware abstraction layer. +// See [Output] for more information on why this type exists separate to drivers. +type Input interface { + Get() (level bool) +} diff --git a/pin.go b/pin.go new file mode 100644 index 000000000..0ef99ed28 --- /dev/null +++ b/pin.go @@ -0,0 +1,60 @@ +package drivers + +// TinyGo Pin HAL (exported) +// +// Pins are represented as function types instead of interfaces because they are: +// - Faster on MCUs +// - Conceptually simpler than an interface +// - Very likely easier to teach than interface: +// - Cleaner at call sites (e.g., isBusy := d.isBusy() vs d.isBusy.Get()). +// - Enable inline funcs at the usage site- less boilerplate than defining +// an interface type + method (see example below). +// - Less prone to “method creep”: the API surface stays small while +// advanced behavior can be composed in user code. +// Example: a pin that can act as both output and input without adding methods. +// +// var pinIsOutput bool +// var po PinOutput = func(b bool) { +// if !pinIsOutput { +// pin.Configure(outputMode) +// pinIsOutput = true +// } +// pin.Set(b) +// } +// var pi PinInput = func() bool { +// if pinIsOutput { +// pin.Configure(inputMode) +// pinIsOutput = false +// } +// return pin.Get() +// } +// +// See https://github.com/tinygo-org/drivers/pull/753 for detailed commentary. + +// PinOutput is hardware abstraction for a pin which outputs a +// digital signal (high or low level). +// +// // Code conversion demo: from machine.Pin to drivers.PinOutput +// led := machine.LED +// led.Configure(machine.PinConfig{Mode: machine.PinOutput}) +// var pin drivers.PinOutput = led.Set // Going from a machine.Pin to a drivers.PinOutput +type PinOutput func(level bool) + +// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true). +func (setPin PinOutput) High() { + setPin(true) +} + +// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false). +func (setPin PinOutput) Low() { + setPin(false) +} + +// PinInput is hardware abstraction for a pin which receives a +// digital signal and reads it (high or low level). +// +// // Code conversion demo: from machine.Pin to drivers.PinInput +// input := machine.LED +// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.PinInput +// var pin drivers.PinInput = input.Get // Going from a machine.Pin to a drivers.PinInput +type PinInput func() (level bool) diff --git a/uc8151/uc8151.go b/uc8151/uc8151.go index 38c48f9a0..7652cfda5 100644 --- a/uc8151/uc8151.go +++ b/uc8151/uc8151.go @@ -8,10 +8,11 @@ package uc8151 // import "tinygo.org/x/drivers/uc8151" import ( "errors" "image/color" - "machine" "time" "tinygo.org/x/drivers" + "tinygo.org/x/drivers/internal/legacy" + "tinygo.org/x/drivers/internal/pin" "tinygo.org/x/drivers/pixel" ) @@ -31,10 +32,10 @@ type Config struct { type Device struct { bus drivers.SPI - cs machine.Pin - dc machine.Pin - rst machine.Pin - busy machine.Pin + cs drivers.PinOutput + dc drivers.PinOutput + rst drivers.PinOutput + isBusy drivers.PinInput width int16 height int16 buffer []uint8 @@ -49,17 +50,22 @@ type Device struct { type Speed uint8 // New returns a new uc8151 driver. Pass in a fully configured SPI bus. -func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device { - csPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) - dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) - rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) - busyPin.Configure(machine.PinConfig{Mode: machine.PinInput}) +// Pins passed in must be configured beforehand. +func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device { + // For backwards compatibility. + // This driver used to configure pins, + // so leave in to not break users. + // May be removed in future so try not to depend on it! + legacy.ConfigurePinOut(csPin) + legacy.ConfigurePinOut(dcPin) + legacy.ConfigurePinOut(rstPin) + legacy.ConfigurePinInput(busyPin) return Device{ - bus: bus, - cs: csPin, - dc: dcPin, - rst: rstPin, - busy: busyPin, + bus: bus, + cs: csPin.Set, + dc: dcPin.Set, + rst: rstPin.Set, + isBusy: busyPin.Get, } } @@ -313,14 +319,14 @@ func (d *Device) ClearDisplay() { // WaitUntilIdle waits until the display is ready func (d *Device) WaitUntilIdle() { - for !d.busy.Get() { + for !d.isBusy() { time.Sleep(10 * time.Millisecond) } } // IsBusy returns the busy status of the display func (d *Device) IsBusy() bool { - return d.busy.Get() + return d.isBusy() } // ClearBuffer sets the buffer to 0xFF (white) From e74e70897d55e67e65981b037bad0fc253d556a5 Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Sun, 2 Nov 2025 19:46:25 -0300 Subject: [PATCH 2/5] unexport drivers.PinOutput/Input HAL --- internal/legacy/pinconfig.go | 8 +-- internal/legacy/pinconfig_tinygo.go | 8 +-- internal/pin/internalpin.go | 78 +++++++++++++++++++++++++---- pin.go | 60 ---------------------- uc8151/uc8151.go | 10 ++-- 5 files changed, 81 insertions(+), 83 deletions(-) delete mode 100644 pin.go diff --git a/internal/legacy/pinconfig.go b/internal/legacy/pinconfig.go index d9d805ffe..c71dbe254 100644 --- a/internal/legacy/pinconfig.go +++ b/internal/legacy/pinconfig.go @@ -19,7 +19,7 @@ import ( // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinOut(po pin.Output) { +func ConfigurePinOut(po pin.OutputInterface) { configurePinOut(po) } @@ -28,7 +28,7 @@ func ConfigurePinOut(po pin.Output) { // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinInputPulldown(pi pin.Input) { +func ConfigurePinInputPulldown(pi pin.InputInterface) { configurePinInputPulldown(pi) } @@ -37,7 +37,7 @@ func ConfigurePinInputPulldown(pi pin.Input) { // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinInput(pi pin.Input) { +func ConfigurePinInput(pi pin.InputInterface) { configurePinInput(pi) } @@ -46,7 +46,7 @@ func ConfigurePinInput(pi pin.Input) { // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinInputPullup(pi pin.Input) { +func ConfigurePinInputPullup(pi pin.InputInterface) { configurePinInputPullup(pi) } diff --git a/internal/legacy/pinconfig_tinygo.go b/internal/legacy/pinconfig_tinygo.go index d0068b2c8..95c2c5d99 100644 --- a/internal/legacy/pinconfig_tinygo.go +++ b/internal/legacy/pinconfig_tinygo.go @@ -8,19 +8,19 @@ import ( "tinygo.org/x/drivers/internal/pin" ) -func configurePinOut(po pin.Output) { +func configurePinOut(po pin.OutputInterface) { configurePin(po, machine.PinOutput) } -func configurePinInputPulldown(pi pin.Input) { +func configurePinInputPulldown(pi pin.InputInterface) { configurePin(pi, pulldown) // some chips do not have pull down, in which case pulldown==machine.PinInput. } -func configurePinInput(pi pin.Input) { +func configurePinInput(pi pin.InputInterface) { configurePin(pi, machine.PinInput) } -func configurePinInputPullup(pi pin.Input) { +func configurePinInputPullup(pi pin.InputInterface) { configurePin(pi, pullup) // some chips do not have pull up, in which case pullup==machine.PinInput. } diff --git a/internal/pin/internalpin.go b/internal/pin/internalpin.go index 083d3a294..91e8340e7 100644 --- a/internal/pin/internalpin.go +++ b/internal/pin/internalpin.go @@ -1,28 +1,86 @@ package pin -import "tinygo.org/x/drivers" +// TinyGo Pin HAL +// +// Pins are represented as function types instead of interfaces because they are: +// - Faster on MCUs +// - Conceptually simpler than an interface +// - Easier to teach than interface for someone who is new to programming. +// - Cleaner at call sites (e.g., isBusy := d.isBusy() vs d.isBusy.Get()). +// - Enable inline funcs at the usage site- less boilerplate than defining +// an interface type + method (see example below). +// - Less prone to “method creep”: the API surface stays small while +// advanced behavior can be composed in user code. +// Example: a pin that can act as both output and input without adding methods. +// +// var pinIsOutput bool +// var po PinOutput = func(b bool) { +// if !pinIsOutput { +// pin.Configure(outputMode) +// pinIsOutput = true +// } +// pin.Set(b) +// } +// var pi PinInput = func() bool { +// if pinIsOutput { +// pin.Configure(inputMode) +// pinIsOutput = false +// } +// return pin.Get() +// } +// +// See https://github.com/tinygo-org/drivers/pull/753 for detailed commentary. +// See https://github.com/orgs/tinygo-org/discussions/5043 for ongoing discussion + +// Output is hardware abstraction for a pin which outputs a +// digital signal (high or low level). +// See [ongoing discussion here]. +// +// // Code conversion demo: from machine.Pin to pin.Output +// led := machine.LED +// led.Configure(machine.PinConfig{Mode: machine.Output}) +// var pin pin.Output = led.Set // Going from a machine.Pin to a pin.Output +// +// [ongoing discussion here]: https://github.com/orgs/tinygo-org/discussions/5043 +type Output func(level bool) + +// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true). +func (setPin Output) High() { + setPin(true) +} + +// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false). +func (setPin Output) Low() { + setPin(false) +} + +// Input is hardware abstraction for a pin which receives a +// digital signal and reads it (high or low level). +// +// // Code conversion demo: from machine.Pin to pin.Input +// input := machine.LED +// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.Input +// var pin pin.Input = input.Get // Going from a machine.Pin to a pin.Input +type Input func() (level bool) // This file contains interface-style Pin HAL definition. // It serves to eliminate machine.Pin from driver constructors // so that drivers can be used in "big" Go projects where // there is no machine package. -// Here to aid relevant documentation links of [drivers.PinOutput] and [drivers.PinInput]. -var _ drivers.PinOutput - -// Output represents a pin hardware abstraction layer for a pin that can output a digital signal. +// OutputInterface represents a pin hardware abstraction layer for a pin that can output a digital signal. // -// This is an alternative to [drivers.PinOutput] abstraction which is a function type and has +// This is an alternative to [Output] abstraction which is a function type and has // not been standardized as of yet as a standard HAL in the drivers package, // [discussion ongoing here]. // // [discussion ongoing here]: https://github.com/orgs/tinygo-org/discussions/5043 -type Output interface { +type OutputInterface interface { Set(level bool) } -// Input represents a pin hardware abstraction layer. -// See [Output] for more information on why this type exists separate to drivers. -type Input interface { +// InputInterface represents a pin hardware abstraction layer. +// See [OutputInterface] for more information on why this type exists separate to drivers. +type InputInterface interface { Get() (level bool) } diff --git a/pin.go b/pin.go deleted file mode 100644 index 0ef99ed28..000000000 --- a/pin.go +++ /dev/null @@ -1,60 +0,0 @@ -package drivers - -// TinyGo Pin HAL (exported) -// -// Pins are represented as function types instead of interfaces because they are: -// - Faster on MCUs -// - Conceptually simpler than an interface -// - Very likely easier to teach than interface: -// - Cleaner at call sites (e.g., isBusy := d.isBusy() vs d.isBusy.Get()). -// - Enable inline funcs at the usage site- less boilerplate than defining -// an interface type + method (see example below). -// - Less prone to “method creep”: the API surface stays small while -// advanced behavior can be composed in user code. -// Example: a pin that can act as both output and input without adding methods. -// -// var pinIsOutput bool -// var po PinOutput = func(b bool) { -// if !pinIsOutput { -// pin.Configure(outputMode) -// pinIsOutput = true -// } -// pin.Set(b) -// } -// var pi PinInput = func() bool { -// if pinIsOutput { -// pin.Configure(inputMode) -// pinIsOutput = false -// } -// return pin.Get() -// } -// -// See https://github.com/tinygo-org/drivers/pull/753 for detailed commentary. - -// PinOutput is hardware abstraction for a pin which outputs a -// digital signal (high or low level). -// -// // Code conversion demo: from machine.Pin to drivers.PinOutput -// led := machine.LED -// led.Configure(machine.PinConfig{Mode: machine.PinOutput}) -// var pin drivers.PinOutput = led.Set // Going from a machine.Pin to a drivers.PinOutput -type PinOutput func(level bool) - -// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true). -func (setPin PinOutput) High() { - setPin(true) -} - -// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false). -func (setPin PinOutput) Low() { - setPin(false) -} - -// PinInput is hardware abstraction for a pin which receives a -// digital signal and reads it (high or low level). -// -// // Code conversion demo: from machine.Pin to drivers.PinInput -// input := machine.LED -// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.PinInput -// var pin drivers.PinInput = input.Get // Going from a machine.Pin to a drivers.PinInput -type PinInput func() (level bool) diff --git a/uc8151/uc8151.go b/uc8151/uc8151.go index 7652cfda5..d70a67fe7 100644 --- a/uc8151/uc8151.go +++ b/uc8151/uc8151.go @@ -32,10 +32,10 @@ type Config struct { type Device struct { bus drivers.SPI - cs drivers.PinOutput - dc drivers.PinOutput - rst drivers.PinOutput - isBusy drivers.PinInput + cs pin.Output + dc pin.Output + rst pin.Output + isBusy pin.Input width int16 height int16 buffer []uint8 @@ -51,7 +51,7 @@ type Speed uint8 // New returns a new uc8151 driver. Pass in a fully configured SPI bus. // Pins passed in must be configured beforehand. -func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device { +func New(bus drivers.SPI, csPin, dcPin, rstPin pin.OutputInterface, busyPin pin.InputInterface) Device { // For backwards compatibility. // This driver used to configure pins, // so leave in to not break users. From 7ebf5001343471a57086482f61e4afb5ac83b46f Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Sun, 2 Nov 2025 19:50:37 -0300 Subject: [PATCH 3/5] fix non-tinygo pin config build --- internal/legacy/pinconfig_go.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/legacy/pinconfig_go.go b/internal/legacy/pinconfig_go.go index 3a7096ba7..ad8368d1e 100644 --- a/internal/legacy/pinconfig_go.go +++ b/internal/legacy/pinconfig_go.go @@ -8,8 +8,8 @@ import "tinygo.org/x/drivers/internal/pin" // for use with "big" or "upstream" Go where // there is no machine package. -func configurePinOut(p pin.Output) {} -func configurePinInput(p pin.Input) {} -func configurePinInputPulldown(p pin.Input) {} -func configurePinInputPullup(p pin.Input) {} -func pinIsNoPin(a any) bool { return false } +func configurePinOut(p pin.OutputInterface) {} +func configurePinInput(p pin.InputInterface) {} +func configurePinInputPulldown(p pin.InputInterface) {} +func configurePinInputPullup(p pin.InputInterface) {} +func pinIsNoPin(a any) bool { return false } From 6eda36d149fd320638cb3ac26c8c13d451859868 Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Fri, 7 Nov 2025 20:55:01 -0300 Subject: [PATCH 4/5] change of heart --- internal/legacy/pinconfig.go | 8 +-- internal/legacy/pinconfig_go.go | 10 ++-- internal/legacy/pinconfig_tinygo.go | 8 +-- internal/pin/internalpin.go | 87 ++++++++++++++++------------- uc8151/uc8151.go | 10 ++-- 5 files changed, 65 insertions(+), 58 deletions(-) diff --git a/internal/legacy/pinconfig.go b/internal/legacy/pinconfig.go index c71dbe254..d9d805ffe 100644 --- a/internal/legacy/pinconfig.go +++ b/internal/legacy/pinconfig.go @@ -19,7 +19,7 @@ import ( // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinOut(po pin.OutputInterface) { +func ConfigurePinOut(po pin.Output) { configurePinOut(po) } @@ -28,7 +28,7 @@ func ConfigurePinOut(po pin.OutputInterface) { // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinInputPulldown(pi pin.InputInterface) { +func ConfigurePinInputPulldown(pi pin.Input) { configurePinInputPulldown(pi) } @@ -37,7 +37,7 @@ func ConfigurePinInputPulldown(pi pin.InputInterface) { // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinInput(pi pin.InputInterface) { +func ConfigurePinInput(pi pin.Input) { configurePinInput(pi) } @@ -46,7 +46,7 @@ func ConfigurePinInput(pi pin.InputInterface) { // Deprecated: Do not configure pins in drivers. // This is a legacy feature and should only be used by drivers that // previously configured pins in initialization to avoid breaking users. -func ConfigurePinInputPullup(pi pin.InputInterface) { +func ConfigurePinInputPullup(pi pin.Input) { configurePinInputPullup(pi) } diff --git a/internal/legacy/pinconfig_go.go b/internal/legacy/pinconfig_go.go index ad8368d1e..3a7096ba7 100644 --- a/internal/legacy/pinconfig_go.go +++ b/internal/legacy/pinconfig_go.go @@ -8,8 +8,8 @@ import "tinygo.org/x/drivers/internal/pin" // for use with "big" or "upstream" Go where // there is no machine package. -func configurePinOut(p pin.OutputInterface) {} -func configurePinInput(p pin.InputInterface) {} -func configurePinInputPulldown(p pin.InputInterface) {} -func configurePinInputPullup(p pin.InputInterface) {} -func pinIsNoPin(a any) bool { return false } +func configurePinOut(p pin.Output) {} +func configurePinInput(p pin.Input) {} +func configurePinInputPulldown(p pin.Input) {} +func configurePinInputPullup(p pin.Input) {} +func pinIsNoPin(a any) bool { return false } diff --git a/internal/legacy/pinconfig_tinygo.go b/internal/legacy/pinconfig_tinygo.go index 95c2c5d99..d0068b2c8 100644 --- a/internal/legacy/pinconfig_tinygo.go +++ b/internal/legacy/pinconfig_tinygo.go @@ -8,19 +8,19 @@ import ( "tinygo.org/x/drivers/internal/pin" ) -func configurePinOut(po pin.OutputInterface) { +func configurePinOut(po pin.Output) { configurePin(po, machine.PinOutput) } -func configurePinInputPulldown(pi pin.InputInterface) { +func configurePinInputPulldown(pi pin.Input) { configurePin(pi, pulldown) // some chips do not have pull down, in which case pulldown==machine.PinInput. } -func configurePinInput(pi pin.InputInterface) { +func configurePinInput(pi pin.Input) { configurePin(pi, machine.PinInput) } -func configurePinInputPullup(pi pin.InputInterface) { +func configurePinInputPullup(pi pin.Input) { configurePin(pi, pullup) // some chips do not have pull up, in which case pullup==machine.PinInput. } diff --git a/internal/pin/internalpin.go b/internal/pin/internalpin.go index 91e8340e7..8e63faaec 100644 --- a/internal/pin/internalpin.go +++ b/internal/pin/internalpin.go @@ -1,36 +1,43 @@ -package pin +/* +package pin implements TinyGo Pin HAL as seen in this [PR] and ongoing [discussion]. -// TinyGo Pin HAL -// -// Pins are represented as function types instead of interfaces because they are: -// - Faster on MCUs -// - Conceptually simpler than an interface -// - Easier to teach than interface for someone who is new to programming. -// - Cleaner at call sites (e.g., isBusy := d.isBusy() vs d.isBusy.Get()). -// - Enable inline funcs at the usage site- less boilerplate than defining -// an interface type + method (see example below). -// - Less prone to “method creep”: the API surface stays small while -// advanced behavior can be composed in user code. -// Example: a pin that can act as both output and input without adding methods. -// -// var pinIsOutput bool -// var po PinOutput = func(b bool) { -// if !pinIsOutput { -// pin.Configure(outputMode) -// pinIsOutput = true -// } -// pin.Set(b) -// } -// var pi PinInput = func() bool { -// if pinIsOutput { -// pin.Configure(inputMode) -// pinIsOutput = false -// } -// return pin.Get() -// } -// -// See https://github.com/tinygo-org/drivers/pull/753 for detailed commentary. -// See https://github.com/orgs/tinygo-org/discussions/5043 for ongoing discussion +pins are preferrably represented as function types instead of interfaces because they are: +- Faster on MCUs, x25 times faster on some architectures. +- Conceptually simpler than an interface + - Easier to teach than interface for someone who is new to programming. + - Cleaner at call sites (e.g., isBusy := d.isBusy() vs d.isBusy.Get()). + - Enable inline funcs at the usage site- less boilerplate than defining + an interface type + method (see example below). + - Less prone to “method creep”: the API surface stays small while + advanced behavior can be composed in user code. + Example: a pin that can act as both output and input without adding methods. + +Below is an example on how to define a input/output pin HAL for a +pin that must switch between input and output mode: + + var pinIsOutput bool + var po PinOutput = func(b bool) { + if !pinIsOutput { + pin.Configure(outputMode) + pinIsOutput = true + } + pin.Set(b) + } + + var pi PinInput = func() bool { + if pinIsOutput { + pin.Configure(inputMode) + pinIsOutput = false + } + return pin.Get() + } + +See this [discussion]. + +[discussion]: https://github.com/orgs/tinygo-org/discussions/5043 +[PR]: https://github.com/tinygo-org/drivers/pull/753 +*/ +package pin // Output is hardware abstraction for a pin which outputs a // digital signal (high or low level). @@ -42,15 +49,15 @@ package pin // var pin pin.Output = led.Set // Going from a machine.Pin to a pin.Output // // [ongoing discussion here]: https://github.com/orgs/tinygo-org/discussions/5043 -type Output func(level bool) +type OutputFunc func(level bool) // High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true). -func (setPin Output) High() { +func (setPin OutputFunc) High() { setPin(true) } // Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false). -func (setPin Output) Low() { +func (setPin OutputFunc) Low() { setPin(false) } @@ -61,7 +68,7 @@ func (setPin Output) Low() { // input := machine.LED // input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.Input // var pin pin.Input = input.Get // Going from a machine.Pin to a pin.Input -type Input func() (level bool) +type InputFunc func() (level bool) // This file contains interface-style Pin HAL definition. // It serves to eliminate machine.Pin from driver constructors @@ -70,17 +77,17 @@ type Input func() (level bool) // OutputInterface represents a pin hardware abstraction layer for a pin that can output a digital signal. // -// This is an alternative to [Output] abstraction which is a function type and has +// This is an alternative to [OutputFunc] abstraction which is a function type and has // not been standardized as of yet as a standard HAL in the drivers package, // [discussion ongoing here]. // // [discussion ongoing here]: https://github.com/orgs/tinygo-org/discussions/5043 -type OutputInterface interface { +type Output interface { Set(level bool) } // InputInterface represents a pin hardware abstraction layer. -// See [OutputInterface] for more information on why this type exists separate to drivers. -type InputInterface interface { +// See [InputFunc] for more information on why this type exists separate to drivers. +type Input interface { Get() (level bool) } diff --git a/uc8151/uc8151.go b/uc8151/uc8151.go index d70a67fe7..4367568cc 100644 --- a/uc8151/uc8151.go +++ b/uc8151/uc8151.go @@ -32,10 +32,10 @@ type Config struct { type Device struct { bus drivers.SPI - cs pin.Output - dc pin.Output - rst pin.Output - isBusy pin.Input + cs pin.OutputFunc + dc pin.OutputFunc + rst pin.OutputFunc + isBusy pin.InputFunc width int16 height int16 buffer []uint8 @@ -51,7 +51,7 @@ type Speed uint8 // New returns a new uc8151 driver. Pass in a fully configured SPI bus. // Pins passed in must be configured beforehand. -func New(bus drivers.SPI, csPin, dcPin, rstPin pin.OutputInterface, busyPin pin.InputInterface) Device { +func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device { // For backwards compatibility. // This driver used to configure pins, // so leave in to not break users. From 53d4b86c7c98283baaeb991b3795e53900f42213 Mon Sep 17 00:00:00 2001 From: deadprogram Date: Sat, 8 Nov 2025 09:56:29 +0100 Subject: [PATCH 5/5] docs: corrected some comments that were not changed at the same time as recent renaming Signed-off-by: deadprogram --- internal/pin/internalpin.go | 97 +++++++++++++++---------------------- 1 file changed, 38 insertions(+), 59 deletions(-) diff --git a/internal/pin/internalpin.go b/internal/pin/internalpin.go index 8e63faaec..6879f3480 100644 --- a/internal/pin/internalpin.go +++ b/internal/pin/internalpin.go @@ -1,54 +1,19 @@ -/* -package pin implements TinyGo Pin HAL as seen in this [PR] and ongoing [discussion]. - -pins are preferrably represented as function types instead of interfaces because they are: -- Faster on MCUs, x25 times faster on some architectures. -- Conceptually simpler than an interface - - Easier to teach than interface for someone who is new to programming. - - Cleaner at call sites (e.g., isBusy := d.isBusy() vs d.isBusy.Get()). - - Enable inline funcs at the usage site- less boilerplate than defining - an interface type + method (see example below). - - Less prone to “method creep”: the API surface stays small while - advanced behavior can be composed in user code. - Example: a pin that can act as both output and input without adding methods. - -Below is an example on how to define a input/output pin HAL for a -pin that must switch between input and output mode: - - var pinIsOutput bool - var po PinOutput = func(b bool) { - if !pinIsOutput { - pin.Configure(outputMode) - pinIsOutput = true - } - pin.Set(b) - } - - var pi PinInput = func() bool { - if pinIsOutput { - pin.Configure(inputMode) - pinIsOutput = false - } - return pin.Get() - } - -See this [discussion]. - -[discussion]: https://github.com/orgs/tinygo-org/discussions/5043 -[PR]: https://github.com/tinygo-org/drivers/pull/753 -*/ +// package pin implements a TinyGo Pin HAL. +// It serves to eliminate machine.Pin from driver constructors +// so that drivers can be used in "big" Go projects where +// there is no machine package. +// This file contains both function and interface-style Pin HAL definitions. package pin -// Output is hardware abstraction for a pin which outputs a +// OutputFunc is hardware abstraction for a pin which outputs a // digital signal (high or low level). -// See [ongoing discussion here]. // -// // Code conversion demo: from machine.Pin to pin.Output +// // Code conversion demo: from machine.Pin to pin.OutputFunc // led := machine.LED // led.Configure(machine.PinConfig{Mode: machine.Output}) -// var pin pin.Output = led.Set // Going from a machine.Pin to a pin.Output +// var pin pin.OutputFunc = led.Set // Going from a machine.Pin to a pin.OutputFunc // -// [ongoing discussion here]: https://github.com/orgs/tinygo-org/discussions/5043 +// This is an alternative to [Output] which is an interface type. type OutputFunc func(level bool) // High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true). @@ -61,33 +26,47 @@ func (setPin OutputFunc) Low() { setPin(false) } -// Input is hardware abstraction for a pin which receives a +// InputFunc is hardware abstraction for a pin which receives a // digital signal and reads it (high or low level). // -// // Code conversion demo: from machine.Pin to pin.Input +// // Code conversion demo: from machine.Pin to pin.InputFunc // input := machine.LED // input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.Input -// var pin pin.Input = input.Get // Going from a machine.Pin to a pin.Input +// var pin pin.InputFunc = input.Get // Going from a machine.Pin to a pin.InputFunc +// +// This is an alternative to [Input] which is an interface type. type InputFunc func() (level bool) -// This file contains interface-style Pin HAL definition. -// It serves to eliminate machine.Pin from driver constructors -// so that drivers can be used in "big" Go projects where -// there is no machine package. - -// OutputInterface represents a pin hardware abstraction layer for a pin that can output a digital signal. +// // Below is an example on how to define a input/output pin HAL for a +// // pin that must switch between input and output mode: +// +// var pinIsOutput bool +// var po PinOutputFunc = func(b bool) { +// if !pinIsOutput { +// pin.Configure(outputMode) +// pinIsOutput = true +// } +// pin.Set(b) +// } // -// This is an alternative to [OutputFunc] abstraction which is a function type and has -// not been standardized as of yet as a standard HAL in the drivers package, -// [discussion ongoing here]. +// var pi PinInputFunc = func() bool { +// if pinIsOutput { +// pin.Configure(inputMode) +// pinIsOutput = false +// } +// return pin.Get() +// } + +// Output interface represents a pin hardware abstraction layer for a pin that can output a digital signal. // -// [discussion ongoing here]: https://github.com/orgs/tinygo-org/discussions/5043 +// This is an alternative to [OutputFunc] abstraction which is a function type. type Output interface { Set(level bool) } -// InputInterface represents a pin hardware abstraction layer. -// See [InputFunc] for more information on why this type exists separate to drivers. +// Input interface represents a pin hardware abstraction layer for a pin that can read a digital signal. +// +// This is an alternative to [InputFunc] abstraction which is a function type. type Input interface { Get() (level bool) }