Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add INPUT_PULLUP support on firmdata platform #728

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions drivers/gpio/aip1640_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
//
// Library ported from: https://github.com/wemos/WEMOS_Matrix_LED_Shield_Arduino_Library
type AIP1640Driver struct {
pinClock *DirectPinDriver
pinClock *DirectPinDriver
pinData *DirectPinDriver
name string
intensity byte
Expand All @@ -34,7 +34,7 @@ type AIP1640Driver struct {
func NewAIP1640Driver(a gobot.Connection, clockPin string, dataPin string) *AIP1640Driver {
t := &AIP1640Driver{
name: gobot.DefaultName("AIP1640Driver"),
pinClock: NewDirectPinDriver(a, clockPin),
pinClock: NewDirectPinDriver(a, clockPin),
pinData: NewDirectPinDriver(a, dataPin),
intensity: 7,
connection: a,
Expand Down
44 changes: 36 additions & 8 deletions drivers/gpio/button_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (

// ButtonDriver Represents a digital Button
type ButtonDriver struct {
Active bool
DefaultState int
pin string
name string
halt chan bool
interval time.Duration
connection DigitalReader
Active bool
DefaultState int
pin string
name string
halt chan bool
interval time.Duration
connection DigitalReader
connectionInputPullup DigitalReaderInputPullup
inputPullup bool
gobot.Eventer
}

Expand All @@ -33,6 +35,7 @@ func NewButtonDriver(a DigitalReader, pin string, v ...time.Duration) *ButtonDri
Eventer: gobot.NewEventer(),
interval: 10 * time.Millisecond,
halt: make(chan bool),
inputPullup: false,
}

if len(v) > 0 {
Expand All @@ -56,7 +59,14 @@ func (b *ButtonDriver) Start() (err error) {
state := b.DefaultState
go func() {
for {
newValue, err := b.connection.DigitalRead(b.Pin())
var newValue int
var err error
if b.IsInputPullup() {
newValue, err = b.connectionInputPullup.DigitalReadInputPullup(b.Pin())
} else {
newValue, err = b.connection.DigitalRead(b.Pin())
}

if err != nil {
b.Publish(Error, err)
} else if newValue != state && newValue != -1 {
Expand All @@ -73,6 +83,24 @@ func (b *ButtonDriver) Start() (err error) {
return
}

// SetInputPullup permit to put pin mode as INPUT_PULLUP
// Your pletaform must be support it
func (b *ButtonDriver) SetInputPullup() (err error) {
if reader, ok := b.Connection().(DigitalReaderInputPullup); ok {
b.connectionInputPullup = reader
b.inputPullup = true

return
}

err = ErrDigitalReadInputPullupUnsupported

return
}

// IsInputPullup return if pin is setting as INPUT_PULLUP
func (b *ButtonDriver) IsInputPullup() bool { return b.inputPullup }

// Halt stops polling the button for new information
func (b *ButtonDriver) Halt() (err error) {
b.halt <- true
Expand Down
89 changes: 89 additions & 0 deletions drivers/gpio/button_driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ func initTestButtonDriver() *ButtonDriver {
return NewButtonDriver(newGpioTestAdaptor(), "1")
}

func initTestButtonInputPullupDriver() *ButtonDriver {
return NewButtonDriver(newGpioInputPullupTestAdaptor(), "1")
}

func TestButtonDriverHalt(t *testing.T) {
d := initTestButtonDriver()
go func() {
Expand Down Expand Up @@ -157,3 +161,88 @@ func TestButtonDriverSetName(t *testing.T) {
g.SetName("mybot")
gobottest.Assert(t, g.Name(), "mybot")
}

func TestButtonDriverSetInputPullup(t *testing.T) {
g := initTestButtonInputPullupDriver()
err := g.SetInputPullup()
gobottest.Assert(t, err, nil)
gobottest.Assert(t, g.IsInputPullup(), true)

g = initTestButtonDriver()
err = g.SetInputPullup()
gobottest.Assert(t, err, ErrDigitalReadInputPullupUnsupported)
}

func TestButtonInputPullupDriverStart(t *testing.T) {
sem := make(chan bool, 0)
a := newGpioInputPullupTestAdaptor()
d := NewButtonDriver(a, "1")
err := d.SetInputPullup()
gobottest.Assert(t, err, nil)

d.Once(ButtonPush, func(data interface{}) {
gobottest.Assert(t, d.Active, true)
sem <- true
})

a.TestAdaptorDigitalRead(func() (val int, err error) {
val = 1
return
})

gobottest.Assert(t, d.Start(), nil)

select {
case <-sem:
case <-time.After(buttonTestDelay * time.Millisecond):
t.Errorf("Button Event \"Push\" was not published")
}

d.Once(ButtonRelease, func(data interface{}) {
gobottest.Assert(t, d.Active, false)
sem <- true
})

a.TestAdaptorDigitalRead(func() (val int, err error) {
val = 0
return
})

select {
case <-sem:
case <-time.After(buttonTestDelay * time.Millisecond):
t.Errorf("Button Event \"Release\" was not published")
}

d.Once(Error, func(data interface{}) {
sem <- true
})

a.TestAdaptorDigitalRead(func() (val int, err error) {
err = errors.New("digital read error")
return
})

select {
case <-sem:
case <-time.After(buttonTestDelay * time.Millisecond):
t.Errorf("Button Event \"Error\" was not published")
}

d.Once(ButtonPush, func(data interface{}) {
sem <- true
})

d.halt <- true

a.TestAdaptorDigitalRead(func() (val int, err error) {
val = 1
return
})

select {
case <-sem:
t.Errorf("Button Event \"Press\" should not published")
case <-time.After(buttonTestDelay * time.Millisecond):
}
}
43 changes: 36 additions & 7 deletions drivers/gpio/direct_pin_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import (

// DirectPinDriver represents a GPIO pin
type DirectPinDriver struct {
name string
pin string
connection gobot.Connection
name string
pin string
inputPullup bool
connection gobot.Connection
connectionInputPullup DigitalReaderInputPullup
gobot.Commander
}

Expand All @@ -24,10 +26,11 @@ type DirectPinDriver struct {
// "ServoWrite" - See DirectPinDriver.ServoWrite
func NewDirectPinDriver(a gobot.Connection, pin string) *DirectPinDriver {
d := &DirectPinDriver{
name: gobot.DefaultName("DirectPin"),
connection: a,
pin: pin,
Commander: gobot.NewCommander(),
name: gobot.DefaultName("DirectPin"),
connection: a,
pin: pin,
Commander: gobot.NewCommander(),
inputPullup: false,
}

d.AddCommand("DigitalRead", func(params map[string]interface{}) interface{} {
Expand All @@ -50,6 +53,25 @@ func NewDirectPinDriver(a gobot.Connection, pin string) *DirectPinDriver {
return d
}

// SetInputPullup permit to put pin mode as INPUT_PULLUP
// Your pletaform must be support it
func (d *DirectPinDriver) SetInputPullup() (err error) {

if reader, ok := d.Connection().(DigitalReaderInputPullup); ok {
d.connectionInputPullup = reader
d.inputPullup = true

return
}

err = ErrDigitalReadInputPullupUnsupported

return
}

// IsInputPullup return if pin is setting as INPUT_PULLUP
func (d *DirectPinDriver) IsInputPullup() bool { return d.inputPullup }

// Name returns the DirectPinDrivers name
func (d *DirectPinDriver) Name() string { return d.name }

Expand Down Expand Up @@ -88,10 +110,17 @@ func (d *DirectPinDriver) On() (err error) {

// DigitalRead returns the current digital state of the pin
func (d *DirectPinDriver) DigitalRead() (val int, err error) {

if d.IsInputPullup() {
return d.connectionInputPullup.DigitalReadInputPullup(d.Pin())
}

if reader, ok := d.Connection().(DigitalReader); ok {
return reader.DigitalRead(d.Pin())

}
err = ErrDigitalReadUnsupported

return
}

Expand Down
42 changes: 42 additions & 0 deletions drivers/gpio/direct_pin_driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ func initTestDirectPinDriver() *DirectPinDriver {
return NewDirectPinDriver(a, "1")
}

func initTestDirectPinInputPullupDriver() *DirectPinDriver {
a := newGpioInputPullupTestAdaptor()
a.testAdaptorDigitalRead = func() (val int, err error) {
val = 1
return
}
a.testAdaptorDigitalReadInputPullup = func() (val int, err error) {
val = 1
return
}
a.testAdaptorDigitalWrite = func() (err error) {
return errors.New("write error")
}
a.testAdaptorPwmWrite = func() (err error) {
return errors.New("write error")
}
a.testAdaptorServoWrite = func() (err error) {
return errors.New("write error")
}
return NewDirectPinDriver(a, "1")
}

func TestDirectPinDriver(t *testing.T) {
var ret map[string]interface{}
var err interface{}
Expand Down Expand Up @@ -169,3 +191,23 @@ func TestDirectPinDriverSetName(t *testing.T) {
d.SetName("mybot")
gobottest.Assert(t, d.Name(), "mybot")
}

func TestDirectPinDriverSetInputPullup(t *testing.T) {
d := initTestDirectPinInputPullupDriver()
err := d.SetInputPullup()
gobottest.Assert(t, err, nil)
gobottest.Assert(t, d.IsInputPullup(), true)

d = initTestDirectPinDriver()
err = d.SetInputPullup()
gobottest.Assert(t, err, ErrDigitalReadInputPullupUnsupported)
}

func TestDirectPinDriverDigitalReadInputPullup(t *testing.T) {
d := initTestDirectPinInputPullupDriver()
err := d.SetInputPullup()
gobottest.Assert(t, err, nil)
ret, err := d.DigitalRead()
gobottest.Assert(t, ret, 1)
gobottest.Assert(t, err, nil)
}
1 change: 0 additions & 1 deletion drivers/gpio/easy_driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,3 @@ func TestEasyDriverDisable(t *testing.T) {
gobottest.Assert(t, d.IsEnabled(), false)
gobottest.Assert(t, d.IsMoving(), false)
}

8 changes: 8 additions & 0 deletions drivers/gpio/gpio.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ var (
// ErrDigitalReadUnsupported is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrDigitalReadUnsupported = errors.New("DigitalRead is not supported by this platform")
// ErrDigitalReadInputPullupUnsupported is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrDigitalReadInputPullupUnsupported = errors.New("DigitalRead with INPUT_PULLUP is not supported by this platform")
// ErrServoOutOfRange is the error resulting when a driver attempts to use
// hardware capabilities which a connection does not support
ErrServoOutOfRange = errors.New("servo angle must be between 0-180")
Expand Down Expand Up @@ -61,3 +64,8 @@ type DigitalWriter interface {
type DigitalReader interface {
DigitalRead(string) (val int, err error)
}

// DigitalReaderInputPullup interface represents an Adaptor which has DigitalRead capabilities with INPUT_PULLUP
type DigitalReaderInputPullup interface {
DigitalReadInputPullup(string) (val int, err error)
}
41 changes: 41 additions & 0 deletions drivers/gpio/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type gpioTestAdaptor struct {
testAdaptorDigitalRead func() (val int, err error)
}

type gpioInputPullupTestAdaptor struct {
testAdaptorDigitalReadInputPullup func() (val int, err error)
gpioTestAdaptor
}

func (t *gpioTestAdaptor) TestAdaptorDigitalWrite(f func() (err error)) {
t.mtx.Lock()
defer t.mtx.Unlock()
Expand Down Expand Up @@ -103,3 +108,39 @@ func newGpioTestAdaptor() *gpioTestAdaptor {
},
}
}

func (t *gpioInputPullupTestAdaptor) TestAdaptorDigitalReadInputPullup(f func() (val int, err error)) {
t.mtx.Lock()
defer t.mtx.Unlock()
t.testAdaptorDigitalReadInputPullup = f
}
func (t *gpioInputPullupTestAdaptor) DigitalReadInputPullup(string) (val int, err error) {
t.mtx.Lock()
defer t.mtx.Unlock()
return t.testAdaptorDigitalRead()
}
func newGpioInputPullupTestAdaptor() *gpioInputPullupTestAdaptor {
return &gpioInputPullupTestAdaptor{
gpioTestAdaptor: gpioTestAdaptor{
port: "/dev/null",
testAdaptorDigitalWrite: func() (err error) {
return nil
},
testAdaptorServoWrite: func() (err error) {
return nil
},
testAdaptorPwmWrite: func() (err error) {
return nil
},
testAdaptorAnalogRead: func() (val int, err error) {
return 99, nil
},
testAdaptorDigitalRead: func() (val int, err error) {
return 1, nil
},
},
testAdaptorDigitalReadInputPullup: func() (val int, err error) {
return 1, nil
},
}
}