mirror of
https://github.com/kidoman/embd
synced 2024-12-22 12:50:19 +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 {
|
type bbbAnalogPin struct {
|
||||||
n int
|
id string
|
||||||
|
n int
|
||||||
|
|
||||||
|
drv GPIODriver
|
||||||
|
|
||||||
val *os.File
|
val *os.File
|
||||||
|
|
||||||
initialized bool
|
initialized bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBBBAnalogPin(n int) AnalogPin {
|
func newBBBAnalogPin(pd *PinDesc, drv GPIODriver) AnalogPin {
|
||||||
return &bbbAnalogPin{n: n}
|
return &bbbAnalogPin{id: pd.ID, n: pd.AnalogLogical, drv: drv}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *bbbAnalogPin) N() int {
|
func (p *bbbAnalogPin) N() int {
|
||||||
@ -227,6 +230,10 @@ func (p *bbbAnalogPin) Read() (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *bbbAnalogPin) Close() error {
|
func (p *bbbAnalogPin) Close() error {
|
||||||
|
if err := p.drv.Unregister(p.id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !p.initialized {
|
if !p.initialized {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -257,6 +264,8 @@ const (
|
|||||||
type bbbPWMPin struct {
|
type bbbPWMPin struct {
|
||||||
n string
|
n string
|
||||||
|
|
||||||
|
drv GPIODriver
|
||||||
|
|
||||||
period int
|
period int
|
||||||
polarity Polarity
|
polarity Polarity
|
||||||
|
|
||||||
@ -267,8 +276,8 @@ type bbbPWMPin struct {
|
|||||||
initialized bool
|
initialized bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBBBPWMPin(n string) PWMPin {
|
func newBBBPWMPin(pd *PinDesc, drv GPIODriver) PWMPin {
|
||||||
return &bbbPWMPin{n: n}
|
return &bbbPWMPin{n: pd.ID, drv: drv}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *bbbPWMPin) N() string {
|
func (p *bbbPWMPin) N() string {
|
||||||
@ -463,6 +472,10 @@ func (p *bbbPWMPin) reset() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *bbbPWMPin) Close() error {
|
func (p *bbbPWMPin) Close() error {
|
||||||
|
if err := p.drv.Unregister(p.n); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !p.initialized {
|
if !p.initialized {
|
||||||
return nil
|
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 {
|
type digitalPin struct {
|
||||||
n int
|
id string
|
||||||
|
n int
|
||||||
|
|
||||||
|
drv GPIODriver
|
||||||
|
|
||||||
dir *os.File
|
dir *os.File
|
||||||
val *os.File
|
val *os.File
|
||||||
@ -25,8 +28,8 @@ type digitalPin struct {
|
|||||||
initialized bool
|
initialized bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDigitalPin(n int) DigitalPin {
|
func newDigitalPin(pd *PinDesc, drv GPIODriver) DigitalPin {
|
||||||
return &digitalPin{n: n, readBuf: make([]byte, 1)}
|
return &digitalPin{id: pd.ID, n: pd.DigitalLogical, drv: drv, readBuf: make([]byte, 1)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *digitalPin) N() int {
|
func (p *digitalPin) N() int {
|
||||||
@ -223,6 +226,10 @@ func (p *digitalPin) PullDown() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *digitalPin) Close() error {
|
func (p *digitalPin) Close() error {
|
||||||
|
if err := p.drv.Unregister(p.id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if !p.initialized {
|
if !p.initialized {
|
||||||
return nil
|
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.
|
// GPIODriver implements a generic GPIO driver.
|
||||||
type GPIODriver interface {
|
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 returns a pin capable of doing digital IO.
|
||||||
DigitalPin(key interface{}) (DigitalPin, error)
|
DigitalPin(key interface{}) (DigitalPin, error)
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ type pin interface {
|
|||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type digitalPinFactory func(n int) DigitalPin
|
type digitalPinFactory func(pd *PinDesc, drv GPIODriver) DigitalPin
|
||||||
type analogPinFactory func(n int) AnalogPin
|
type analogPinFactory func(pd *PinDesc, drv GPIODriver) AnalogPin
|
||||||
type pwmPinFactory func(n string) PWMPin
|
type pwmPinFactory func(pd *PinDesc, drv GPIODriver) PWMPin
|
||||||
|
|
||||||
type gpioDriver struct {
|
type gpioDriver struct {
|
||||||
pinMap PinMap
|
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) {
|
func (io *gpioDriver) DigitalPin(key interface{}) (DigitalPin, error) {
|
||||||
if io.dpf == nil {
|
if io.dpf == nil {
|
||||||
return nil, errors.New("gpio: digital io not supported on this host")
|
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)
|
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
|
io.initializedPins[pd.ID] = p
|
||||||
|
|
||||||
return p, nil
|
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)
|
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
|
io.initializedPins[pd.ID] = p
|
||||||
|
|
||||||
return p, nil
|
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)
|
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
|
io.initializedPins[pd.ID] = p
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
|
@ -6,7 +6,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type fakeDigitalPin struct {
|
type fakeDigitalPin struct {
|
||||||
n int
|
id string
|
||||||
|
n int
|
||||||
|
|
||||||
|
drv GPIODriver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *fakeDigitalPin) N() int {
|
func (p *fakeDigitalPin) N() int {
|
||||||
@ -41,12 +44,12 @@ func (*fakeDigitalPin) PullDown() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*fakeDigitalPin) Close() error {
|
func (p *fakeDigitalPin) Close() error {
|
||||||
return nil
|
return p.drv.Unregister(p.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFakeDigitalPin(n int) DigitalPin {
|
func newFakeDigitalPin(pd *PinDesc, drv GPIODriver) DigitalPin {
|
||||||
return &fakeDigitalPin{n}
|
return &fakeDigitalPin{id: pd.ID, n: pd.DigitalLogical, drv: drv}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGpioDriverDigitalPin(t *testing.T) {
|
func TestGpioDriverDigitalPin(t *testing.T) {
|
||||||
@ -73,7 +76,10 @@ func TestGpioDriverDigitalPin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type fakeAnalogPin struct {
|
type fakeAnalogPin struct {
|
||||||
n int
|
id string
|
||||||
|
n int
|
||||||
|
|
||||||
|
drv GPIODriver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *fakeAnalogPin) N() int {
|
func (p *fakeAnalogPin) N() int {
|
||||||
@ -92,8 +98,8 @@ func (*fakeAnalogPin) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFakeAnalogPin(n int) AnalogPin {
|
func newFakeAnalogPin(pd *PinDesc, drv GPIODriver) AnalogPin {
|
||||||
return &fakeAnalogPin{n}
|
return &fakeAnalogPin{id: pd.ID, n: pd.AnalogLogical, drv: drv}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGpioDriverAnalogPin(t *testing.T) {
|
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)
|
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