From 453ff96a66a9917603b87e83bce100fe7cf0347f Mon Sep 17 00:00:00 2001 From: Yurii Soldak Date: Sun, 21 Sep 2025 10:04:20 +0200 Subject: [PATCH] Replace Safe functions with legacy.PinOutput --- bmi160/bmi160.go | 3 +- buzzer/buzzer.go | 2 +- dht/thermometer.go | 6 +-- dht/timesafethermometer.go | 4 +- examples/dht/main.go | 6 ++- examples/hcsr04/main.go | 5 ++- hcsr04/hcsr04.go | 21 +++++----- internal/legacy/pinlegacy_generic.go | 9 +++++ internal/legacy/pinlegacy_tinygo.go | 16 ++++++++ pin.go | 16 +++++--- pin_generic.go | 18 --------- pin_tinygo.go | 57 ---------------------------- rpio/pin.go | 2 + ssd1306/ssd1306_spi.go | 7 ++-- st7735/st7735.go | 9 +++-- tinygo/pin.go | 39 +++++++++++++++++++ 16 files changed, 112 insertions(+), 108 deletions(-) create mode 100644 internal/legacy/pinlegacy_generic.go create mode 100644 internal/legacy/pinlegacy_tinygo.go delete mode 100644 pin_generic.go delete mode 100644 pin_tinygo.go create mode 100644 tinygo/pin.go diff --git a/bmi160/bmi160.go b/bmi160/bmi160.go index 6a04a8c..a8712bf 100644 --- a/bmi160/bmi160.go +++ b/bmi160/bmi160.go @@ -4,6 +4,7 @@ import ( "time" "tinygo.org/x/drivers" + "tinygo.org/x/drivers/internal/legacy" ) // DeviceSPI is the SPI interface to a BMI160 accelerometer/gyroscope. There is @@ -23,7 +24,7 @@ type DeviceSPI struct { // using this device. func NewSPI(csb drivers.PinOutput, spi drivers.SPI) *DeviceSPI { return &DeviceSPI{ - CSB: drivers.SafePinOutput(csb), // chip select + CSB: legacy.PinOutput(csb), // chip select Bus: spi, } } diff --git a/buzzer/buzzer.go b/buzzer/buzzer.go index ed94f74..bbface5 100644 --- a/buzzer/buzzer.go +++ b/buzzer/buzzer.go @@ -17,7 +17,7 @@ type Device struct { // New returns a new buzzer driver given which pin to use func New(pin drivers.PinOutput) Device { return Device{ - set: drivers.SafePinOutput(pin).Set, + set: pin.Set, High: false, BPM: 96.0, } diff --git a/dht/thermometer.go b/dht/thermometer.go index cc3f4d3..4f6e07f 100644 --- a/dht/thermometer.go +++ b/dht/thermometer.go @@ -45,9 +45,7 @@ type device struct { func (t *device) ReadMeasurements() error { // initial waiting state := powerUp(t.pin) - defer func() { - t.pin.Set(state) - }() + defer t.pin.Set(state) err := t.read() if err == nil { t.initialized = true @@ -213,7 +211,7 @@ func waitForDataTransmission(p drivers.PinInput) error { func NewDummyDevice(pin drivers.Pin, deviceType DeviceType) DummyDevice { pin.Set(true) return &device{ - pin: drivers.SafePin(pin), + pin: pin, measurements: deviceType, initialized: false, temperature: 0, diff --git a/dht/timesafethermometer.go b/dht/timesafethermometer.go index 0d1307a..81e82bf 100644 --- a/dht/timesafethermometer.go +++ b/dht/timesafethermometer.go @@ -129,7 +129,7 @@ func New(pin drivers.Pin, deviceType DeviceType) Device { pin.Set(true) return &managedDevice{ t: device{ - pin: drivers.SafePin(pin), + pin: pin, measurements: deviceType, initialized: false, }, @@ -146,7 +146,7 @@ func NewWithPolicy(pin drivers.Pin, deviceType DeviceType, updatePolicy UpdatePo pin.Set(true) result := &managedDevice{ t: device{ - pin: drivers.SafePin(pin), + pin: pin, measurements: deviceType, initialized: false, }, diff --git a/examples/dht/main.go b/examples/dht/main.go index 151258b..f6b9878 100644 --- a/examples/dht/main.go +++ b/examples/dht/main.go @@ -1,14 +1,18 @@ +//go:build baremetal && tinygo + package main import ( "fmt" "machine" "time" + "tinygo.org/x/drivers/dht" + "tinygo.org/x/drivers/tinygo" ) func main() { - pin := machine.D6 + pin := tinygo.New(machine.D6) dhtSensor := dht.New(pin, dht.DHT11) for { temp, hum, err := dhtSensor.Measurements() diff --git a/examples/hcsr04/main.go b/examples/hcsr04/main.go index 191bc07..9bf9765 100644 --- a/examples/hcsr04/main.go +++ b/examples/hcsr04/main.go @@ -5,10 +5,13 @@ import ( "time" "tinygo.org/x/drivers/hcsr04" + "tinygo.org/x/drivers/tinygo" ) func main() { - sensor := hcsr04.New(machine.D10, machine.D9) + trigger := tinygo.New(machine.D10) // automatically configures pin as output + echo := tinygo.New(machine.D9) // automatically configures pin as input + sensor := hcsr04.New(trigger, echo) sensor.Configure() println("Ultrasonic starts") diff --git a/hcsr04/hcsr04.go b/hcsr04/hcsr04.go index 703fa78..06f984f 100644 --- a/hcsr04/hcsr04.go +++ b/hcsr04/hcsr04.go @@ -5,20 +5,22 @@ package hcsr04 import ( - "machine" "time" + + "tinygo.org/x/drivers" ) const TIMEOUT = 23324 // max sensing distance (4m) // Device holds the pins type Device struct { - trigger machine.Pin - echo machine.Pin + trigger drivers.PinOutput + echo drivers.PinInput } -// New returns a new ultrasonic driver given 2 pins -func New(trigger, echo machine.Pin) Device { +// New returns a new ultrasonic driver given 2 pins. +// Pins must be configured as output (trigger) and input (echo). +func New(trigger drivers.PinOutput, echo drivers.PinInput) Device { return Device{ trigger: trigger, echo: echo, @@ -27,8 +29,7 @@ func New(trigger, echo machine.Pin) Device { // Configure configures the pins of the Device func (d *Device) Configure() { - d.trigger.Configure(machine.PinConfig{Mode: machine.PinOutput}) - d.echo.Configure(machine.PinConfig{Mode: machine.PinInput}) + // no-op, left for API compatibility } // ReadDistance returns the distance of the object in mm @@ -45,11 +46,11 @@ func (d *Device) ReadDistance() int32 { // ReadPulse returns the time of the pulse (roundtrip) in microseconds func (d *Device) ReadPulse() int32 { t := time.Now() - d.trigger.Low() + d.trigger.Set(false) time.Sleep(2 * time.Microsecond) - d.trigger.High() + d.trigger.Set(true) time.Sleep(10 * time.Microsecond) - d.trigger.Low() + d.trigger.Set(false) i := uint8(0) for { if d.echo.Get() { diff --git a/internal/legacy/pinlegacy_generic.go b/internal/legacy/pinlegacy_generic.go new file mode 100644 index 0000000..8ca2a24 --- /dev/null +++ b/internal/legacy/pinlegacy_generic.go @@ -0,0 +1,9 @@ +//go:build !(baremetal && tinygo) + +package legacy + +import "tinygo.org/x/drivers" + +func PinOutput(pin drivers.PinOutput) drivers.PinOutput { + return pin +} diff --git a/internal/legacy/pinlegacy_tinygo.go b/internal/legacy/pinlegacy_tinygo.go new file mode 100644 index 0000000..209096f --- /dev/null +++ b/internal/legacy/pinlegacy_tinygo.go @@ -0,0 +1,16 @@ +//go:build baremetal && tinygo + +package legacy + +import ( + "machine" + + "tinygo.org/x/drivers" +) + +func PinOutput(pin drivers.PinOutput) drivers.PinOutput { + if p, ok := pin.(machine.Pin); ok { + p.Configure(machine.PinConfig{Mode: machine.PinOutput}) + } + return pin +} diff --git a/pin.go b/pin.go index 104a0b5..783d1cc 100644 --- a/pin.go +++ b/pin.go @@ -4,13 +4,17 @@ package drivers // allowing the use of different hardware or libraries without changing driver code. // // Note, pin mode functionality is not part of the Pin interface. -// Implementations must ensure correct pin mode is set when Get or Set methods are called. +// Client code is responsible for configuring pin modes correctly. +// This can be done either before passing the pin to a driver constructor +// or by ensuring correct pin mode is set when Get or Set methods are called. +// See rpio package for an example of a pin implementation that does this. // -// Drivers must use SafePin(), SafePinInput() and SafePinOutput() wrappers in constructors. -// The client code can pass either machine.Pin or a custom implementation of the Pin interface. -// Wrappers for TinyGo's machine.Pin are provided in pin_tinygo.go. -// It's custom implementation's responsibility to configure the pin modes correctly as -// Wrappers in pin_generic.go are no-ops. +// Drivers that used to configure output pin mode in their constructors can use +// legacy.PinOutput() wrapper to keep the same behavior for machine.Pin. +// See internal/legacy/pinlegacy_tinygo.go and internal/legacy/pinlegacy_generic.go for details. +// +// All new drivers are encouraged to not configure pin modes in their constructors and +// do not depend on either machine package or legacy wrappers. // PinInput is an interface for reading the state of a pin. type PinInput interface { diff --git a/pin_generic.go b/pin_generic.go deleted file mode 100644 index fe47933..0000000 --- a/pin_generic.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build !tinygo - -// Generic no-op implementations of SafePin, SafePinInput and SafePinOutput. -// It's custom implementation's responsibility to configure the pin modes correctly when needed. - -package drivers - -func SafePinInput(pin PinInput) PinInput { - return pin -} - -func SafePinOutput(pin PinOutput) PinOutput { - return pin -} - -func SafePin(pin Pin) Pin { - return pin -} diff --git a/pin_tinygo.go b/pin_tinygo.go deleted file mode 100644 index 1d3164d..0000000 --- a/pin_tinygo.go +++ /dev/null @@ -1,57 +0,0 @@ -//go:build tinygo - -// Implementation of the Pin interface for tinygo (baremetal), depends on "machine" package. -// SafePin, SafePinInput and SafePinOutput wrappers must be used in constructors of drivers. - -package drivers - -import ( - "machine" -) - -// MachinePin wraps machine.Pin to ensure correct pin mode is set when Get or Set methods are called. - -type MachinePin struct { - pin machine.Pin - mode machine.PinMode - modeSet bool -} - -func (p *MachinePin) Get() bool { - if !p.modeSet || p.mode != machine.PinInput { - p.pin.Configure(machine.PinConfig{Mode: machine.PinInput}) - p.mode = machine.PinInput - } - return p.pin.Get() -} - -func (p *MachinePin) Set(high bool) { - if !p.modeSet || p.mode != machine.PinOutput { - p.pin.Configure(machine.PinConfig{Mode: machine.PinOutput}) - p.mode = machine.PinOutput - } - p.pin.Set(high) -} - -// Wrappers for Pin, PinInput and PinOutput interfaces that convert machine.Pin to safe MachinePin. - -func SafePinInput(pin PinInput) PinInput { - if p, ok := pin.(machine.Pin); ok { - return &MachinePin{pin: p} - } - return pin -} - -func SafePinOutput(pin PinOutput) PinOutput { - if p, ok := pin.(machine.Pin); ok { - return &MachinePin{pin: p} - } - return pin -} - -func SafePin(pin Pin) Pin { - if p, ok := pin.(machine.Pin); ok { - return &MachinePin{pin: p} - } - return pin -} diff --git a/rpio/pin.go b/rpio/pin.go index 52bd94b..369c0e5 100644 --- a/rpio/pin.go +++ b/rpio/pin.go @@ -1,4 +1,6 @@ // Implementation of the Pin interface for the Raspberry Pi GPIO pins. +// Depends on the go-rpio library. +// Configures pin modes automatically when Get or Set methods are called. package rpio // import "tinygo.org/x/drivers/rpio" diff --git a/ssd1306/ssd1306_spi.go b/ssd1306/ssd1306_spi.go index 96a98c0..83217f1 100644 --- a/ssd1306/ssd1306_spi.go +++ b/ssd1306/ssd1306_spi.go @@ -4,6 +4,7 @@ import ( "time" "tinygo.org/x/drivers" + "tinygo.org/x/drivers/internal/legacy" ) type SPIBus struct { @@ -19,9 +20,9 @@ func NewSPI(bus drivers.SPI, dcPin, resetPin, csPin drivers.PinOutput) *Device { return &Device{ bus: &SPIBus{ wire: bus, - dcPin: drivers.SafePinOutput(dcPin), - resetPin: drivers.SafePinOutput(resetPin), - csPin: drivers.SafePinOutput(csPin), + dcPin: legacy.PinOutput(dcPin), + resetPin: legacy.PinOutput(resetPin), + csPin: legacy.PinOutput(csPin), }, } } diff --git a/st7735/st7735.go b/st7735/st7735.go index d0b1997..0b85e9e 100644 --- a/st7735/st7735.go +++ b/st7735/st7735.go @@ -10,6 +10,7 @@ import ( "errors" "tinygo.org/x/drivers" + "tinygo.org/x/drivers/internal/legacy" "tinygo.org/x/drivers/pixel" ) @@ -73,10 +74,10 @@ func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.PinOutput) Devic func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin drivers.PinOutput) DeviceOf[T] { return DeviceOf[T]{ bus: bus, - dcPin: drivers.SafePinOutput(dcPin), - resetPin: drivers.SafePinOutput(resetPin), - csPin: drivers.SafePinOutput(csPin), - blPin: drivers.SafePinOutput(blPin), + dcPin: legacy.PinOutput(dcPin), + resetPin: legacy.PinOutput(resetPin), + csPin: legacy.PinOutput(csPin), + blPin: legacy.PinOutput(blPin), } } diff --git a/tinygo/pin.go b/tinygo/pin.go new file mode 100644 index 0000000..363001b --- /dev/null +++ b/tinygo/pin.go @@ -0,0 +1,39 @@ +//go:build baremetal && tinygo + +package tinygo // import "tinygo.org/x/drivers/tinygo" + +import "machine" + +// tinygo.Pin wraps machine.Pin to ensure correct pin mode is set when Get or Set methods are called. + +type Pin struct { + pin machine.Pin + mode machine.PinMode + + modeSet bool + inputMode machine.PinMode +} + +func New(pin machine.Pin) *Pin { + return &Pin{pin: pin, inputMode: machine.PinInput} +} + +func NewWithInputMode(pin machine.Pin, inputMode machine.PinMode) *Pin { + return &Pin{pin: pin, inputMode: inputMode} +} + +func (p *Pin) Get() bool { + if !p.modeSet || p.mode != p.inputMode { + p.pin.Configure(machine.PinConfig{Mode: p.inputMode}) + p.mode = machine.PinInput + } + return p.pin.Get() +} + +func (p *Pin) Set(high bool) { + if !p.modeSet || p.mode != machine.PinOutput { + p.pin.Configure(machine.PinConfig{Mode: machine.PinOutput}) + p.mode = machine.PinOutput + } + p.pin.Set(high) +}