mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-05-11 19:29:20 +08:00
Merge branch 'dev' into nats
This commit is contained in:
commit
fa0b82d84c
@ -56,7 +56,7 @@ func TestAnalogSensorDriverStart(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(10 * time.Second):
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Errorf("AnalogSensor Event \"Data\" was not published")
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ func TestAnalogSensorDriverStart(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(10 * time.Second):
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Errorf("AnalogSensor Event \"Error\" was not published")
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ func TestAnalogSensorDriverStart(t *testing.T) {
|
||||
select {
|
||||
case <-sem:
|
||||
t.Errorf("AnalogSensor Event should not published")
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
case <-time.After(1 * time.Second):
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ func TestAnalogSensorDriverHalt(t *testing.T) {
|
||||
gobottest.Assert(t, d.Halt(), nil)
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Millisecond):
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Errorf("AnalogSensor was not halted")
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func TestGroveTempSensorPublishesTemperatureInCelsius(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(10 * time.Second):
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Errorf("Grove Temperature Sensor Event \"Data\" was not published")
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ func TestGroveTempSensorPublishesError(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(time.Second):
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Errorf("Grove Temperature Sensor Event \"Error\" was not published")
|
||||
}
|
||||
}
|
||||
@ -81,7 +81,7 @@ func TestGroveTempSensorHalt(t *testing.T) {
|
||||
gobottest.Assert(t, d.Halt(), nil)
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Millisecond):
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Errorf("Grove Temperature Sensor was not halted")
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
var _ gobot.Driver = (*ButtonDriver)(nil)
|
||||
|
||||
const BUTTON_TEST_DELAY = 150
|
||||
const buttonTestDelay = 250
|
||||
|
||||
func initTestButtonDriver() *ButtonDriver {
|
||||
return NewButtonDriver(newGpioTestAdaptor(), "1")
|
||||
@ -52,7 +52,7 @@ func TestButtonDriverStart(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(buttonTestDelay * time.Millisecond):
|
||||
t.Errorf("Button Event \"Push\" was not published")
|
||||
}
|
||||
|
||||
@ -68,40 +68,40 @@ func TestButtonDriverStart(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
|
||||
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
|
||||
})
|
||||
|
||||
d.Once(Error, func(data interface{}) {
|
||||
sem <- true
|
||||
})
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(buttonTestDelay * time.Millisecond):
|
||||
t.Errorf("Button Event \"Error\" was not published")
|
||||
}
|
||||
|
||||
d.Once(ButtonPush, func(data interface{}) {
|
||||
sem <- true
|
||||
})
|
||||
|
||||
a.TestAdaptorDigitalRead(func() (val int, err error) {
|
||||
val = 1
|
||||
return
|
||||
})
|
||||
|
||||
d.Once(ButtonPush, func(data interface{}) {
|
||||
sem <- true
|
||||
})
|
||||
|
||||
d.halt <- true
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
t.Errorf("Button Event \"Press\" should not published")
|
||||
case <-time.After(BUTTON_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(buttonTestDelay * time.Millisecond):
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,9 +71,6 @@ func TestLedDriverToggle(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLedDriverBrightness(t *testing.T) {
|
||||
// d := initTestLedDriver(&gpioTestDigitalWriter{})
|
||||
// gobottest.Assert(t, d.Brightness(150), ErrPwmWriteUnsupported)
|
||||
|
||||
a := newGpioTestAdaptor()
|
||||
d := NewLedDriver(a, "1")
|
||||
a.testAdaptorPwmWrite = func() (err error) {
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
var _ gobot.Driver = (*MakeyButtonDriver)(nil)
|
||||
|
||||
const MAKEY_TEST_DELAY = 30
|
||||
const makeyTestDelay = 250
|
||||
|
||||
func initTestMakeyButtonDriver() *MakeyButtonDriver {
|
||||
return NewMakeyButtonDriver(newGpioTestAdaptor(), "1")
|
||||
@ -27,7 +27,7 @@ func TestMakeyButtonDriverHalt(t *testing.T) {
|
||||
gobottest.Assert(t, d.Halt(), nil)
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(time.Millisecond):
|
||||
case <-time.After(makeyTestDelay * time.Millisecond):
|
||||
t.Errorf("MakeyButton was not halted")
|
||||
}
|
||||
}
|
||||
@ -39,7 +39,7 @@ func TestMakeyButtonDriver(t *testing.T) {
|
||||
gobottest.Assert(t, d.interval, 10*time.Millisecond)
|
||||
|
||||
d = NewMakeyButtonDriver(newGpioTestAdaptor(), "1", 30*time.Second)
|
||||
gobottest.Assert(t, d.interval, MAKEY_TEST_DELAY*time.Second)
|
||||
gobottest.Assert(t, d.interval, 30*time.Second)
|
||||
}
|
||||
|
||||
func TestMakeyButtonDriverStart(t *testing.T) {
|
||||
@ -49,51 +49,51 @@ func TestMakeyButtonDriverStart(t *testing.T) {
|
||||
|
||||
gobottest.Assert(t, d.Start(), nil)
|
||||
|
||||
a.TestAdaptorDigitalRead(func() (val int, err error) {
|
||||
val = 0
|
||||
return
|
||||
})
|
||||
|
||||
d.Once(ButtonPush, func(data interface{}) {
|
||||
gobottest.Assert(t, d.Active, true)
|
||||
sem <- true
|
||||
})
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(MAKEY_TEST_DELAY * time.Millisecond):
|
||||
t.Errorf("MakeyButton Event \"Push\" was not published")
|
||||
}
|
||||
|
||||
a.TestAdaptorDigitalRead(func() (val int, err error) {
|
||||
val = 1
|
||||
val = 0
|
||||
return
|
||||
})
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(makeyTestDelay * time.Millisecond):
|
||||
t.Errorf("MakeyButton Event \"Push\" was not published")
|
||||
}
|
||||
|
||||
d.Once(ButtonRelease, func(data interface{}) {
|
||||
gobottest.Assert(t, d.Active, false)
|
||||
sem <- true
|
||||
})
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(MAKEY_TEST_DELAY * time.Millisecond):
|
||||
t.Errorf("MakeyButton Event \"Release\" was not published")
|
||||
}
|
||||
|
||||
a.TestAdaptorDigitalRead(func() (val int, err error) {
|
||||
err = errors.New("digital read error")
|
||||
val = 1
|
||||
return
|
||||
})
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(makeyTestDelay * time.Millisecond):
|
||||
t.Errorf("MakeyButton Event \"Release\" was not published")
|
||||
}
|
||||
|
||||
d.Once(Error, func(data interface{}) {
|
||||
gobottest.Assert(t, data.(error).Error(), "digital read error")
|
||||
sem <- true
|
||||
})
|
||||
|
||||
a.TestAdaptorDigitalRead(func() (val int, err error) {
|
||||
err = errors.New("digital read error")
|
||||
return
|
||||
})
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(MAKEY_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(makeyTestDelay * time.Millisecond):
|
||||
t.Errorf("MakeyButton Event \"Error\" was not published")
|
||||
}
|
||||
|
||||
@ -112,6 +112,6 @@ func TestMakeyButtonDriverStart(t *testing.T) {
|
||||
select {
|
||||
case <-sem:
|
||||
t.Errorf("MakeyButton Event should not have been published")
|
||||
case <-time.After(MAKEY_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(makeyTestDelay * time.Millisecond):
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
var _ gobot.Driver = (*PIRMotionDriver)(nil)
|
||||
|
||||
const MOTION_TEST_DELAY = 150
|
||||
const motionTestDelay = 150
|
||||
|
||||
func initTestPIRMotionDriver() *PIRMotionDriver {
|
||||
return NewPIRMotionDriver(newGpioTestAdaptor(), "1")
|
||||
@ -53,7 +53,7 @@ func TestPIRMotionDriverStart(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(MOTION_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(motionTestDelay * time.Millisecond):
|
||||
t.Errorf("PIRMotionDriver Event \"MotionDetected\" was not published")
|
||||
}
|
||||
|
||||
@ -69,22 +69,22 @@ func TestPIRMotionDriverStart(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(MOTION_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(motionTestDelay * time.Millisecond):
|
||||
t.Errorf("PIRMotionDriver Event \"MotionStopped\" 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
|
||||
})
|
||||
|
||||
d.Once(Error, func(data interface{}) {
|
||||
sem <- true
|
||||
})
|
||||
|
||||
select {
|
||||
case <-sem:
|
||||
case <-time.After(MOTION_TEST_DELAY * time.Millisecond):
|
||||
case <-time.After(motionTestDelay * time.Millisecond):
|
||||
t.Errorf("PIRMotionDriver Event \"Error\" was not published")
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,10 @@ func main() {
|
||||
led := gpio.NewLedDriver(firmataAdaptor, "13")
|
||||
|
||||
work := func() {
|
||||
mqttAdaptor.On("lights/on", func(data []byte) {
|
||||
mqttAdaptor.On("lights/on", func(msg mqtt.Message) {
|
||||
led.On()
|
||||
})
|
||||
mqttAdaptor.On("lights/off", func(data []byte) {
|
||||
mqttAdaptor.On("lights/off", func(msg mqtt.Message) {
|
||||
led.Off()
|
||||
})
|
||||
data := []byte("")
|
||||
|
@ -16,10 +16,10 @@ func main() {
|
||||
mqttAdaptor := mqtt.NewAdaptor("tcp://test.mosquitto.org:1883", "pinger")
|
||||
|
||||
work := func() {
|
||||
mqttAdaptor.On("hello", func(data []byte) {
|
||||
mqttAdaptor.On("hello", func(msg mqtt.Message) {
|
||||
fmt.Println("hello")
|
||||
})
|
||||
mqttAdaptor.On("hola", func(data []byte) {
|
||||
mqttAdaptor.On("hola", func(msg mqtt.Message) {
|
||||
fmt.Println("hola")
|
||||
})
|
||||
data := []byte("o")
|
||||
|
@ -31,8 +31,8 @@ func main() {
|
||||
work := func() {
|
||||
ollie.SetRGB(255, 0, 255)
|
||||
|
||||
mqttAdaptor.On("sensores/dial", func(data []byte) {
|
||||
val, _ := strconv.Atoi(string(data))
|
||||
mqttAdaptor.On("sensores/dial", func(msg mqtt.Message) {
|
||||
val, _ := strconv.Atoi(string(msg.Payload()))
|
||||
|
||||
if val > 2000 {
|
||||
ollie.SetRGB(0, 255, 0)
|
||||
@ -45,28 +45,28 @@ func main() {
|
||||
ollie.SetRGB(255, 0, 0)
|
||||
})
|
||||
|
||||
mqttAdaptor.On("rover/frente", func(data []byte) {
|
||||
mqttAdaptor.On("rover/frente", func(msg mqtt.Message) {
|
||||
ollie.Roll(40, FRENTE)
|
||||
gobot.After(1*time.Second, func() {
|
||||
ollie.Stop()
|
||||
})
|
||||
})
|
||||
|
||||
mqttAdaptor.On("rover/derecha", func(data []byte) {
|
||||
mqttAdaptor.On("rover/derecha", func(msg mqtt.Message) {
|
||||
ollie.Roll(40, DERECHA)
|
||||
gobot.After(1*time.Second, func() {
|
||||
ollie.Stop()
|
||||
})
|
||||
})
|
||||
|
||||
mqttAdaptor.On("rover/atras", func(data []byte) {
|
||||
mqttAdaptor.On("rover/atras", func(msg mqtt.Message) {
|
||||
ollie.Roll(40, ATRAS)
|
||||
gobot.After(1*time.Second, func() {
|
||||
ollie.Stop()
|
||||
})
|
||||
})
|
||||
|
||||
mqttAdaptor.On("rover/izquierda", func(data []byte) {
|
||||
mqttAdaptor.On("rover/izquierda", func(msg mqtt.Message) {
|
||||
ollie.Roll(40, IZQUIERDA)
|
||||
gobot.After(1*time.Second, func() {
|
||||
ollie.Stop()
|
||||
|
@ -12,36 +12,11 @@ import (
|
||||
"gobot.io/x/gobot/sysfs"
|
||||
)
|
||||
|
||||
func writeFile(path string, data []byte) (i int, err error) {
|
||||
file, err := sysfs.OpenFile(path, os.O_WRONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return file.Write(data)
|
||||
}
|
||||
|
||||
func readFile(path string) ([]byte, error) {
|
||||
file, err := sysfs.OpenFile(path, os.O_RDONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return make([]byte, 0), err
|
||||
}
|
||||
|
||||
buf := make([]byte, 200)
|
||||
var i int
|
||||
i, err = file.Read(buf)
|
||||
if i == 0 {
|
||||
return buf, err
|
||||
}
|
||||
return buf[:i], err
|
||||
}
|
||||
|
||||
type mux struct {
|
||||
pin int
|
||||
value int
|
||||
}
|
||||
|
||||
type sysfsPin struct {
|
||||
pin int
|
||||
resistor int
|
||||
@ -57,26 +32,20 @@ type Adaptor struct {
|
||||
pinmap map[string]sysfsPin
|
||||
tristate sysfs.DigitalPin
|
||||
digitalPins map[int]sysfs.DigitalPin
|
||||
pwmPins map[int]*pwmPin
|
||||
pwmPins map[int]*sysfs.PWMPin
|
||||
i2cBus sysfs.I2cDevice
|
||||
connect func(e *Adaptor) (err error)
|
||||
}
|
||||
|
||||
// changePinMode writes pin mode to current_pinmux file
|
||||
func changePinMode(pin, mode string) (err error) {
|
||||
_, err = writeFile(
|
||||
"/sys/kernel/debug/gpio_debug/gpio"+pin+"/current_pinmux",
|
||||
[]byte("mode"+mode),
|
||||
)
|
||||
return
|
||||
writeFile func(path string, data []byte) (i int, err error)
|
||||
readFile func(path string) ([]byte, error)
|
||||
}
|
||||
|
||||
// NewAdaptor returns a new Edison Adaptor
|
||||
func NewAdaptor() *Adaptor {
|
||||
return &Adaptor{
|
||||
name: gobot.DefaultName("Edison"),
|
||||
board: "arduino",
|
||||
pinmap: arduinoPinMap,
|
||||
name: gobot.DefaultName("Edison"),
|
||||
pinmap: arduinoPinMap,
|
||||
writeFile: writeFile,
|
||||
readFile: readFile,
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +64,11 @@ func (e *Adaptor) SetBoard(n string) { e.board = n }
|
||||
// Connect initializes the Edison for use with the Arduino beakout board
|
||||
func (e *Adaptor) Connect() (err error) {
|
||||
e.digitalPins = make(map[int]sysfs.DigitalPin)
|
||||
e.pwmPins = make(map[int]*pwmPin)
|
||||
e.pwmPins = make(map[int]*sysfs.PWMPin)
|
||||
|
||||
if e.board == "" && e.checkForArduino() {
|
||||
e.board = "arduino"
|
||||
}
|
||||
|
||||
switch e.Board() {
|
||||
case "sparkfun":
|
||||
@ -130,10 +103,10 @@ func (e *Adaptor) Finalize() (err error) {
|
||||
}
|
||||
for _, pin := range e.pwmPins {
|
||||
if pin != nil {
|
||||
if errs := pin.enable("0"); errs != nil {
|
||||
if errs := pin.Enable("0"); errs != nil {
|
||||
err = multierror.Append(err, errs)
|
||||
}
|
||||
if errs := pin.unexport(); errs != nil {
|
||||
if errs := pin.Unexport(); errs != nil {
|
||||
err = multierror.Append(err, errs)
|
||||
}
|
||||
}
|
||||
@ -172,18 +145,18 @@ func (e *Adaptor) PwmWrite(pin string, val byte) (err error) {
|
||||
if err = e.DigitalWrite(pin, 1); err != nil {
|
||||
return
|
||||
}
|
||||
if err = changePinMode(strconv.Itoa(int(sysPin.pin)), "1"); err != nil {
|
||||
if err = changePinMode(e, strconv.Itoa(int(sysPin.pin)), "1"); err != nil {
|
||||
return
|
||||
}
|
||||
e.pwmPins[sysPin.pwmPin] = newPwmPin(sysPin.pwmPin)
|
||||
if err = e.pwmPins[sysPin.pwmPin].export(); err != nil {
|
||||
e.pwmPins[sysPin.pwmPin] = sysfs.NewPWMPin(sysPin.pwmPin)
|
||||
if err = e.pwmPins[sysPin.pwmPin].Export(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = e.pwmPins[sysPin.pwmPin].enable("1"); err != nil {
|
||||
if err = e.pwmPins[sysPin.pwmPin].Enable("1"); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
p, err := e.pwmPins[sysPin.pwmPin].period()
|
||||
p, err := e.pwmPins[sysPin.pwmPin].Period()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -192,14 +165,14 @@ func (e *Adaptor) PwmWrite(pin string, val byte) (err error) {
|
||||
return err
|
||||
}
|
||||
duty := gobot.FromScale(float64(val), 0, 255.0)
|
||||
return e.pwmPins[sysPin.pwmPin].writeDuty(strconv.Itoa(int(float64(period) * duty)))
|
||||
return e.pwmPins[sysPin.pwmPin].WriteDuty(strconv.Itoa(int(float64(period) * duty)))
|
||||
}
|
||||
return errors.New("Not a PWM pin")
|
||||
}
|
||||
|
||||
// AnalogRead returns value from analog reading of specified pin
|
||||
func (e *Adaptor) AnalogRead(pin string) (val int, err error) {
|
||||
buf, err := readFile(
|
||||
buf, err := e.readFile(
|
||||
"/sys/bus/iio/devices/iio:device1/in_voltage" + pin + "_raw",
|
||||
)
|
||||
if err != nil {
|
||||
@ -236,12 +209,29 @@ func (e *Adaptor) GetDefaultBus() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arduinoSetup does needed setup for the Arduino compatible breakout board
|
||||
func (e *Adaptor) arduinoSetup() (err error) {
|
||||
// TODO: also check to see if device labels for
|
||||
// /sys/class/gpio/gpiochip{200,216,232,248}/label == "pcal9555a"
|
||||
func (e *Adaptor) checkForArduino() bool {
|
||||
if err := e.exportTristatePin(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *Adaptor) exportTristatePin() (err error) {
|
||||
e.tristate = sysfs.NewDigitalPin(214)
|
||||
if err = e.tristate.Export(); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// arduinoSetup does needed setup for the Arduino compatible breakout board
|
||||
func (e *Adaptor) arduinoSetup() (err error) {
|
||||
if err = e.exportTristatePin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = e.tristate.Direction(sysfs.OUT); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -262,13 +252,13 @@ func (e *Adaptor) arduinoSetup() (err error) {
|
||||
}
|
||||
|
||||
for _, i := range []string{"111", "115", "114", "109"} {
|
||||
if err = changePinMode(i, "1"); err != nil {
|
||||
if err = changePinMode(e, i, "1"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, i := range []string{"131", "129", "40"} {
|
||||
if err = changePinMode(i, "0"); err != nil {
|
||||
if err = changePinMode(e, i, "0"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -302,7 +292,7 @@ func (e *Adaptor) arduinoI2CSetup() (err error) {
|
||||
}
|
||||
|
||||
for _, i := range []string{"28", "27"} {
|
||||
if err = changePinMode(i, "1"); err != nil {
|
||||
if err = changePinMode(e, i, "1"); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -427,3 +417,38 @@ func (e *Adaptor) newDigitalPin(i int, level int) (err error) {
|
||||
err = io.Unexport()
|
||||
return
|
||||
}
|
||||
|
||||
func writeFile(path string, data []byte) (i int, err error) {
|
||||
file, err := sysfs.OpenFile(path, os.O_WRONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return file.Write(data)
|
||||
}
|
||||
|
||||
func readFile(path string) ([]byte, error) {
|
||||
file, err := sysfs.OpenFile(path, os.O_RDONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return make([]byte, 0), err
|
||||
}
|
||||
|
||||
buf := make([]byte, 200)
|
||||
var i int
|
||||
i, err = file.Read(buf)
|
||||
if i == 0 {
|
||||
return buf, err
|
||||
}
|
||||
return buf[:i], err
|
||||
}
|
||||
|
||||
// changePinMode writes pin mode to current_pinmux file
|
||||
func changePinMode(a *Adaptor, pin, mode string) (err error) {
|
||||
_, err = a.writeFile(
|
||||
"/sys/kernel/debug/gpio_debug/gpio"+pin+"/current_pinmux",
|
||||
[]byte("mode"+mode),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func initTestAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
|
||||
"/dev/i2c-6",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
fs.Files["/sys/class/pwm/pwmchip0/pwm1/period"].Contents = "5000\n"
|
||||
fs.Files["/sys/class/pwm/pwmchip0/pwm1/period"].Contents = "5000"
|
||||
a.Connect()
|
||||
return a, fs
|
||||
}
|
||||
@ -109,17 +109,29 @@ func TestAdaptorConnect(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 6)
|
||||
gobottest.Assert(t, a.Board(), "arduino")
|
||||
|
||||
a = NewAdaptor()
|
||||
sysfs.SetFilesystem(sysfs.NewMockFilesystem([]string{}))
|
||||
gobottest.Refute(t, a.Connect(), nil)
|
||||
}
|
||||
|
||||
func TestAdaptorConnectArduinoError(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
a.writeFile = func(string, []byte) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
}
|
||||
|
||||
err := a.Connect()
|
||||
gobottest.Assert(t, strings.Contains(err.Error(), "write error"), true)
|
||||
}
|
||||
|
||||
func TestAdaptorConnectSparkfun(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
a.SetBoard("sparkfun")
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 1)
|
||||
gobottest.Assert(t, a.Board(), "sparkfun")
|
||||
}
|
||||
|
||||
func TestAdaptorConnectMiniboard(t *testing.T) {
|
||||
@ -127,6 +139,7 @@ func TestAdaptorConnectMiniboard(t *testing.T) {
|
||||
a.SetBoard("miniboard")
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
gobottest.Assert(t, a.GetDefaultBus(), 1)
|
||||
gobottest.Assert(t, a.Board(), "miniboard")
|
||||
}
|
||||
|
||||
func TestAdaptorConnectUnknown(t *testing.T) {
|
||||
@ -176,6 +189,12 @@ func TestAdaptorI2c(t *testing.T) {
|
||||
gobottest.Assert(t, a.Finalize(), nil)
|
||||
}
|
||||
|
||||
func TestAdaptorI2cInvalidBus(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
_, err := a.GetConnection(0xff, 3)
|
||||
gobottest.Assert(t, err, errors.New("Unsupported I2C bus"))
|
||||
}
|
||||
|
||||
func TestAdaptorPwm(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
|
||||
@ -187,6 +206,17 @@ func TestAdaptorPwm(t *testing.T) {
|
||||
gobottest.Assert(t, err, errors.New("Not a PWM pin"))
|
||||
}
|
||||
|
||||
func TestAdaptorPwmError(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
|
||||
a.writeFile = func(string, []byte) (int, error) {
|
||||
return 0, errors.New("write error")
|
||||
}
|
||||
|
||||
err := a.PwmWrite("5", 100)
|
||||
gobottest.Assert(t, err, errors.New("write error"))
|
||||
}
|
||||
|
||||
func TestAdaptorAnalog(t *testing.T) {
|
||||
a, fs := initTestAdaptor()
|
||||
|
||||
@ -194,3 +224,13 @@ func TestAdaptorAnalog(t *testing.T) {
|
||||
i, _ := a.AnalogRead("0")
|
||||
gobottest.Assert(t, i, 250)
|
||||
}
|
||||
|
||||
func TestAdaptorAnalogError(t *testing.T) {
|
||||
a, _ := initTestAdaptor()
|
||||
|
||||
a.readFile = func(string) ([]byte, error) {
|
||||
return nil, errors.New("read error")
|
||||
}
|
||||
_, err := a.AnalogRead("0")
|
||||
gobottest.Assert(t, err, errors.New("read error"))
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
package edison
|
||||
|
||||
import "strconv"
|
||||
|
||||
// pwmPath returns pwm base path
|
||||
func pwmPath() string {
|
||||
return "/sys/class/pwm/pwmchip0"
|
||||
}
|
||||
|
||||
// pwmExportPath returns export path
|
||||
func pwmExportPath() string {
|
||||
return pwmPath() + "/export"
|
||||
}
|
||||
|
||||
// pwmUnExportPath returns unexport path
|
||||
func pwmUnExportPath() string {
|
||||
return pwmPath() + "/unexport"
|
||||
}
|
||||
|
||||
// pwmDutyCyclePath returns duty_cycle path for specified pin
|
||||
func pwmDutyCyclePath(pin string) string {
|
||||
return pwmPath() + "/pwm" + pin + "/duty_cycle"
|
||||
}
|
||||
|
||||
// pwmPeriodPath returns period path for specified pin
|
||||
func pwmPeriodPath(pin string) string {
|
||||
return pwmPath() + "/pwm" + pin + "/period"
|
||||
}
|
||||
|
||||
// pwmEnablePath returns enable path for specified pin
|
||||
func pwmEnablePath(pin string) string {
|
||||
return pwmPath() + "/pwm" + pin + "/enable"
|
||||
}
|
||||
|
||||
type pwmPin struct {
|
||||
pin string
|
||||
}
|
||||
|
||||
// newPwmPin returns an exported and enabled pwmPin
|
||||
func newPwmPin(pin int) *pwmPin {
|
||||
return &pwmPin{pin: strconv.Itoa(pin)}
|
||||
}
|
||||
|
||||
// enable writes value to pwm enable path
|
||||
func (p *pwmPin) enable(val string) (err error) {
|
||||
_, err = writeFile(pwmEnablePath(p.pin), []byte(val))
|
||||
return
|
||||
}
|
||||
|
||||
// period reads from pwm period path and returns value
|
||||
func (p *pwmPin) period() (period string, err error) {
|
||||
buf, err := readFile(pwmPeriodPath(p.pin))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return string(buf[0 : len(buf)-1]), nil
|
||||
}
|
||||
|
||||
// writeDuty writes value to pwm duty cycle path
|
||||
func (p *pwmPin) writeDuty(duty string) (err error) {
|
||||
_, err = writeFile(pwmDutyCyclePath(p.pin), []byte(duty))
|
||||
return
|
||||
}
|
||||
|
||||
// export writes pin to pwm export path
|
||||
func (p *pwmPin) export() (err error) {
|
||||
_, err = writeFile(pwmExportPath(), []byte(p.pin))
|
||||
return
|
||||
}
|
||||
|
||||
// export writes pin to pwm unexport path
|
||||
func (p *pwmPin) unexport() (err error) {
|
||||
_, err = writeFile(pwmUnExportPath(), []byte(p.pin))
|
||||
return
|
||||
}
|
@ -3,7 +3,6 @@ package joule
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
@ -12,32 +11,6 @@ import (
|
||||
"gobot.io/x/gobot/sysfs"
|
||||
)
|
||||
|
||||
func writeFile(path string, data []byte) (i int, err error) {
|
||||
file, err := sysfs.OpenFile(path, os.O_WRONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return file.Write(data)
|
||||
}
|
||||
|
||||
func readFile(path string) ([]byte, error) {
|
||||
file, err := sysfs.OpenFile(path, os.O_RDONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return make([]byte, 0), err
|
||||
}
|
||||
|
||||
buf := make([]byte, 200)
|
||||
var i int
|
||||
i, err = file.Read(buf)
|
||||
if i == 0 {
|
||||
return buf, err
|
||||
}
|
||||
return buf[:i], err
|
||||
}
|
||||
|
||||
type sysfsPin struct {
|
||||
pin int
|
||||
pwmPin int
|
||||
@ -47,7 +20,7 @@ type sysfsPin struct {
|
||||
type Adaptor struct {
|
||||
name string
|
||||
digitalPins map[int]sysfs.DigitalPin
|
||||
pwmPins map[int]*pwmPin
|
||||
pwmPins map[int]*sysfs.PWMPin
|
||||
i2cBuses [3]sysfs.I2cDevice
|
||||
connect func(e *Adaptor) (err error)
|
||||
}
|
||||
@ -71,7 +44,7 @@ func (e *Adaptor) SetName(n string) { e.name = n }
|
||||
// Connect initializes the Joule for use with the Arduino beakout board
|
||||
func (e *Adaptor) Connect() (err error) {
|
||||
e.digitalPins = make(map[int]sysfs.DigitalPin)
|
||||
e.pwmPins = make(map[int]*pwmPin)
|
||||
e.pwmPins = make(map[int]*sysfs.PWMPin)
|
||||
err = e.connect(e)
|
||||
return
|
||||
}
|
||||
@ -87,10 +60,10 @@ func (e *Adaptor) Finalize() (err error) {
|
||||
}
|
||||
for _, pin := range e.pwmPins {
|
||||
if pin != nil {
|
||||
if errs := pin.enable("0"); errs != nil {
|
||||
if errs := pin.Enable("0"); errs != nil {
|
||||
err = multierror.Append(err, errs)
|
||||
}
|
||||
if errs := pin.unexport(); errs != nil {
|
||||
if errs := pin.Unexport(); errs != nil {
|
||||
err = multierror.Append(err, errs)
|
||||
}
|
||||
}
|
||||
@ -153,15 +126,15 @@ func (e *Adaptor) PwmWrite(pin string, val byte) (err error) {
|
||||
if err = e.DigitalWrite(pin, 1); err != nil {
|
||||
return
|
||||
}
|
||||
e.pwmPins[sysPin.pwmPin] = newPwmPin(sysPin.pwmPin)
|
||||
if err = e.pwmPins[sysPin.pwmPin].export(); err != nil {
|
||||
e.pwmPins[sysPin.pwmPin] = sysfs.NewPWMPin(sysPin.pwmPin)
|
||||
if err = e.pwmPins[sysPin.pwmPin].Export(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = e.pwmPins[sysPin.pwmPin].enable("1"); err != nil {
|
||||
if err = e.pwmPins[sysPin.pwmPin].Enable("1"); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
p, err := e.pwmPins[sysPin.pwmPin].period()
|
||||
p, err := e.pwmPins[sysPin.pwmPin].Period()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -170,7 +143,7 @@ func (e *Adaptor) PwmWrite(pin string, val byte) (err error) {
|
||||
return err
|
||||
}
|
||||
duty := gobot.FromScale(float64(val), 0, 255.0)
|
||||
return e.pwmPins[sysPin.pwmPin].writeDuty(strconv.Itoa(int(float64(period) * duty)))
|
||||
return e.pwmPins[sysPin.pwmPin].WriteDuty(strconv.Itoa(int(float64(period) * duty)))
|
||||
}
|
||||
return errors.New("Not a PWM pin")
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ func initTestAdaptor() (*Adaptor, *sysfs.MockFilesystem) {
|
||||
"/dev/i2c-0",
|
||||
})
|
||||
sysfs.SetFilesystem(fs)
|
||||
fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "5000\n"
|
||||
fs.Files["/sys/class/pwm/pwmchip0/pwm0/period"].Contents = "5000"
|
||||
a.Connect()
|
||||
return a, fs
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
// Package joule pwm implementation
|
||||
package joule
|
||||
|
||||
import "strconv"
|
||||
|
||||
// pwmPath returns pwm base path
|
||||
func pwmPath() string {
|
||||
return "/sys/class/pwm/pwmchip0"
|
||||
}
|
||||
|
||||
// pwmExportPath returns export path
|
||||
func pwmExportPath() string {
|
||||
return pwmPath() + "/export"
|
||||
}
|
||||
|
||||
// pwmUnExportPath returns unexport path
|
||||
func pwmUnExportPath() string {
|
||||
return pwmPath() + "/unexport"
|
||||
}
|
||||
|
||||
// pwmDutyCyclePath returns duty_cycle path for specified pin
|
||||
func pwmDutyCyclePath(pin string) string {
|
||||
return pwmPath() + "/pwm" + pin + "/duty_cycle"
|
||||
}
|
||||
|
||||
// pwmPeriodPath returns period path for specified pin
|
||||
func pwmPeriodPath(pin string) string {
|
||||
return pwmPath() + "/pwm" + pin + "/period"
|
||||
}
|
||||
|
||||
// pwmEnablePath returns enable path for specified pin
|
||||
func pwmEnablePath(pin string) string {
|
||||
return pwmPath() + "/pwm" + pin + "/enable"
|
||||
}
|
||||
|
||||
type pwmPin struct {
|
||||
pin string
|
||||
}
|
||||
|
||||
// newPwmPin returns an exported and enabled pwmPin
|
||||
func newPwmPin(pin int) *pwmPin {
|
||||
return &pwmPin{pin: strconv.Itoa(pin)}
|
||||
}
|
||||
|
||||
// enable writes value to pwm enable path
|
||||
func (p *pwmPin) enable(val string) (err error) {
|
||||
_, err = writeFile(pwmEnablePath(p.pin), []byte(val))
|
||||
return
|
||||
}
|
||||
|
||||
// period reads from pwm period path and returns value
|
||||
func (p *pwmPin) period() (period string, err error) {
|
||||
buf, err := readFile(pwmPeriodPath(p.pin))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return string(buf[0 : len(buf)-1]), nil
|
||||
}
|
||||
|
||||
// writeDuty writes value to pwm duty cycle path
|
||||
func (p *pwmPin) writeDuty(duty string) (err error) {
|
||||
_, err = writeFile(pwmDutyCyclePath(p.pin), []byte(duty))
|
||||
return
|
||||
}
|
||||
|
||||
// export writes pin to pwm export path
|
||||
func (p *pwmPin) export() (err error) {
|
||||
_, err = writeFile(pwmExportPath(), []byte(p.pin))
|
||||
return
|
||||
}
|
||||
|
||||
// export writes pin to pwm unexport path
|
||||
func (p *pwmPin) unexport() (err error) {
|
||||
_, err = writeFile(pwmUnExportPath(), []byte(p.pin))
|
||||
return
|
||||
}
|
@ -6,10 +6,16 @@ import (
|
||||
common "gobot.io/x/gobot/platforms/mavlink/common"
|
||||
)
|
||||
|
||||
type UDPConnection interface {
|
||||
Close() error
|
||||
ReadFromUDP([]byte) (int, *net.UDPAddr, error)
|
||||
WriteTo([]byte, net.Addr) (int, error)
|
||||
}
|
||||
|
||||
type UDPAdaptor struct {
|
||||
name string
|
||||
port string
|
||||
sock *net.UDPConn
|
||||
sock UDPConnection
|
||||
}
|
||||
|
||||
var _ BaseAdaptor = (*UDPAdaptor)(nil)
|
||||
@ -86,5 +92,10 @@ func (m *UDPAdaptor) ReadMAVLinkPacket() (*common.MAVLinkPacket, error) {
|
||||
}
|
||||
|
||||
func (m *UDPAdaptor) Write(b []byte) (int, error) {
|
||||
return m.sock.Write(b)
|
||||
addr, err := net.ResolveUDPAddr("udp", m.Port())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return m.sock.WriteTo(b, addr)
|
||||
}
|
||||
|
@ -1,15 +1,51 @@
|
||||
package mavlink
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gobot.io/x/gobot"
|
||||
"gobot.io/x/gobot/gobottest"
|
||||
mavlink "gobot.io/x/gobot/platforms/mavlink/common"
|
||||
)
|
||||
|
||||
var _ gobot.Adaptor = (*UDPAdaptor)(nil)
|
||||
|
||||
type MockUDPConnection struct {
|
||||
TestClose func() error
|
||||
TestReadFromUDP func([]byte) (int, *net.UDPAddr, error)
|
||||
TestWriteTo func([]byte, net.Addr) (int, error)
|
||||
}
|
||||
|
||||
func (m *MockUDPConnection) Close() error {
|
||||
return m.TestClose()
|
||||
}
|
||||
|
||||
func (m *MockUDPConnection) ReadFromUDP(b []byte) (int, *net.UDPAddr, error) {
|
||||
return m.TestReadFromUDP(b)
|
||||
}
|
||||
|
||||
func (m *MockUDPConnection) WriteTo(b []byte, a net.Addr) (int, error) {
|
||||
return m.TestWriteTo(b, a)
|
||||
}
|
||||
|
||||
func NewMockUDPConnection() *MockUDPConnection {
|
||||
return &MockUDPConnection{
|
||||
TestClose: func() error {
|
||||
return nil
|
||||
},
|
||||
TestReadFromUDP: func([]byte) (int, *net.UDPAddr, error) {
|
||||
return 0, nil, nil
|
||||
},
|
||||
TestWriteTo: func([]byte, net.Addr) (int, error) {
|
||||
return 0, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func initTestMavlinkUDPAdaptor() *UDPAdaptor {
|
||||
m := NewUDPAdaptor(":14550")
|
||||
return m
|
||||
@ -27,12 +63,78 @@ func TestMavlinkUDPAdaptorName(t *testing.T) {
|
||||
gobottest.Assert(t, a.Name(), "NewName")
|
||||
}
|
||||
|
||||
func TestMavlinkUDPAdaptorConnect(t *testing.T) {
|
||||
func TestMavlinkUDPAdaptorConnectAndFinalize(t *testing.T) {
|
||||
a := initTestMavlinkUDPAdaptor()
|
||||
gobottest.Assert(t, a.Connect(), nil)
|
||||
}
|
||||
|
||||
func TestMavlinkUDPAdaptorFinalize(t *testing.T) {
|
||||
a := initTestMavlinkUDPAdaptor()
|
||||
gobottest.Assert(t, a.Finalize(), nil)
|
||||
}
|
||||
|
||||
func TestMavlinkUDPAdaptorWrite(t *testing.T) {
|
||||
a := initTestMavlinkUDPAdaptor()
|
||||
a.Connect()
|
||||
defer a.Finalize()
|
||||
|
||||
m := NewMockUDPConnection()
|
||||
m.TestWriteTo = func([]byte, net.Addr) (int, error) {
|
||||
return 3, nil
|
||||
}
|
||||
a.sock = m
|
||||
|
||||
i, err := a.Write([]byte{0x01, 0x02, 0x03})
|
||||
gobottest.Assert(t, i, 3)
|
||||
gobottest.Assert(t, err, nil)
|
||||
}
|
||||
|
||||
func TestMavlinkReadMAVLinkReadDefaultPacket(t *testing.T) {
|
||||
a := initTestMavlinkUDPAdaptor()
|
||||
a.Connect()
|
||||
defer a.Finalize()
|
||||
|
||||
m := NewMockUDPConnection()
|
||||
|
||||
m.TestReadFromUDP = func(b []byte) (int, *net.UDPAddr, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Write([]byte{mavlink.MAVLINK_10_STX, 0x02, 0x03})
|
||||
copy(b, buf.Bytes())
|
||||
return buf.Len(), nil, nil
|
||||
}
|
||||
a.sock = m
|
||||
|
||||
p, _ := a.ReadMAVLinkPacket()
|
||||
gobottest.Assert(t, p.Protocol, uint8(254))
|
||||
}
|
||||
|
||||
func TestMavlinkReadMAVLinkPacketReadError(t *testing.T) {
|
||||
a := initTestMavlinkUDPAdaptor()
|
||||
a.Connect()
|
||||
defer a.Finalize()
|
||||
|
||||
m := NewMockUDPConnection()
|
||||
|
||||
i := 0
|
||||
m.TestReadFromUDP = func(b []byte) (int, *net.UDPAddr, error) {
|
||||
switch i {
|
||||
case 0:
|
||||
i = 1
|
||||
return 1, nil, nil
|
||||
case 1:
|
||||
i = 2
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Write([]byte{0x01, 0x02, 0x03})
|
||||
copy(b, buf.Bytes())
|
||||
return buf.Len(), nil, nil
|
||||
case 2:
|
||||
i = 3
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Write([]byte{mavlink.MAVLINK_10_STX, 255})
|
||||
copy(b, buf.Bytes())
|
||||
return buf.Len(), nil, nil
|
||||
}
|
||||
|
||||
return 0, nil, errors.New("read error")
|
||||
}
|
||||
a.sock = m
|
||||
|
||||
_, err := a.ReadMAVLinkPacket()
|
||||
gobottest.Assert(t, err, errors.New("read error"))
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ func main() {
|
||||
mqttAdaptor := mqtt.NewAdaptor("tcp://0.0.0.0:1883", "pinger")
|
||||
|
||||
work := func() {
|
||||
mqttAdaptor.On("hello", func(data []byte) {
|
||||
fmt.Println("hello")
|
||||
mqttAdaptor.On("hello", func(msg mqtt.Message) {
|
||||
fmt.Println(msg)
|
||||
})
|
||||
mqttAdaptor.On("hola", func(data []byte) {
|
||||
fmt.Println("hola")
|
||||
mqttAdaptor.On("hola", func(msg mqtt.Message) {
|
||||
fmt.Println(msg)
|
||||
})
|
||||
data := []byte("o")
|
||||
gobot.Every(1*time.Second, func() {
|
||||
|
@ -11,6 +11,9 @@ import (
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
)
|
||||
|
||||
// Message is a message received from the broker.
|
||||
type Message paho.Message
|
||||
|
||||
// Adaptor is the Gobot Adaptor for MQTT
|
||||
type Adaptor struct {
|
||||
name string
|
||||
@ -86,7 +89,7 @@ func (a *Adaptor) SetClientCert(val string) { a.clientCert = val }
|
||||
// ClientKey returns the MQTT client SSL key file
|
||||
func (a *Adaptor) ClientKey() string { return a.clientKey }
|
||||
|
||||
// SetClientCert sets the MQTT server SSL key file
|
||||
// SetClientKey sets the MQTT client SSL key file
|
||||
func (a *Adaptor) SetClientKey(val string) { a.clientKey = val }
|
||||
|
||||
// Connect returns true if connection to mqtt is established
|
||||
@ -123,12 +126,12 @@ func (a *Adaptor) Publish(topic string, message []byte) bool {
|
||||
}
|
||||
|
||||
// On subscribes to a topic, and then calls the message handler function when data is received
|
||||
func (a *Adaptor) On(event string, f func(s []byte)) bool {
|
||||
func (a *Adaptor) On(event string, f func(msg Message)) bool {
|
||||
if a.client == nil {
|
||||
return false
|
||||
}
|
||||
a.client.Subscribe(event, 0, func(client paho.Client, msg paho.Message) {
|
||||
f(msg.Payload())
|
||||
f(msg)
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
var _ gobot.Adaptor = (*Adaptor)(nil)
|
||||
|
||||
func initTestMqttAdaptor() *Adaptor {
|
||||
return NewAdaptor("localhost:1883", "client")
|
||||
return NewAdaptor("tcp://localhost:1883", "client")
|
||||
}
|
||||
|
||||
func TestMqttAdaptorName(t *testing.T) {
|
||||
@ -24,8 +24,65 @@ func TestMqttAdaptorName(t *testing.T) {
|
||||
gobottest.Assert(t, a.Name(), "NewName")
|
||||
}
|
||||
|
||||
func TestMqttAdaptorConnect(t *testing.T) {
|
||||
func TestMqttAdaptorPort(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
gobottest.Assert(t, a.Port(), "tcp://localhost:1883")
|
||||
}
|
||||
|
||||
func TestMqttAdaptorAutoReconnect(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
gobottest.Assert(t, a.AutoReconnect(), false)
|
||||
a.SetAutoReconnect(true)
|
||||
gobottest.Assert(t, a.AutoReconnect(), true)
|
||||
}
|
||||
|
||||
func TestMqttAdaptorUseSSL(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
gobottest.Assert(t, a.UseSSL(), false)
|
||||
a.SetUseSSL(true)
|
||||
gobottest.Assert(t, a.UseSSL(), true)
|
||||
}
|
||||
|
||||
func TestMqttAdaptorUseServerCert(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
gobottest.Assert(t, a.ServerCert(), "")
|
||||
a.SetServerCert("/path/to/server.cert")
|
||||
gobottest.Assert(t, a.ServerCert(), "/path/to/server.cert")
|
||||
}
|
||||
|
||||
func TestMqttAdaptorUseClientCert(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
gobottest.Assert(t, a.ClientCert(), "")
|
||||
a.SetClientCert("/path/to/client.cert")
|
||||
gobottest.Assert(t, a.ClientCert(), "/path/to/client.cert")
|
||||
}
|
||||
|
||||
func TestMqttAdaptorUseClientKey(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
gobottest.Assert(t, a.ClientKey(), "")
|
||||
a.SetClientKey("/path/to/client.key")
|
||||
gobottest.Assert(t, a.ClientKey(), "/path/to/client.key")
|
||||
}
|
||||
|
||||
func TestMqttAdaptorConnectError(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
var expected error
|
||||
expected = multierror.Append(expected, errors.New("Network Error : dial tcp 127.0.0.1:1883: getsockopt: connection refused"))
|
||||
|
||||
gobottest.Assert(t, a.Connect(), expected)
|
||||
}
|
||||
|
||||
func TestMqttAdaptorConnectSSLError(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
a.SetUseSSL(true)
|
||||
var expected error
|
||||
expected = multierror.Append(expected, errors.New("Network Error : dial tcp 127.0.0.1:1883: getsockopt: connection refused"))
|
||||
|
||||
gobottest.Assert(t, a.Connect(), expected)
|
||||
}
|
||||
|
||||
func TestMqttAdaptorConnectWithAuthError(t *testing.T) {
|
||||
a := NewAdaptorWithAuth("localhost:1883", "client", "user", "pass")
|
||||
var expected error
|
||||
expected = multierror.Append(expected, errors.New("Network Error : Unknown protocol"))
|
||||
|
||||
@ -52,7 +109,7 @@ func TestMqttAdaptorPublishWhenConnected(t *testing.T) {
|
||||
|
||||
func TestMqttAdaptorCannotOnUnlessConnected(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
gobottest.Assert(t, a.On("hola", func(data []byte) {
|
||||
gobottest.Assert(t, a.On("hola", func(msg Message) {
|
||||
fmt.Println("hola")
|
||||
}), false)
|
||||
}
|
||||
@ -60,7 +117,7 @@ func TestMqttAdaptorCannotOnUnlessConnected(t *testing.T) {
|
||||
func TestMqttAdaptorOnWhenConnected(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
a.Connect()
|
||||
gobottest.Assert(t, a.On("hola", func(data []byte) {
|
||||
gobottest.Assert(t, a.On("hola", func(msg Message) {
|
||||
fmt.Println("hola")
|
||||
}), true)
|
||||
}
|
||||
|
@ -74,10 +74,10 @@ func (m *Driver) Publish(data interface{}) bool {
|
||||
|
||||
// On subscribes to data updates for the current device topic,
|
||||
// and then calls the message handler function when data is received
|
||||
func (m *Driver) On(n string, f func(d interface{})) error {
|
||||
func (m *Driver) On(n string, f func(msg interface{})) error {
|
||||
// TODO: also be able to subscribe to Error updates
|
||||
f1 := func(s []byte) {
|
||||
f(s)
|
||||
f1 := func(msg Message) {
|
||||
f(msg)
|
||||
}
|
||||
m.adaptor().On(m.topic, f1)
|
||||
return nil
|
||||
|
@ -26,3 +26,27 @@ func TestMqttDriverName(t *testing.T) {
|
||||
d.SetName("NewName")
|
||||
gobottest.Assert(t, d.Name(), "NewName")
|
||||
}
|
||||
|
||||
func TestMqttDriverTopic(t *testing.T) {
|
||||
d := NewDriver(initTestMqttAdaptor(), "/test/topic")
|
||||
gobottest.Assert(t, d.Topic(), "/test/topic")
|
||||
d.SetTopic("/test/newtopic")
|
||||
gobottest.Assert(t, d.Topic(), "/test/newtopic")
|
||||
}
|
||||
|
||||
func TestMqttDriverPublish(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
d := NewDriver(a, "/test/topic")
|
||||
a.Connect()
|
||||
d.Start()
|
||||
defer d.Halt()
|
||||
gobottest.Assert(t, d.Publish([]byte{0x01, 0x02, 0x03}), true)
|
||||
}
|
||||
|
||||
func TestMqttDriverPublishError(t *testing.T) {
|
||||
a := initTestMqttAdaptor()
|
||||
d := NewDriver(a, "/test/topic")
|
||||
d.Start()
|
||||
defer d.Halt()
|
||||
gobottest.Assert(t, d.Publish([]byte{0x01, 0x02, 0x03}), false)
|
||||
}
|
||||
|
125
sysfs/pwm_pin.go
Normal file
125
sysfs/pwm_pin.go
Normal file
@ -0,0 +1,125 @@
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// PWMPin is the interface for sysfs PWM interactions
|
||||
type PWMPinner interface {
|
||||
// Export exports the pin for use by the operating system
|
||||
Export() error
|
||||
// Unexport unexports the pin and releases the pin from the operating system
|
||||
Unexport() error
|
||||
// Enable enables/disables the PWM pin
|
||||
Enable(val string) (err error)
|
||||
// Period returns the current PWM period for pin
|
||||
Period() (period string, err error)
|
||||
// WriteDuty writes the duty cycle to the pin
|
||||
WriteDuty(duty string) (err error)
|
||||
}
|
||||
|
||||
type PWMPin struct {
|
||||
pin string
|
||||
Chip string
|
||||
write func(path string, data []byte) (i int, err error)
|
||||
read func(path string) ([]byte, error)
|
||||
}
|
||||
|
||||
// NewPwmPin returns a new pwmPin
|
||||
func NewPWMPin(pin int) *PWMPin {
|
||||
return &PWMPin{
|
||||
pin: strconv.Itoa(pin),
|
||||
Chip: "0",
|
||||
read: readPwmFile,
|
||||
write: writePwmFile}
|
||||
}
|
||||
|
||||
// Export writes pin to pwm export path
|
||||
func (p *PWMPin) Export() (err error) {
|
||||
_, err = p.write(p.pwmExportPath(), []byte(p.pin))
|
||||
return
|
||||
}
|
||||
|
||||
// Unexport writes pin to pwm unexport path
|
||||
func (p *PWMPin) Unexport() (err error) {
|
||||
_, err = p.write(p.pwmUnexportPath(), []byte(p.pin))
|
||||
return
|
||||
}
|
||||
|
||||
// Enable writes value to pwm enable path
|
||||
func (p *PWMPin) Enable(val string) (err error) {
|
||||
_, err = p.write(p.pwmEnablePath(), []byte(val))
|
||||
return
|
||||
}
|
||||
|
||||
// Period reads from pwm period path and returns value
|
||||
func (p *PWMPin) Period() (period string, err error) {
|
||||
buf, err := p.read(p.pwmPeriodPath())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// WriteDuty writes value to pwm duty cycle path
|
||||
func (p *PWMPin) WriteDuty(duty string) (err error) {
|
||||
_, err = p.write(p.pwmDutyCyclePath(), []byte(duty))
|
||||
return
|
||||
}
|
||||
|
||||
// pwmPath returns pwm base path
|
||||
func (p *PWMPin) pwmPath() string {
|
||||
return "/sys/class/pwm/pwmchip" + p.Chip
|
||||
}
|
||||
|
||||
// pwmExportPath returns export path
|
||||
func (p *PWMPin) pwmExportPath() string {
|
||||
return p.pwmPath() + "/export"
|
||||
}
|
||||
|
||||
// pwmUnexportPath returns unexport path
|
||||
func (p *PWMPin) pwmUnexportPath() string {
|
||||
return p.pwmPath() + "/unexport"
|
||||
}
|
||||
|
||||
// pwmDutyCyclePath returns duty_cycle path for specified pin
|
||||
func (p *PWMPin) pwmDutyCyclePath() string {
|
||||
return p.pwmPath() + "/pwm" + p.pin + "/duty_cycle"
|
||||
}
|
||||
|
||||
// pwmPeriodPath returns period path for specified pin
|
||||
func (p *PWMPin) pwmPeriodPath() string {
|
||||
return p.pwmPath() + "/pwm" + p.pin + "/period"
|
||||
}
|
||||
|
||||
// pwmEnablePath returns enable path for specified pin
|
||||
func (p *PWMPin) pwmEnablePath() string {
|
||||
return p.pwmPath() + "/pwm" + p.pin + "/enable"
|
||||
}
|
||||
|
||||
func writePwmFile(path string, data []byte) (i int, err error) {
|
||||
file, err := OpenFile(path, os.O_WRONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return file.Write(data)
|
||||
}
|
||||
|
||||
func readPwmFile(path string) ([]byte, error) {
|
||||
file, err := OpenFile(path, os.O_RDONLY, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return make([]byte, 0), err
|
||||
}
|
||||
|
||||
buf := make([]byte, 200)
|
||||
var i int
|
||||
i, err = file.Read(buf)
|
||||
if i == 0 {
|
||||
return buf, err
|
||||
}
|
||||
return buf[:i], err
|
||||
}
|
104
sysfs/pwm_pin_test.go
Normal file
104
sysfs/pwm_pin_test.go
Normal file
@ -0,0 +1,104 @@
|
||||
package sysfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"gobot.io/x/gobot/gobottest"
|
||||
)
|
||||
|
||||
func TestPwmPin(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/sys/class/pwm/pwmchip0/export",
|
||||
"/sys/class/pwm/pwmchip0/unexport",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/enable",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/period",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/duty_cycle",
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
gobottest.Assert(t, pin.pin, "10")
|
||||
|
||||
err := pin.Unexport()
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/pwm/pwmchip0/unexport"].Contents, "10")
|
||||
|
||||
err = pin.Export()
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/pwm/pwmchip0/export"].Contents, "10")
|
||||
|
||||
gobottest.Refute(t, fs.Files["/sys/class/pwm/pwmchip0/pwm10/enable"].Contents, "1")
|
||||
err = pin.Enable("1")
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/pwm/pwmchip0/pwm10/enable"].Contents, "1")
|
||||
|
||||
fs.Files["/sys/class/pwm/pwmchip0/pwm10/period"].Contents = "6"
|
||||
data, _ := pin.Period()
|
||||
gobottest.Assert(t, data, "6")
|
||||
|
||||
gobottest.Refute(t, fs.Files["/sys/class/pwm/pwmchip0/pwm10/duty_cycle"].Contents, "1")
|
||||
err = pin.WriteDuty("100")
|
||||
gobottest.Assert(t, err, nil)
|
||||
gobottest.Assert(t, fs.Files["/sys/class/pwm/pwmchip0/pwm10/duty_cycle"].Contents, "100")
|
||||
}
|
||||
|
||||
func TestPwmPinExportError(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/sys/class/pwm/pwmchip0/export",
|
||||
"/sys/class/pwm/pwmchip0/unexport",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/enable",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/period",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/duty_cycle",
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.write = func(string, []byte) (int, error) {
|
||||
return 0, &os.PathError{Err: syscall.EBUSY}
|
||||
}
|
||||
|
||||
gobottest.Refute(t, pin.Export(), nil)
|
||||
}
|
||||
|
||||
func TestPwmPinUnxportError(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/sys/class/pwm/pwmchip0/export",
|
||||
"/sys/class/pwm/pwmchip0/unexport",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/enable",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/period",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/duty_cycle",
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.write = func(string, []byte) (int, error) {
|
||||
return 0, &os.PathError{Err: syscall.EBUSY}
|
||||
}
|
||||
|
||||
gobottest.Refute(t, pin.Unexport(), nil)
|
||||
}
|
||||
|
||||
func TestPwmPinPeriodError(t *testing.T) {
|
||||
fs := NewMockFilesystem([]string{
|
||||
"/sys/class/pwm/pwmchip0/export",
|
||||
"/sys/class/pwm/pwmchip0/unexport",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/enable",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/period",
|
||||
"/sys/class/pwm/pwmchip0/pwm10/duty_cycle",
|
||||
})
|
||||
|
||||
SetFilesystem(fs)
|
||||
|
||||
pin := NewPWMPin(10)
|
||||
pin.read = func(string) ([]byte, error) {
|
||||
return nil, &os.PathError{Err: syscall.EBUSY}
|
||||
}
|
||||
|
||||
_, err := pin.Period()
|
||||
gobottest.Refute(t, err, nil)
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package gobot
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -79,3 +80,8 @@ func TestRand(t *testing.T) {
|
||||
t.Errorf("%v should not equal %v", a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultName(t *testing.T) {
|
||||
name := DefaultName("tester")
|
||||
gobottest.Assert(t, strings.Contains(name, "tester"), true)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user