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:
Karan Misra 2014-04-06 05:30:54 +05:30
parent 6f90af377d
commit 57328c979d
7 changed files with 164 additions and 22 deletions

23
bbb.go
View File

@ -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
View 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")
}
}

View File

@ -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
View 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")
}
}

View File

@ -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)

View File

@ -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

View File

@ -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")
}
}