Skip to content

Commit

Permalink
add advanced digital pin options (pull, bias, drive, debounce, event)
Browse files Browse the repository at this point in the history
  • Loading branch information
gen2thomas authored Jan 28, 2023
1 parent 6c7ecbe commit 9ce45c0
Show file tree
Hide file tree
Showing 18 changed files with 1,344 additions and 122 deletions.
19 changes: 18 additions & 1 deletion adaptor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package gobot

import "io"
import (
"io"
"time"
)

// DigitalPinOptioner is the interface to provide the possibility to change pin behavior for the next usage
type DigitalPinOptioner interface {
Expand All @@ -10,6 +13,20 @@ type DigitalPinOptioner interface {
SetDirectionOutput(initialState int) (changed bool)
// SetDirectionInput sets the pins direction to input
SetDirectionInput() (changed bool)
// SetActiveLow initializes the pin with inverse reaction (applies on input and output).
SetActiveLow() (changed bool)
// SetBias initializes the pin with the given bias (applies on input and output).
SetBias(bias int) (changed bool)
// SetDrive initializes the output pin with the given drive option.
SetDrive(drive int) (changed bool)
// SetDebounce initializes the input pin with the given debounce period.
SetDebounce(period time.Duration) (changed bool)
// SetEventHandlerForEdge initializes the input pin for edge detection and to call the event handler on specified edge.
// lineOffset is within the GPIO chip (needs to transformed to the pin id), timestamp is the detection time,
// detectedEdge contains the direction of the pin changes, seqno is the sequence number for this event in the sequence
// of events for all the lines in this line request, lseqno is the same but for this line
SetEventHandlerForEdge(handler func(lineOffset int, timestamp time.Duration, detectedEdge string, seqno uint32,
lseqno uint32), edge int) (changed bool)
}

// DigitalPinOptionApplier is the interface to apply options to change pin behavior immediately
Expand Down
78 changes: 78 additions & 0 deletions examples/raspi_direct_pin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// +build example
//
// Do not build by default.

package main

import (
"fmt"
"time"

"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/gpio"
"gobot.io/x/gobot/platforms/adaptors"
"gobot.io/x/gobot/platforms/raspi"
)

// Wiring
// PWR Raspi: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND)
// GPIO Raspi: header pin 21 (GPIO9) is input, pin 24 (GPIO8) is normal output, pin 26 (GPIO7) is inverted output
// Button: the input pin is wired with a button to GND, the internal pull up resistor is used
// LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) to VCC
// Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state changes
func main() {
const (
inPinNum = "21"
outPinNum = "24"
outPinInvertedNum = "26"
)
// note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up
board := raspi.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum),
adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum),
adaptors.WithGpiosPullUp(inPinNum),
adaptors.WithGpioDebounce(inPinNum, 2*time.Second))

inPin := gpio.NewDirectPinDriver(board, inPinNum)
outPin := gpio.NewDirectPinDriver(board, outPinNum)
outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum)

work := func() {
level := byte(1)

gobot.Every(500*time.Millisecond, func() {
read, err := inPin.DigitalRead()
fmt.Printf("pin %s state is %d\n", inPinNum, read)
if err != nil {
fmt.Println(err)
} else {
level = byte(read)
}

err = outPin.DigitalWrite(level)
fmt.Printf("pin %s is now %d\n", outPinNum, level)
if err != nil {
fmt.Println(err)
}

err = outPinInverted.DigitalWrite(level)
fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level)
if err != nil {
fmt.Println(err)
}

if level == 1 {
level = 0
} else {
level = 1
}
})
}

robot := gobot.NewRobot("pinBot",
[]gobot.Connection{board},
[]gobot.Device{inPin, outPin, outPinInverted},
work,
)

robot.Start()
}
97 changes: 97 additions & 0 deletions examples/raspi_direct_pin_event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// +build example
//
// Do not build by default.

package main

import (
"fmt"
"time"

"gobot.io/x/gobot"
"gobot.io/x/gobot/platforms/raspi"
"gobot.io/x/gobot/system"
)

const (
inPinNum = "21"
outPinNum = "24"
outPinInvertedNum = "26"
debounceTime = 2 * time.Second
)

var (
outPin gobot.DigitalPinner
outPinInverted gobot.DigitalPinner
)

// Wiring
// PWR Raspi: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND)
// GPIO Raspi: header pin 21 (GPIO9) is input, pin 24 (GPIO8) is normal output, pin 26 (GPIO7) is inverted output
// Button: the input pin is wired with a button to GND, the internal pull up resistor is used
// LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) to VCC
// Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state changes
func main() {

board := raspi.NewAdaptor()

work := func() {
inPin, err := board.DigitalPin(inPinNum)
if err != nil {
fmt.Println(err)
}
if err := inPin.ApplyOptions(system.WithPinDirectionInput(), system.WithPinPullUp(),
system.WithPinDebounce(debounceTime), system.WithPinEventOnBothEdges(buttonEventHandler)); err != nil {
fmt.Println(err)
}

// note: WithPinOpenDrain() is optional, if using WithPinOpenSource() the LED's will not light up
outPin, err = board.DigitalPin(outPinNum)
if err != nil {
fmt.Println(err)
}
if err := outPin.ApplyOptions(system.WithPinDirectionOutput(1), system.WithPinOpenDrain()); err != nil {
fmt.Println(err)
}

outPinInverted, err = board.DigitalPin(outPinInvertedNum)
if err != nil {
fmt.Println(err)
}
if err := outPinInverted.ApplyOptions(system.WithPinActiveLow(), system.WithPinDirectionOutput(1),
system.WithPinOpenDrain()); err != nil {
fmt.Println(err)
}

fmt.Printf("\nPlease press and hold the button for at least %s\n", debounceTime)
}

robot := gobot.NewRobot("pinEdgeBot",
[]gobot.Connection{board},
[]gobot.Device{},
work,
)

robot.Start()
}

func buttonEventHandler(offset int, t time.Duration, et string, sn uint32, lsn uint32) {
fmt.Printf("%s: %s detected on line %d with total sequence %d and line sequence %d\n", t, et, offset, sn, lsn)
level := 1

if et == "falling edge" {
level = 0
}

err := outPin.Write(level)
fmt.Printf("pin %s is now %d\n", outPinNum, level)
if err != nil {
fmt.Println(err)
}

err = outPinInverted.Write(level)
fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level)
if err != nil {
fmt.Println(err)
}
}
39 changes: 32 additions & 7 deletions examples/tinkerboard_direct_pin.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,51 @@ import (

"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/gpio"
"gobot.io/x/gobot/platforms/adaptors"
"gobot.io/x/gobot/platforms/tinkerboard"
)

// Wiring
// PWR Tinkerboard: 1 (+3.3V, VCC), 2(+5V), 6, 9, 14, 20 (GND)
// GPIO Tinkerboard: header pin 26 used as output
// GPIO Tinkerboard: header pin 21 is input, pin 24 used as normal output, pin 26 used as inverted output
// Button: the input pin is wired with a button to GND, an external pull up resistor is needed (e.g. 1K)
// LED's: the output pins are wired to the cathode of a LED, the anode is wired with a resistor (70-130Ohm for 20mA) to VCC
// Expected behavior: always one LED is on, the other in opposite state, on button press the state changes
func main() {
const pinNo = "26"
board := tinkerboard.NewAdaptor()
pin := gpio.NewDirectPinDriver(board, pinNo)
const (
inPinNum = "21"
outPinNum = "24"
outPinInvertedNum = "26"
)
board := tinkerboard.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum))
inPin := gpio.NewDirectPinDriver(board, inPinNum)
outPin := gpio.NewDirectPinDriver(board, outPinNum)
outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum)

work := func() {
level := byte(1)

gobot.Every(500*time.Millisecond, func() {
err := pin.DigitalWrite(level)
fmt.Printf("pin %s is now %d\n", pinNo, level)
read, err := inPin.DigitalRead()
fmt.Printf("pin %s state is %d\n", inPinNum, read)
if err != nil {
fmt.Println(err)
} else {
level = byte(read)
}

err = outPin.DigitalWrite(level)
fmt.Printf("pin %s is now %d\n", outPinNum, level)
if err != nil {
fmt.Println(err)
}

err = outPinInverted.DigitalWrite(level)
fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level)
if err != nil {
fmt.Println(err)
}

if level == 1 {
level = 0
} else {
Expand All @@ -41,7 +66,7 @@ func main() {

robot := gobot.NewRobot("pinBot",
[]gobot.Connection{board},
[]gobot.Device{pin},
[]gobot.Device{inPin, outPin, outPinInverted},
work,
)

Expand Down
Loading

0 comments on commit 9ce45c0

Please sign in to comment.