mirror of
https://github.com/kidoman/embd
synced 2024-12-22 04:40:04 +01:00
gpio: implement pin caching
this allows for the short version of the API to work as expected as consecutive calls to the same pin would now be internally working on the pin instance (all the 3 currently supported types). closing a pin busts the cache
This commit is contained in:
parent
6f90af377d
commit
57328c979d
23
bbb.go
23
bbb.go
@ -157,15 +157,18 @@ func bbbEnsureFeatureDisabled(id string) error {
|
||||
}
|
||||
|
||||
type bbbAnalogPin struct {
|
||||
n int
|
||||
id string
|
||||
n int
|
||||
|
||||
drv GPIODriver
|
||||
|
||||
val *os.File
|
||||
|
||||
initialized bool
|
||||
}
|
||||
|
||||
func newBBBAnalogPin(n int) AnalogPin {
|
||||
return &bbbAnalogPin{n: n}
|
||||
func newBBBAnalogPin(pd *PinDesc, drv GPIODriver) AnalogPin {
|
||||
return &bbbAnalogPin{id: pd.ID, n: pd.AnalogLogical, drv: drv}
|
||||
}
|
||||
|
||||
func (p *bbbAnalogPin) N() int {
|
||||
@ -227,6 +230,10 @@ func (p *bbbAnalogPin) Read() (int, error) {
|
||||
}
|
||||
|
||||
func (p *bbbAnalogPin) Close() error {
|
||||
if err := p.drv.Unregister(p.id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !p.initialized {
|
||||
return nil
|
||||
}
|
||||
@ -257,6 +264,8 @@ const (
|
||||
type bbbPWMPin struct {
|
||||
n string
|
||||
|
||||
drv GPIODriver
|
||||
|
||||
period int
|
||||
polarity Polarity
|
||||
|
||||
@ -267,8 +276,8 @@ type bbbPWMPin struct {
|
||||
initialized bool
|
||||
}
|
||||
|
||||
func newBBBPWMPin(n string) PWMPin {
|
||||
return &bbbPWMPin{n: n}
|
||||
func newBBBPWMPin(pd *PinDesc, drv GPIODriver) PWMPin {
|
||||
return &bbbPWMPin{n: pd.ID, drv: drv}
|
||||
}
|
||||
|
||||
func (p *bbbPWMPin) N() string {
|
||||
@ -463,6 +472,10 @@ func (p *bbbPWMPin) reset() error {
|
||||
}
|
||||
|
||||
func (p *bbbPWMPin) Close() error {
|
||||
if err := p.drv.Unregister(p.n); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !p.initialized {
|
||||
return nil
|
||||
}
|
||||
|
41
bbb_test.go
Normal file
41
bbb_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
package embd
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBBBAnalogPinClose(t *testing.T) {
|
||||
pinMap := PinMap{
|
||||
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapAnalog},
|
||||
}
|
||||
driver := newGPIODriver(pinMap, nil, newBBBAnalogPin, nil)
|
||||
pin, err := driver.AnalogPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up analog pin 1: got %v", err)
|
||||
}
|
||||
pin.Close()
|
||||
pin2, err := driver.AnalogPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up analog pin 1: got %v", err)
|
||||
}
|
||||
if pin == pin2 {
|
||||
t.Fatal("Looking up closed analog pin 1: but got the old instance")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBBBPWMPinClose(t *testing.T) {
|
||||
pinMap := PinMap{
|
||||
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapPWM},
|
||||
}
|
||||
driver := newGPIODriver(pinMap, nil, nil, newBBBPWMPin)
|
||||
pin, err := driver.PWMPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up pwm pin 1: got %v", err)
|
||||
}
|
||||
pin.Close()
|
||||
pin2, err := driver.PWMPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up pwm pin 1: got %v", err)
|
||||
}
|
||||
if pin == pin2 {
|
||||
t.Fatal("Looking up closed pwm pin 1: but got the old instance")
|
||||
}
|
||||
}
|
@ -14,7 +14,10 @@ import (
|
||||
)
|
||||
|
||||
type digitalPin struct {
|
||||
n int
|
||||
id string
|
||||
n int
|
||||
|
||||
drv GPIODriver
|
||||
|
||||
dir *os.File
|
||||
val *os.File
|
||||
@ -25,8 +28,8 @@ type digitalPin struct {
|
||||
initialized bool
|
||||
}
|
||||
|
||||
func newDigitalPin(n int) DigitalPin {
|
||||
return &digitalPin{n: n, readBuf: make([]byte, 1)}
|
||||
func newDigitalPin(pd *PinDesc, drv GPIODriver) DigitalPin {
|
||||
return &digitalPin{id: pd.ID, n: pd.DigitalLogical, drv: drv, readBuf: make([]byte, 1)}
|
||||
}
|
||||
|
||||
func (p *digitalPin) N() int {
|
||||
@ -223,6 +226,10 @@ func (p *digitalPin) PullDown() error {
|
||||
}
|
||||
|
||||
func (p *digitalPin) Close() error {
|
||||
if err := p.drv.Unregister(p.id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !p.initialized {
|
||||
return nil
|
||||
}
|
||||
|
22
digitalpin_test.go
Normal file
22
digitalpin_test.go
Normal file
@ -0,0 +1,22 @@
|
||||
package embd
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDigitalPinClose(t *testing.T) {
|
||||
pinMap := PinMap{
|
||||
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapDigital},
|
||||
}
|
||||
driver := newGPIODriver(pinMap, newDigitalPin, nil, nil)
|
||||
pin, err := driver.DigitalPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up digital pin 1: got %v", err)
|
||||
}
|
||||
pin.Close()
|
||||
pin2, err := driver.DigitalPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up digital pin 1: got %v", err)
|
||||
}
|
||||
if pin == pin2 {
|
||||
t.Fatal("Looking up closed digital pin 1: but got the old instance")
|
||||
}
|
||||
}
|
3
gpio.go
3
gpio.go
@ -103,6 +103,9 @@ type PWMPin interface {
|
||||
|
||||
// GPIODriver implements a generic GPIO driver.
|
||||
type GPIODriver interface {
|
||||
// Unregister unregisters the pin from the driver. Should be called when the pin is closed.
|
||||
Unregister(string) error
|
||||
|
||||
// DigitalPin returns a pin capable of doing digital IO.
|
||||
DigitalPin(key interface{}) (DigitalPin, error)
|
||||
|
||||
|
@ -11,9 +11,9 @@ type pin interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
type digitalPinFactory func(n int) DigitalPin
|
||||
type analogPinFactory func(n int) AnalogPin
|
||||
type pwmPinFactory func(n string) PWMPin
|
||||
type digitalPinFactory func(pd *PinDesc, drv GPIODriver) DigitalPin
|
||||
type analogPinFactory func(pd *PinDesc, drv GPIODriver) AnalogPin
|
||||
type pwmPinFactory func(pd *PinDesc, drv GPIODriver) PWMPin
|
||||
|
||||
type gpioDriver struct {
|
||||
pinMap PinMap
|
||||
@ -36,6 +36,15 @@ func newGPIODriver(pinMap PinMap, dpf digitalPinFactory, apf analogPinFactory, p
|
||||
}
|
||||
}
|
||||
|
||||
func (io *gpioDriver) Unregister(id string) error {
|
||||
if _, ok := io.initializedPins[id]; !ok {
|
||||
return fmt.Errorf("gpio: pin %v is not registered yet, cannot unregister", id)
|
||||
}
|
||||
|
||||
delete(io.initializedPins, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (io *gpioDriver) DigitalPin(key interface{}) (DigitalPin, error) {
|
||||
if io.dpf == nil {
|
||||
return nil, errors.New("gpio: digital io not supported on this host")
|
||||
@ -46,7 +55,11 @@ func (io *gpioDriver) DigitalPin(key interface{}) (DigitalPin, error) {
|
||||
return nil, fmt.Errorf("gpio: could not find pin matching %v", key)
|
||||
}
|
||||
|
||||
p := io.dpf(pd.DigitalLogical)
|
||||
if p, ok := io.initializedPins[pd.ID]; ok {
|
||||
return p.(DigitalPin), nil
|
||||
}
|
||||
|
||||
p := io.dpf(pd, io)
|
||||
io.initializedPins[pd.ID] = p
|
||||
|
||||
return p, nil
|
||||
@ -62,7 +75,11 @@ func (io *gpioDriver) AnalogPin(key interface{}) (AnalogPin, error) {
|
||||
return nil, fmt.Errorf("gpio: could not find pin matching %v", key)
|
||||
}
|
||||
|
||||
p := io.apf(pd.AnalogLogical)
|
||||
if p, ok := io.initializedPins[pd.ID]; ok {
|
||||
return p.(AnalogPin), nil
|
||||
}
|
||||
|
||||
p := io.apf(pd, io)
|
||||
io.initializedPins[pd.ID] = p
|
||||
|
||||
return p, nil
|
||||
@ -78,7 +95,11 @@ func (io *gpioDriver) PWMPin(key interface{}) (PWMPin, error) {
|
||||
return nil, fmt.Errorf("gpio: could not find pin matching %v", key)
|
||||
}
|
||||
|
||||
p := io.ppf(pd.ID)
|
||||
if p, ok := io.initializedPins[pd.ID]; ok {
|
||||
return p.(PWMPin), nil
|
||||
}
|
||||
|
||||
p := io.ppf(pd, io)
|
||||
io.initializedPins[pd.ID] = p
|
||||
|
||||
return p, nil
|
||||
|
@ -6,7 +6,10 @@ import (
|
||||
)
|
||||
|
||||
type fakeDigitalPin struct {
|
||||
n int
|
||||
id string
|
||||
n int
|
||||
|
||||
drv GPIODriver
|
||||
}
|
||||
|
||||
func (p *fakeDigitalPin) N() int {
|
||||
@ -41,12 +44,12 @@ func (*fakeDigitalPin) PullDown() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*fakeDigitalPin) Close() error {
|
||||
return nil
|
||||
func (p *fakeDigitalPin) Close() error {
|
||||
return p.drv.Unregister(p.id)
|
||||
}
|
||||
|
||||
func newFakeDigitalPin(n int) DigitalPin {
|
||||
return &fakeDigitalPin{n}
|
||||
func newFakeDigitalPin(pd *PinDesc, drv GPIODriver) DigitalPin {
|
||||
return &fakeDigitalPin{id: pd.ID, n: pd.DigitalLogical, drv: drv}
|
||||
}
|
||||
|
||||
func TestGpioDriverDigitalPin(t *testing.T) {
|
||||
@ -73,7 +76,10 @@ func TestGpioDriverDigitalPin(t *testing.T) {
|
||||
}
|
||||
|
||||
type fakeAnalogPin struct {
|
||||
n int
|
||||
id string
|
||||
n int
|
||||
|
||||
drv GPIODriver
|
||||
}
|
||||
|
||||
func (p *fakeAnalogPin) N() int {
|
||||
@ -92,8 +98,8 @@ func (*fakeAnalogPin) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newFakeAnalogPin(n int) AnalogPin {
|
||||
return &fakeAnalogPin{n}
|
||||
func newFakeAnalogPin(pd *PinDesc, drv GPIODriver) AnalogPin {
|
||||
return &fakeAnalogPin{id: pd.ID, n: pd.AnalogLogical, drv: drv}
|
||||
}
|
||||
|
||||
func TestGpioDriverAnalogPin(t *testing.T) {
|
||||
@ -142,3 +148,32 @@ func TestGpioDriverUnavailablePinType(t *testing.T) {
|
||||
t.Fatalf("Looking up analog pin 1: got error %q, expected %q", err, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGpioPinCaching(t *testing.T) {
|
||||
pinMap := PinMap{
|
||||
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapDigital},
|
||||
}
|
||||
driver := newGPIODriver(pinMap, newFakeDigitalPin, nil, nil)
|
||||
pin, err := driver.DigitalPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up digital pin 1: got %v", err)
|
||||
}
|
||||
// Lookup the same pin again
|
||||
pin2, err := driver.DigitalPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up digital pin 1: got %v", err)
|
||||
}
|
||||
if pin != pin2 {
|
||||
t.Fatalf("Looking up digital pin 1 for the second time: got %v, want %v", &pin2, &pin)
|
||||
}
|
||||
// Looking up a closed pin
|
||||
pin.Close()
|
||||
pin3, err := driver.DigitalPin(1)
|
||||
if err != nil {
|
||||
t.Fatalf("Looking up digital pin 1: got %v", err)
|
||||
return
|
||||
}
|
||||
if pin == pin3 {
|
||||
t.Fatal("Looking up a closed pin, but got the same old instance")
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user