Merge branch 'dev' into refactor_device_connection

This commit is contained in:
Adrian Zankich 2014-07-07 22:04:02 -07:00
commit 97a1dc67cc
16 changed files with 267 additions and 50 deletions

View File

@ -12,3 +12,18 @@ cover:
cat tmp.cov | grep -v "mode: count" >> profile.cov ; \ cat tmp.cov | grep -v "mode: count" >> profile.cov ; \
done ; \ done ; \
rm tmp.cov ; \ rm tmp.cov ; \
robeaux:
ifeq (,$(shell which go-bindata))
$(error robeaux not built! https://github.com/jteeuwen/go-bindata is required to build robeaux assets )
endif
cd api ; \
git clone --depth 1 git://github.com/hybridgroup/robeaux.git ; \
cd robeaux ; \
echo "Updating robeaux to $(shell git rev-parse HEAD)" ; \
go-bindata -pkg="api" -o robeaux.go -ignore=\\.git ./... ; \
mv robeaux.go .. ; \
cd .. ; \
rm -rf robeaux/ ; \
go fmt ./robeaux.go ; \

View File

@ -135,7 +135,7 @@ You can also specify the api host and port, and turn on authentication:
server.Start() server.Start()
``` ```
In order to use the [robeaux](https://github.com/hybridgroup/robeaux) AngularJS interface with Gobot you simply clone the robeaux repo and place it in the directory of your Gobot program. The robeaux assets must be in a folder called `robeaux`. In order to use the [robeaux](https://github.com/hybridgroup/robeaux) AngularJS interface with Gobot you must have [go-bindata](https://github.com/jteeuwen/go-bindata) installed and then run `$ make robeaux`. You may now access robeaux by navigating to `http://localhost:3000/index.html`.
## Documentation ## Documentation
We're busy adding documentation to our web site at http://gobot.io/ please check there as we continue to work on Gobot We're busy adding documentation to our web site at http://gobot.io/ please check there as we continue to work on Gobot

View File

@ -9,6 +9,7 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"strings"
) )
// Optional restful API through Gobot has access // Optional restful API through Gobot has access
@ -45,6 +46,7 @@ func NewAPI(g *gobot.Gobot) *api {
log.Println("Initializing API on " + host + ":" + port + "...") log.Println("Initializing API on " + host + ":" + port + "...")
http.Handle("/", a.server) http.Handle("/", a.server)
go func() { go func() {
if cert != "" && key != "" { if cert != "" && key != "" {
http.ListenAndServeTLS(host+":"+port, cert, key, nil) http.ListenAndServeTLS(host+":"+port, cert, key, nil)
@ -82,6 +84,12 @@ func (a *api) Start() {
a.server.Post(deviceCommandRoute, a.setHeaders(a.executeDeviceCommand)) a.server.Post(deviceCommandRoute, a.setHeaders(a.executeDeviceCommand))
a.server.Get("/robots/:robot/connections", a.setHeaders(a.robotConnections)) a.server.Get("/robots/:robot/connections", a.setHeaders(a.robotConnections))
a.server.Get("/robots/:robot/connections/:connection", a.setHeaders(a.robotConnection)) a.server.Get("/robots/:robot/connections/:connection", a.setHeaders(a.robotConnection))
a.server.Get("/:a", a.setHeaders(a.robeaux))
a.server.Get("/:a/", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b/", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b/:c", a.setHeaders(a.robeaux))
a.server.Get("/:a/:b/:c/", a.setHeaders(a.robeaux))
a.start(a) a.start(a)
} }
@ -118,6 +126,23 @@ func (a *api) setHeaders(f func(http.ResponseWriter, *http.Request)) http.Handle
} }
} }
func (a *api) robeaux(res http.ResponseWriter, req *http.Request) {
path := req.URL.Path
buf, err := Asset(path[1:])
if err != nil {
log.Println("Error serving static file:", err.Error())
res.Write([]byte(err.Error()))
return
}
t := strings.Split(path, ".")
if t[len(t)-1] == "js" {
res.Header().Set("Content-Type", "text/javascript; charset=utf-8")
} else if t[len(t)-1] == "css" {
res.Header().Set("Content-Type", "text/css; charset=utf-8")
}
res.Write(buf)
}
func (a *api) root(res http.ResponseWriter, req *http.Request) { func (a *api) root(res http.ResponseWriter, req *http.Request) {
data, _ := json.Marshal(a.gobot.ToJSON()) data, _ := json.Marshal(a.gobot.ToJSON())
res.Header().Set("Content-Type", "application/json; charset=utf-8") res.Header().Set("Content-Type", "application/json; charset=utf-8")

9
api/robeaux.go Normal file
View File

@ -0,0 +1,9 @@
package api
import (
"fmt"
)
func Asset(name string) ([]byte, error) {
return nil, fmt.Errorf("Please run '$ make robeaux' for robeaux support")
}

View File

@ -0,0 +1,29 @@
package main
import (
"fmt"
"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/beaglebone"
"github.com/hybridgroup/gobot/platforms/gpio"
)
func main() {
gbot := gobot.NewGobot()
beagleboneAdaptor := beaglebone.NewBeagleboneAdaptor("beaglebone")
button := gpio.NewButtonDriver(beagleboneAdaptor, "button", "P8_9")
work := func() {
gobot.On(button.Events["push"], func(data interface{}) {
fmt.Println("button pressed")
})
gobot.On(button.Events["release"], func(data interface{}) {
fmt.Println("button released")
})
}
gbot.Robots = append(gbot.Robots,
gobot.NewRobot("buttonBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{button}, work))
gbot.Start()
}

View File

@ -0,0 +1,30 @@
package main
import (
"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/beaglebone"
"github.com/hybridgroup/gobot/platforms/gpio"
"time"
)
func main() {
gbot := gobot.NewGobot()
beagleboneAdaptor := beaglebone.NewBeagleboneAdaptor("beaglebone")
led := gpio.NewDirectPinDriver(beagleboneAdaptor, "led", "P8_10")
button := gpio.NewDirectPinDriver(beagleboneAdaptor, "button", "P8_9")
work := func() {
gobot.Every(500*time.Millisecond, func() {
if button.DigitalRead() == 1 {
led.DigitalWrite(1)
} else {
led.DigitalWrite(0)
}
})
}
gbot.Robots = append(gbot.Robots,
gobot.NewRobot("pinBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{led}, work))
gbot.Start()
}

View File

@ -0,0 +1,29 @@
package main
import (
"fmt"
"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/beaglebone"
"github.com/hybridgroup/gobot/platforms/gpio"
)
func main() {
gbot := gobot.NewGobot()
beagleboneAdaptor := beaglebone.NewBeagleboneAdaptor("beaglebone")
button := gpio.NewMakeyButtonDriver(beagleboneAdaptor, "button", "P8_9")
work := func() {
gobot.On(button.Events["push"], func(data interface{}) {
fmt.Println("button pressed")
})
gobot.On(button.Events["release"], func(data interface{}) {
fmt.Println("button released")
})
}
gbot.Robots = append(gbot.Robots,
gobot.NewRobot("makeyBot", []gobot.Connection{beagleboneAdaptor}, []gobot.Device{button}, work))
gbot.Start()
}

View File

@ -5,7 +5,6 @@ import (
"github.com/hybridgroup/gobot" "github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/firmata" "github.com/hybridgroup/gobot/platforms/firmata"
"github.com/hybridgroup/gobot/platforms/gpio" "github.com/hybridgroup/gobot/platforms/gpio"
"time"
) )
func main() { func main() {
@ -15,10 +14,9 @@ func main() {
led := gpio.NewLedDriver(firmataAdaptor, "led", "3") led := gpio.NewLedDriver(firmataAdaptor, "led", "3")
work := func() { work := func() {
gobot.Every(100*time.Millisecond, func() { gobot.On(sensor.Events["data"], func(data interface{}) {
val := sensor.Read() brightness := uint8(gobot.ToScale(gobot.FromScale(float64(data.(int)), 0, 1024), 0, 255))
brightness := uint8(gobot.ToScale(gobot.FromScale(float64(val), 0, 1024), 0, 255)) fmt.Println("sensor", data)
fmt.Println("sensor", val)
fmt.Println("brightness", brightness) fmt.Println("brightness", brightness)
led.Brightness(brightness) led.Brightness(brightness)
}) })

View File

@ -13,22 +13,9 @@ type analogPin struct {
} }
func newAnalogPin(pinNum string) *analogPin { func newAnalogPin(pinNum string) *analogPin {
var err error
var fi *os.File
d := new(analogPin) d := new(analogPin)
d.pinNum = pinNum d.pinNum = pinNum
slot, err := filepath.Glob(Slots)
if err != nil {
panic(err)
}
fi, err = os.OpenFile(fmt.Sprintf("%v/slots", slot[0]), os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
fi.WriteString("cape-bone-iio")
fi.Close()
return d return d
} }

View File

@ -1,8 +1,13 @@
package beaglebone package beaglebone
import ( import (
"bufio"
"fmt"
"github.com/hybridgroup/gobot" "github.com/hybridgroup/gobot"
"os"
"path/filepath"
"strconv" "strconv"
"strings"
) )
const Slots = "/sys/devices/bone_capemgr.*" const Slots = "/sys/devices/bone_capemgr.*"
@ -103,6 +108,7 @@ type BeagleboneAdaptor struct {
pwmPins map[string]*pwmPin pwmPins map[string]*pwmPin
analogPins map[string]*analogPin analogPins map[string]*analogPin
i2cDevice *i2cDevice i2cDevice *i2cDevice
connect func()
} }
func NewBeagleboneAdaptor(name string) *BeagleboneAdaptor { func NewBeagleboneAdaptor(name string) *BeagleboneAdaptor {
@ -111,6 +117,10 @@ func NewBeagleboneAdaptor(name string) *BeagleboneAdaptor {
name, name,
"BeagleboneAdaptor", "BeagleboneAdaptor",
), ),
connect: func() {
ensureSlot("cape-bone-iio")
ensureSlot("am33xx_pwm")
},
} }
} }
@ -118,6 +128,7 @@ func (b *BeagleboneAdaptor) Connect() bool {
b.digitalPins = make([]*digitalPin, 120) b.digitalPins = make([]*digitalPin, 120)
b.pwmPins = make(map[string]*pwmPin) b.pwmPins = make(map[string]*pwmPin)
b.analogPins = make(map[string]*analogPin) b.analogPins = make(map[string]*analogPin)
b.connect()
return true return true
} }
@ -141,10 +152,7 @@ func (b *BeagleboneAdaptor) Reconnect() bool { return true }
func (b *BeagleboneAdaptor) Disconnect() bool { return true } func (b *BeagleboneAdaptor) Disconnect() bool { return true }
func (b *BeagleboneAdaptor) PwmWrite(pin string, val byte) { func (b *BeagleboneAdaptor) PwmWrite(pin string, val byte) {
i := b.pwmPin(pin) b.pwmWrite(pin, val)
period := 500000.0
duty := gobot.FromScale(float64(^val), 0, 255.0)
b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty)))
} }
func (b *BeagleboneAdaptor) InitServo() {} func (b *BeagleboneAdaptor) InitServo() {}
@ -155,6 +163,11 @@ func (b *BeagleboneAdaptor) ServoWrite(pin string, val byte) {
b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty))) b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty)))
} }
func (b *BeagleboneAdaptor) DigitalRead(pin string) int {
i := b.digitalPin(pin, "r")
return b.digitalPins[i].digitalRead()
}
func (b *BeagleboneAdaptor) DigitalWrite(pin string, val byte) { func (b *BeagleboneAdaptor) DigitalWrite(pin string, val byte) {
i := b.digitalPin(pin, "w") i := b.digitalPin(pin, "w")
b.digitalPins[i].digitalWrite(strconv.Itoa(int(val))) b.digitalPins[i].digitalWrite(strconv.Itoa(int(val)))
@ -165,6 +178,10 @@ func (b *BeagleboneAdaptor) AnalogRead(pin string) int {
return b.analogPins[i].analogRead() return b.analogPins[i].analogRead()
} }
func (b *BeagleboneAdaptor) AnalogWrite(pin string, val byte) {
b.pwmWrite(pin, val)
}
func (b *BeagleboneAdaptor) I2cStart(address byte) { func (b *BeagleboneAdaptor) I2cStart(address byte) {
b.i2cDevice = newI2cDevice(I2CLocation, address) b.i2cDevice = newI2cDevice(I2CLocation, address)
b.i2cDevice.start() b.i2cDevice.start()
@ -228,3 +245,45 @@ func (b *BeagleboneAdaptor) pwmPin(pin string) string {
} }
return i return i
} }
func (b *BeagleboneAdaptor) pwmWrite(pin string, val byte) {
i := b.pwmPin(pin)
period := 500000.0
duty := gobot.FromScale(float64(^val), 0, 255.0)
b.pwmPins[i].pwmWrite(strconv.Itoa(int(period)), strconv.Itoa(int(period*duty)))
}
func ensureSlot(item string) {
var err error
var fi *os.File
slot, err := filepath.Glob(Slots)
if err != nil {
panic(err)
}
fi, err = os.OpenFile(fmt.Sprintf("%v/slots", slot[0]), os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer fi.Close()
//ensure the slot is not already written into the capemanager (from: https://github.com/mrmorphic/hwio/blob/master/module_bb_pwm.go#L190)
scanner := bufio.NewScanner(fi)
for scanner.Scan() {
line := scanner.Text()
if strings.Index(line, item) > 0 {
return
}
}
fi.WriteString(item)
fi.Sync()
scanner = bufio.NewScanner(fi)
for scanner.Scan() {
line := scanner.Text()
if strings.Index(line, item) > 0 {
return
}
}
}

View File

@ -6,7 +6,9 @@ import (
) )
func initTestBeagleboneAdaptor() *BeagleboneAdaptor { func initTestBeagleboneAdaptor() *BeagleboneAdaptor {
return NewBeagleboneAdaptor("bot") b := NewBeagleboneAdaptor("bot")
b.connect = func() {}
return b
} }
func TestBeagleboneAdaptorFinalize(t *testing.T) { func TestBeagleboneAdaptorFinalize(t *testing.T) {

View File

@ -26,8 +26,9 @@ func newDigitalPin(pinNum int, mode string) *digitalPin {
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer fi.Close()
fi.WriteString(d.PinNum) fi.WriteString(d.PinNum)
fi.Close()
d.setMode(mode) d.setMode(mode)
@ -71,6 +72,18 @@ func (d *digitalPin) digitalWrite(value string) {
d.PinFile.Sync() d.PinFile.Sync()
} }
func (d *digitalPin) digitalRead() int {
if d.Mode != "r" {
d.setMode("r")
}
var buf []byte = make([]byte, 1)
d.PinFile.ReadAt(buf, 0)
i, _ := strconv.Atoi(string(buf[0]))
return i
}
func (d *digitalPin) close() { func (d *digitalPin) close() {
fi, err := os.OpenFile(GPIOPath+"/unexport", os.O_WRONLY|os.O_APPEND, 0666) fi, err := os.OpenFile(GPIOPath+"/unexport", os.O_WRONLY|os.O_APPEND, 0666)
if err != nil { if err != nil {

View File

@ -5,7 +5,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
) )
type pwmPin struct { type pwmPin struct {
@ -17,21 +16,11 @@ func newPwmPin(pinNum string) *pwmPin {
var err error var err error
var fi *os.File var fi *os.File
d := new(pwmPin) d := &pwmPin{
d.pinNum = strings.ToUpper(pinNum) pinNum: strings.ToUpper(pinNum),
slots, err := filepath.Glob(Slots)
if err != nil {
panic(err)
} }
fi, err = os.OpenFile(fmt.Sprintf("%v/slots", slots[0]), os.O_WRONLY|os.O_APPEND, 0666)
if err != nil { ensureSlot(fmt.Sprintf("bone_pwm_%v", d.pinNum))
panic(err)
}
fi.WriteString("am33xx_pwm")
fi.Sync()
fi.WriteString(fmt.Sprintf("bone_pwm_%v", d.pinNum))
fi.Sync()
fi.Close()
ocp, err := filepath.Glob(Ocp) ocp, err := filepath.Glob(Ocp)
if err != nil { if err != nil {
@ -42,18 +31,32 @@ func newPwmPin(pinNum string) *pwmPin {
if err != nil { if err != nil {
panic(err) panic(err)
} }
d.pwmDevice = pwmDevice[0] d.pwmDevice = pwmDevice[0]
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
fi, err = os.OpenFile(fmt.Sprintf("%v/run", d.pwmDevice), os.O_WRONLY|os.O_APPEND, 0666) fi, err = os.OpenFile(fmt.Sprintf("%v/run", d.pwmDevice), os.O_RDWR|os.O_APPEND, 0666)
if err != nil && i == 9 { if err != nil && i == 9 {
panic(err) panic(err)
} else {
break
} }
time.Sleep(10 * time.Millisecond)
} }
fi.WriteString("1") fi.WriteString("1")
fi.Sync()
fi.Close() fi.Close()
for {
if _, err := os.Stat(fmt.Sprintf("%v/period", d.pwmDevice)); err == nil {
break
}
}
for {
if _, err := os.Stat(fmt.Sprintf("%v/duty", d.pwmDevice)); err == nil {
break
}
}
return d return d
} }

View File

@ -249,12 +249,12 @@ func (b *board) process(data []byte) {
if err != nil { if err != nil {
break break
} }
switch messageType { switch {
case ReportVersion: case ReportVersion == messageType:
b.MajorVersion, _ = buf.ReadByte() b.MajorVersion, _ = buf.ReadByte()
b.MinorVersion, _ = buf.ReadByte() b.MinorVersion, _ = buf.ReadByte()
b.Events = append(b.Events, event{Name: "report_version"}) b.Events = append(b.Events, event{Name: "report_version"})
case AnalogMessage: case AnalogMessageRangeStart <= messageType && AnalogMessageRangeEnd >= messageType:
leastSignificantByte, _ := buf.ReadByte() leastSignificantByte, _ := buf.ReadByte()
mostSignificantByte, _ := buf.ReadByte() mostSignificantByte, _ := buf.ReadByte()
@ -264,7 +264,7 @@ func (b *board) process(data []byte) {
b.Pins[b.AnalogPins[pin]].Value = int(value) b.Pins[b.AnalogPins[pin]].Value = int(value)
b.Events = append(b.Events, event{Name: fmt.Sprintf("analog_read_%v", pin), Data: []byte{byte(value >> 24), byte(value >> 16), byte(value >> 8), byte(value & 0xff)}}) b.Events = append(b.Events, event{Name: fmt.Sprintf("analog_read_%v", pin), Data: []byte{byte(value >> 24), byte(value >> 16), byte(value >> 8), byte(value & 0xff)}})
case DigitalMessage: case DigitalMessageRangeStart <= messageType && DigitalMessageRangeEnd >= messageType:
port := messageType & 0x0F port := messageType & 0x0F
firstBitmask, _ := buf.ReadByte() firstBitmask, _ := buf.ReadByte()
secondBitmask, _ := buf.ReadByte() secondBitmask, _ := buf.ReadByte()
@ -279,7 +279,7 @@ func (b *board) process(data []byte) {
} }
} }
case StartSysex: case StartSysex == messageType:
currentBuffer := []byte{messageType} currentBuffer := []byte{messageType}
for { for {
b, err := buf.ReadByte() b, err := buf.ReadByte()

View File

@ -18,6 +18,7 @@ func NewAnalogSensorDriver(a AnalogReader, name string, pin string) *AnalogSenso
), ),
} }
d.AddEvent("data")
d.Driver.AddCommand("Read", func(params map[string]interface{}) interface{} { d.Driver.AddCommand("Read", func(params map[string]interface{}) interface{} {
return d.Read() return d.Read()
}) })
@ -29,9 +30,19 @@ func (a *AnalogSensorDriver) adaptor() AnalogReader {
return a.Driver.Adaptor().(AnalogReader) return a.Driver.Adaptor().(AnalogReader)
} }
func (a *AnalogSensorDriver) Start() bool { return true } func (a *AnalogSensorDriver) Start() bool {
func (a *AnalogSensorDriver) Init() bool { return true } value := 0
func (a *AnalogSensorDriver) Halt() bool { return true } gobot.Every(a.Interval(), func() {
newValue := a.Read()
if newValue != value && newValue != -1 {
value = newValue
gobot.Publish(a.Event("data"), value)
}
})
return true
}
func (a *AnalogSensorDriver) Init() bool { return true }
func (a *AnalogSensorDriver) Halt() bool { return true }
func (a *AnalogSensorDriver) Read() int { func (a *AnalogSensorDriver) Read() int {
return a.adaptor().AnalogRead(a.Pin()) return a.adaptor().AnalogRead(a.Pin())

7
version.go Normal file
View File

@ -0,0 +1,7 @@
package gobot
const version = "0.5.1"
func Version() string {
return version
}