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
|
||||
halt chan bool
|
||||
interval time.Duration
|
||||
connection AnalogReader
|
||||
connection AnalogReadEventer
|
||||
gobot.Eventer
|
||||
gobot.Commander
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ type AnalogSensorDriver struct {
|
|||
//
|
||||
// Adds the following API Commands:
|
||||
// "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{
|
||||
name: "AnalogSensor",
|
||||
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.
|
||||
// Error error - Event is emitted on error reading from the sensor.
|
||||
func (a *AnalogSensorDriver) Start() (err error) {
|
||||
value := 0
|
||||
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)
|
||||
}
|
||||
evts := a.connection.SubscribeAnalogRead(a.Pin())
|
||||
|
||||
timer.Reset(a.interval)
|
||||
go func() {
|
||||
analogread := "analogread-" + a.Pin()
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
case <-a.halt:
|
||||
timer.Stop()
|
||||
return
|
||||
case evt := <-evts:
|
||||
if evt.Name == analogread {
|
||||
a.Publish(Data, evt.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -73,3 +73,17 @@ type DigitalReader interface {
|
|||
gobot.Adaptor
|
||||
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:
|
||||
// "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{
|
||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ type GroveLightSensorDriver struct {
|
|||
//
|
||||
// Adds the following API Commands:
|
||||
// "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{
|
||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ type GrovePiezoVibrationSensorDriver struct {
|
|||
//
|
||||
// Adds the following API Commands:
|
||||
// "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{
|
||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ type GroveSoundSensorDriver struct {
|
|||
//
|
||||
// Adds the following API Commands:
|
||||
// "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{
|
||||
AnalogSensorDriver: NewAnalogSensorDriver(a, pin, v...),
|
||||
}
|
||||
|
|
20
eventer.go
20
eventer.go
|
@ -2,17 +2,17 @@ package gobot
|
|||
|
||||
import "sync"
|
||||
|
||||
type eventChannel chan *Event
|
||||
type EventChannel chan *Event
|
||||
|
||||
type eventer struct {
|
||||
// map of valid Event names
|
||||
eventnames map[string]string
|
||||
|
||||
// new events get put in to the event channel
|
||||
in eventChannel
|
||||
in EventChannel
|
||||
|
||||
// map of out channels used by subscribers
|
||||
outs map[eventChannel]eventChannel
|
||||
outs map[EventChannel]EventChannel
|
||||
|
||||
// mutex to protect the eventChannel map
|
||||
eventsMutex sync.Mutex
|
||||
|
@ -38,10 +38,10 @@ type Eventer interface {
|
|||
Publish(name string, data interface{})
|
||||
|
||||
// Subscribe to events
|
||||
Subscribe() (events eventChannel)
|
||||
Subscribe() (events EventChannel)
|
||||
|
||||
// Unsubscribe from an event channel
|
||||
Unsubscribe(events eventChannel)
|
||||
Unsubscribe(events EventChannel)
|
||||
|
||||
// Event handler
|
||||
On(name string, f func(s interface{})) (err error)
|
||||
|
@ -54,8 +54,8 @@ type Eventer interface {
|
|||
func NewEventer() Eventer {
|
||||
evtr := &eventer{
|
||||
eventnames: make(map[string]string),
|
||||
in: make(eventChannel, 1),
|
||||
outs: make(map[eventChannel]eventChannel),
|
||||
in: make(EventChannel, 1),
|
||||
outs: make(map[EventChannel]EventChannel),
|
||||
}
|
||||
|
||||
// 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
|
||||
func (e *eventer) Subscribe() eventChannel {
|
||||
func (e *eventer) Subscribe() EventChannel {
|
||||
e.eventsMutex.Lock()
|
||||
defer e.eventsMutex.Unlock()
|
||||
out := make(eventChannel)
|
||||
out := make(EventChannel)
|
||||
e.outs[out] = out
|
||||
return out
|
||||
}
|
||||
|
||||
// Unsubscribe from the event channel
|
||||
func (e *eventer) Unsubscribe(events eventChannel) {
|
||||
func (e *eventer) Unsubscribe(events EventChannel) {
|
||||
e.eventsMutex.Lock()
|
||||
defer e.eventsMutex.Unlock()
|
||||
delete(e.outs, events)
|
||||
|
|
|
@ -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"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"gobot.io/x/gobot"
|
||||
"gobot.io/x/gobot/sysfs"
|
||||
"gobot.io/x/gobot/drivers/gpio"
|
||||
)
|
||||
|
||||
var glob = func(pattern string) (matches []string, err error) {
|
||||
|
@ -31,6 +33,9 @@ type Adaptor struct {
|
|||
analogPath string
|
||||
analogPinMap map[string]string
|
||||
slots string
|
||||
interval time.Duration
|
||||
halt chan bool
|
||||
gobot.Eventer
|
||||
}
|
||||
|
||||
// NewAdaptor returns a new Beaglebone Adaptor
|
||||
|
@ -39,6 +44,8 @@ func NewAdaptor() *Adaptor {
|
|||
name: "Beaglebone",
|
||||
digitalPins: make([]sysfs.DigitalPin, 120),
|
||||
pwmPins: make(map[string]*pwmPin),
|
||||
interval: 10 * time.Millisecond,
|
||||
halt: make(chan bool),
|
||||
}
|
||||
|
||||
b.setSlots()
|
||||
|
@ -195,6 +202,68 @@ func (b *Adaptor) AnalogRead(pin string) (val int, err error) {
|
|||
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
|
||||
func (b *Adaptor) I2cStart(address int) (err error) {
|
||||
if b.i2cDevice == nil {
|
||||
|
|
Loading…
Reference in New Issue