mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-24 13:48:49 +08:00
core: some WIP on using digitalread and analogread event subscriptions for all gpio drivers
Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
parent
4577cdad60
commit
8851344da1
@ -12,7 +12,7 @@ type AnalogSensorDriver struct {
|
|||||||
pin string
|
pin string
|
||||||
halt chan bool
|
halt chan bool
|
||||||
interval time.Duration
|
interval time.Duration
|
||||||
connection AnalogReader
|
connection AnalogReadEventer
|
||||||
gobot.Eventer
|
gobot.Eventer
|
||||||
gobot.Commander
|
gobot.Commander
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ type AnalogSensorDriver struct {
|
|||||||
//
|
//
|
||||||
// Adds the following API Commands:
|
// Adds the following API Commands:
|
||||||
// "Read" - See AnalogSensor.Read
|
// "Read" - See AnalogSensor.Read
|
||||||
func NewAnalogSensorDriver(a AnalogReader, pin string, v ...time.Duration) *AnalogSensorDriver {
|
func NewAnalogSensorDriver(a AnalogReadEventer, pin string, v ...time.Duration) *AnalogSensorDriver {
|
||||||
d := &AnalogSensorDriver{
|
d := &AnalogSensorDriver{
|
||||||
name: "AnalogSensor",
|
name: "AnalogSensor",
|
||||||
connection: a,
|
connection: a,
|
||||||
@ -56,25 +56,18 @@ func NewAnalogSensorDriver(a AnalogReader, pin string, v ...time.Duration) *Anal
|
|||||||
// Data int - Event is emitted on change and represents the current reading from the sensor.
|
// Data int - Event is emitted on change and represents the current reading from the sensor.
|
||||||
// Error error - Event is emitted on error reading from the sensor.
|
// Error error - Event is emitted on error reading from the sensor.
|
||||||
func (a *AnalogSensorDriver) Start() (err error) {
|
func (a *AnalogSensorDriver) Start() (err error) {
|
||||||
value := 0
|
evts := a.connection.SubscribeAnalogRead(a.Pin())
|
||||||
go func() {
|
|
||||||
timer := time.NewTimer(a.interval)
|
|
||||||
timer.Stop()
|
|
||||||
for {
|
|
||||||
newValue, err := a.Read()
|
|
||||||
if err != nil {
|
|
||||||
a.Publish(a.Event(Error), err)
|
|
||||||
} else if newValue != value && newValue != -1 {
|
|
||||||
value = newValue
|
|
||||||
a.Publish(a.Event(Data), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.Reset(a.interval)
|
go func() {
|
||||||
|
analogread := "analogread-" + a.Pin()
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
|
||||||
case <-a.halt:
|
case <-a.halt:
|
||||||
timer.Stop()
|
|
||||||
return
|
return
|
||||||
|
case evt := <-evts:
|
||||||
|
if evt.Name == analogread {
|
||||||
|
a.Publish(Data, evt.Data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -73,3 +73,17 @@ type DigitalReader interface {
|
|||||||
gobot.Adaptor
|
gobot.Adaptor
|
||||||
DigitalRead(string) (val int, err error)
|
DigitalRead(string) (val int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DigitalReadEventer interface represents an Adaptor which has SubscribeDigitalRead capabilities
|
||||||
|
type DigitalReadEventer interface {
|
||||||
|
gobot.Eventer
|
||||||
|
DigitalReader
|
||||||
|
SubscribeDigitalRead(string) (gobot.EventChannel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnalogReadEventer interface represents an Adaptor which has SubscribeAnalogRead capabilities
|
||||||
|
type AnalogReadEventer interface {
|
||||||
|
gobot.Eventer
|
||||||
|
AnalogReader
|
||||||
|
SubscribeAnalogRead(string) (gobot.EventChannel)
|
||||||
|
}
|
||||||
|
@ -34,7 +34,7 @@ type GroveRotaryDriver struct {
|
|||||||
//
|
//
|
||||||
// Adds the following API Commands:
|
// Adds the following API Commands:
|
||||||
// "Read" - See AnalogSensor.Read
|
// "Read" - See AnalogSensor.Read
|
||||||
func NewGroveRotaryDriver(a AnalogReader, pin string, v ...time.Duration) *GroveRotaryDriver {
|
func NewGroveRotaryDriver(a AnalogReadEventer, pin string, v ...time.Duration) *GroveRotaryDriver {
|
||||||
return &GroveRotaryDriver{
|
return &GroveRotaryDriver{
|
||||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ type GroveLightSensorDriver struct {
|
|||||||
//
|
//
|
||||||
// Adds the following API Commands:
|
// Adds the following API Commands:
|
||||||
// "Read" - See AnalogSensor.Read
|
// "Read" - See AnalogSensor.Read
|
||||||
func NewGroveLightSensorDriver(a AnalogReader, pin string, v ...time.Duration) *GroveLightSensorDriver {
|
func NewGroveLightSensorDriver(a AnalogReadEventer, pin string, v ...time.Duration) *GroveLightSensorDriver {
|
||||||
return &GroveLightSensorDriver{
|
return &GroveLightSensorDriver{
|
||||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ type GrovePiezoVibrationSensorDriver struct {
|
|||||||
//
|
//
|
||||||
// Adds the following API Commands:
|
// Adds the following API Commands:
|
||||||
// "Read" - See AnalogSensor.Read
|
// "Read" - See AnalogSensor.Read
|
||||||
func NewGrovePiezoVibrationSensorDriver(a AnalogReader, pin string, v ...time.Duration) *GrovePiezoVibrationSensorDriver {
|
func NewGrovePiezoVibrationSensorDriver(a AnalogReadEventer, pin string, v ...time.Duration) *GrovePiezoVibrationSensorDriver {
|
||||||
sensor := &GrovePiezoVibrationSensorDriver{
|
sensor := &GrovePiezoVibrationSensorDriver{
|
||||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ type GroveSoundSensorDriver struct {
|
|||||||
//
|
//
|
||||||
// Adds the following API Commands:
|
// Adds the following API Commands:
|
||||||
// "Read" - See AnalogSensor.Read
|
// "Read" - See AnalogSensor.Read
|
||||||
func NewGroveSoundSensorDriver(a AnalogReader, pin string, v ...time.Duration) *GroveSoundSensorDriver {
|
func NewGroveSoundSensorDriver(a AnalogReadEventer, pin string, v ...time.Duration) *GroveSoundSensorDriver {
|
||||||
return &GroveSoundSensorDriver{
|
return &GroveSoundSensorDriver{
|
||||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||||
}
|
}
|
||||||
|
20
eventer.go
20
eventer.go
@ -2,17 +2,17 @@ package gobot
|
|||||||
|
|
||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
type eventChannel chan *Event
|
type EventChannel chan *Event
|
||||||
|
|
||||||
type eventer struct {
|
type eventer struct {
|
||||||
// map of valid Event names
|
// map of valid Event names
|
||||||
eventnames map[string]string
|
eventnames map[string]string
|
||||||
|
|
||||||
// new events get put in to the event channel
|
// new events get put in to the event channel
|
||||||
in eventChannel
|
in EventChannel
|
||||||
|
|
||||||
// map of out channels used by subscribers
|
// map of out channels used by subscribers
|
||||||
outs map[eventChannel]eventChannel
|
outs map[EventChannel]EventChannel
|
||||||
|
|
||||||
// mutex to protect the eventChannel map
|
// mutex to protect the eventChannel map
|
||||||
eventsMutex sync.Mutex
|
eventsMutex sync.Mutex
|
||||||
@ -38,10 +38,10 @@ type Eventer interface {
|
|||||||
Publish(name string, data interface{})
|
Publish(name string, data interface{})
|
||||||
|
|
||||||
// Subscribe to events
|
// Subscribe to events
|
||||||
Subscribe() (events eventChannel)
|
Subscribe() (events EventChannel)
|
||||||
|
|
||||||
// Unsubscribe from an event channel
|
// Unsubscribe from an event channel
|
||||||
Unsubscribe(events eventChannel)
|
Unsubscribe(events EventChannel)
|
||||||
|
|
||||||
// Event handler
|
// Event handler
|
||||||
On(name string, f func(s interface{})) (err error)
|
On(name string, f func(s interface{})) (err error)
|
||||||
@ -54,8 +54,8 @@ type Eventer interface {
|
|||||||
func NewEventer() Eventer {
|
func NewEventer() Eventer {
|
||||||
evtr := &eventer{
|
evtr := &eventer{
|
||||||
eventnames: make(map[string]string),
|
eventnames: make(map[string]string),
|
||||||
in: make(eventChannel, 1),
|
in: make(EventChannel, 1),
|
||||||
outs: make(map[eventChannel]eventChannel),
|
outs: make(map[EventChannel]EventChannel),
|
||||||
}
|
}
|
||||||
|
|
||||||
// goroutine to cascade "in" events to all "out" event channels
|
// goroutine to cascade "in" events to all "out" event channels
|
||||||
@ -103,16 +103,16 @@ func (e *eventer) Publish(name string, data interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to any events from this eventer
|
// Subscribe to any events from this eventer
|
||||||
func (e *eventer) Subscribe() eventChannel {
|
func (e *eventer) Subscribe() EventChannel {
|
||||||
e.eventsMutex.Lock()
|
e.eventsMutex.Lock()
|
||||||
defer e.eventsMutex.Unlock()
|
defer e.eventsMutex.Unlock()
|
||||||
out := make(eventChannel)
|
out := make(EventChannel)
|
||||||
e.outs[out] = out
|
e.outs[out] = out
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsubscribe from the event channel
|
// Unsubscribe from the event channel
|
||||||
func (e *eventer) Unsubscribe(events eventChannel) {
|
func (e *eventer) Unsubscribe(events EventChannel) {
|
||||||
e.eventsMutex.Lock()
|
e.eventsMutex.Lock()
|
||||||
defer e.eventsMutex.Unlock()
|
defer e.eventsMutex.Unlock()
|
||||||
delete(e.outs, events)
|
delete(e.outs, events)
|
||||||
|
33
examples/beaglebone_analog.go
Normal file
33
examples/beaglebone_analog.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gobot.io/x/gobot"
|
||||||
|
"gobot.io/x/gobot/drivers/gpio"
|
||||||
|
"gobot.io/x/gobot/platforms/beaglebone"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
a := beaglebone.NewAdaptor()
|
||||||
|
sensor := gpio.NewAnalogSensorDriver(a, "P9_39")
|
||||||
|
|
||||||
|
work := func() {
|
||||||
|
sensor.On(gpio.Data, func(data interface{}) {
|
||||||
|
voltage := (float64(data.(int)) * 1.8) / 1024 // BBB uses 1.8V
|
||||||
|
tempC := (voltage - 0.5) * 100
|
||||||
|
tempF := (tempC * 9 / 5) + 32
|
||||||
|
|
||||||
|
fmt.Printf("%.2f°C\n", tempC)
|
||||||
|
fmt.Printf("%.2f°F\n", tempF)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
robot := gobot.NewRobot("sensorBot",
|
||||||
|
[]gobot.Connection{a},
|
||||||
|
[]gobot.Device{sensor},
|
||||||
|
work,
|
||||||
|
)
|
||||||
|
|
||||||
|
robot.Start()
|
||||||
|
}
|
@ -9,10 +9,12 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
multierror "github.com/hashicorp/go-multierror"
|
||||||
"gobot.io/x/gobot"
|
"gobot.io/x/gobot"
|
||||||
"gobot.io/x/gobot/sysfs"
|
"gobot.io/x/gobot/sysfs"
|
||||||
|
"gobot.io/x/gobot/drivers/gpio"
|
||||||
)
|
)
|
||||||
|
|
||||||
var glob = func(pattern string) (matches []string, err error) {
|
var glob = func(pattern string) (matches []string, err error) {
|
||||||
@ -31,6 +33,9 @@ type Adaptor struct {
|
|||||||
analogPath string
|
analogPath string
|
||||||
analogPinMap map[string]string
|
analogPinMap map[string]string
|
||||||
slots string
|
slots string
|
||||||
|
interval time.Duration
|
||||||
|
halt chan bool
|
||||||
|
gobot.Eventer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAdaptor returns a new Beaglebone Adaptor
|
// NewAdaptor returns a new Beaglebone Adaptor
|
||||||
@ -39,6 +44,8 @@ func NewAdaptor() *Adaptor {
|
|||||||
name: "Beaglebone",
|
name: "Beaglebone",
|
||||||
digitalPins: make([]sysfs.DigitalPin, 120),
|
digitalPins: make([]sysfs.DigitalPin, 120),
|
||||||
pwmPins: make(map[string]*pwmPin),
|
pwmPins: make(map[string]*pwmPin),
|
||||||
|
interval: 10 * time.Millisecond,
|
||||||
|
halt: make(chan bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
b.setSlots()
|
b.setSlots()
|
||||||
@ -195,6 +202,68 @@ func (b *Adaptor) AnalogRead(pin string) (val int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubscribeDigitalRead starts reading from the specified pin,
|
||||||
|
// and publishes events on the returned event channel when changes occur
|
||||||
|
func (b *Adaptor) SubscribeDigitalRead(pin string) (gobot.EventChannel) {
|
||||||
|
// TODO: replace with epoll based implementation
|
||||||
|
b.AddEvent("digitalread-" + pin)
|
||||||
|
value := 0
|
||||||
|
go func() {
|
||||||
|
timer := time.NewTimer(b.interval)
|
||||||
|
timer.Stop()
|
||||||
|
for {
|
||||||
|
newValue, err := b.DigitalRead(pin)
|
||||||
|
if err != nil {
|
||||||
|
b.Publish(b.Event(gpio.Error), err)
|
||||||
|
} else if newValue != value && newValue != -1 {
|
||||||
|
value = newValue
|
||||||
|
b.Publish(b.Event("digitalread-" + pin), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Reset(b.interval)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-b.halt:
|
||||||
|
timer.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return b.Subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeAnalogRead starts reading from the specified pin,
|
||||||
|
// and publishes events on the returned event channel when changes occur
|
||||||
|
func (b *Adaptor) SubscribeAnalogRead(pin string) (gobot.EventChannel) {
|
||||||
|
// TODO: replace with epoll based implementation
|
||||||
|
b.AddEvent("analogread-" + pin)
|
||||||
|
value := 0
|
||||||
|
go func() {
|
||||||
|
timer := time.NewTimer(b.interval)
|
||||||
|
timer.Stop()
|
||||||
|
for {
|
||||||
|
newValue, err := b.AnalogRead(pin)
|
||||||
|
if err != nil {
|
||||||
|
b.Publish(b.Event(gpio.Error), err)
|
||||||
|
} else if newValue != value && newValue != -1 {
|
||||||
|
value = newValue
|
||||||
|
b.Publish(b.Event("analogread-" + pin), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Reset(b.interval)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
case <-b.halt:
|
||||||
|
timer.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return b.Subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
// I2cStart starts a i2c device in specified address on i2c bus /dev/i2c-1
|
// I2cStart starts a i2c device in specified address on i2c bus /dev/i2c-1
|
||||||
func (b *Adaptor) I2cStart(address int) (err error) {
|
func (b *Adaptor) I2cStart(address int) (err error) {
|
||||||
if b.i2cDevice == nil {
|
if b.i2cDevice == nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user