func TestConnect(t *testing.T) { b := New() response := testProtocolResponse() go func() { for { testReadData = append(testReadData, response...) <-time.After(100 * time.Millisecond) } }() gobot.Once(b.Event("ProtocolVersion"), func(data interface{}) { response = testFirmwareResponse() }) gobot.Once(b.Event("FirmwareQuery"), func(data interface{}) { response = testCapabilitiesResponse() }) gobot.Once(b.Event("CapabilityQuery"), func(data interface{}) { response = testAnalogMappingResponse() }) gobot.Once(b.Event("AnalogMappingQuery"), func(data interface{}) { response = testProtocolResponse() }) gobot.Assert(t, b.Connect(readWriteCloser{}), nil) }
func TestSparkCoreAdaptorEventStream(t *testing.T) { a := initTestSparkCoreAdaptor() var url string eventSource = func(u string) (chan eventsource.Event, chan error, error) { url = u return nil, nil, nil } a.EventStream("all", "ping") gobot.Assert(t, url, "https://api.spark.io/v1/events/ping?access_token=token") a.EventStream("devices", "ping") gobot.Assert(t, url, "https://api.spark.io/v1/devices/events/ping?access_token=token") a.EventStream("device", "ping") gobot.Assert(t, url, "https://api.spark.io/v1/devices/myDevice/events/ping?access_token=token") _, err := a.EventStream("nothing", "ping") gobot.Assert(t, err.Error(), "source param should be: all, devices or device") eventSource = func(u string) (chan eventsource.Event, chan error, error) { return nil, nil, errors.New("error connecting sse") } _, err = a.EventStream("devices", "") gobot.Assert(t, err.Error(), "error connecting sse") eventChan := make(chan eventsource.Event, 0) errorChan := make(chan error, 0) eventSource = func(u string) (chan eventsource.Event, chan error, error) { return eventChan, errorChan, nil } sem := make(chan bool, 0) stream, err := a.EventStream("devices", "") gobot.Assert(t, err, nil) eventChan <- testEventSource{event: "event", data: "sse event"} gobot.Once(stream, func(data interface{}) { e := data.(Event) gobot.Assert(t, e.Name, "event") gobot.Assert(t, e.Data, "sse event") gobot.Assert(t, e.Error, nil) sem <- true }) <-sem errorChan <- errors.New("stream error") gobot.Once(stream, func(data interface{}) { e := data.(Event) gobot.Assert(t, e.Name, "") gobot.Assert(t, e.Data, "") gobot.Assert(t, e.Error.Error(), "stream error") sem <- true }) <-sem }
func TestAnalogSensorDriverStart(t *testing.T) { sem := make(chan bool, 1) d := NewAnalogSensorDriver(newGpioTestAdaptor("adaptor"), "bot", "1") gobot.Assert(t, len(d.Start()), 0) gobot.Once(d.Event(Data), func(data interface{}) { gobot.Assert(t, data.(int), 100) sem <- true }) testAdaptorAnalogRead = func() (val int, err error) { val = 100 return } select { case <-sem: case <-time.After(15 * time.Millisecond): t.Errorf("AnalogSensor Event \"Data\" was not published") } gobot.Once(d.Event(Error), func(data interface{}) { gobot.Assert(t, data.(error).Error(), "read error") sem <- true }) testAdaptorAnalogRead = func() (val int, err error) { err = errors.New("read error") return } select { case <-sem: case <-time.After(15 * time.Millisecond): t.Errorf("AnalogSensor Event \"Error\" was not published") } gobot.Once(d.Event(Data), func(data interface{}) { sem <- true }) testAdaptorAnalogRead = func() (val int, err error) { val = 200 return } d.halt <- true select { case <-sem: t.Errorf("AnalogSensor Event should not published") case <-time.After(30 * time.Millisecond): } }
// Connect connects to the Client given conn. It first resets the firmata board // then continuously polls the firmata board for new information when it's // available. func (b *Client) Connect(conn io.ReadWriteCloser) (err error) { if b.connected { return ErrConnected } b.connection = conn b.Reset() initFunc := b.ProtocolVersionQuery gobot.Once(b.Event("ProtocolVersion"), func(data interface{}) { initFunc = b.FirmwareQuery }) gobot.Once(b.Event("FirmwareQuery"), func(data interface{}) { initFunc = b.CapabilitiesQuery }) gobot.Once(b.Event("CapabilityQuery"), func(data interface{}) { initFunc = b.AnalogMappingQuery }) gobot.Once(b.Event("AnalogMappingQuery"), func(data interface{}) { initFunc = func() error { return nil } b.ReportDigital(0, 1) b.ReportDigital(1, 1) b.connected = true }) for { if err := initFunc(); err != nil { return err } if err := b.process(); err != nil { return err } if b.connected { go func() { for { if !b.connected { break } if err := b.process(); err != nil { gobot.Publish(b.Event("Error"), err) } } }() break } } return }
func TestMavlinkDriverStart(t *testing.T) { d := initTestMavlinkDriver() err := make(chan error, 0) packet := make(chan *common.MAVLinkPacket, 0) message := make(chan common.MAVLinkMessage, 0) gobot.Once(d.Event("packet"), func(data interface{}) { packet <- data.(*common.MAVLinkPacket) }) gobot.Once(d.Event("message"), func(data interface{}) { message <- data.(common.MAVLinkMessage) }) gobot.Once(d.Event("errorIO"), func(data interface{}) { err <- data.(error) }) gobot.Once(d.Event("errorMAVLink"), func(data interface{}) { err <- data.(error) }) gobottest.Assert(t, len(d.Start()), 0) select { case p := <-packet: gobottest.Assert(t, d.SendPacket(p), nil) case <-time.After(100 * time.Millisecond): t.Errorf("packet was not emitted") } select { case <-message: case <-time.After(100 * time.Millisecond): t.Errorf("message was not emitted") } select { case <-err: case <-time.After(100 * time.Millisecond): t.Errorf("error was not emitted") } payload = []byte{0xFE, 0x09, 0x4E, 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x51, 0x04, 0x03, 0x1C, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} select { case e := <-err: gobottest.Assert(t, e, errors.New("Unknown Message ID: 255")) case <-time.After(100 * time.Millisecond): t.Errorf("error was not emitted") } }
// initBoard initializes board by listening for "firware_query", "capability_query" // and "analog_mapping_query" events func (b *board) initBoard() { gobot.Once(b.events["firmware_query"], func(data interface{}) { b.queryCapabilities() }) gobot.Once(b.events["capability_query"], func(data interface{}) { b.queryAnalogMapping() }) gobot.Once(b.events["analog_mapping_query"], func(data interface{}) { b.togglePinReporting(0, high, reportDigital) b.togglePinReporting(1, high, reportDigital) b.connected = true }) }
// AnalogRead retrieves value from analog pin. // Returns -1 if the response from the board has timed out func (f *FirmataAdaptor) AnalogRead(pin string) (val int, err error) { ret := make(chan int) p, err := strconv.Atoi(pin) if err != nil { return } // NOTE pins are numbered A0-A5, which translate to digital pins 14-19 p = f.digitalPin(p) if err = f.board.setPinMode(byte(p), analog); err != nil { return } if err = f.board.togglePinReporting(byte(p), high, reportAnalog); err != nil { return } if err = f.board.readAndProcess(); err != nil { return } gobot.Once(f.board.events[fmt.Sprintf("analog_read_%v", pin)], func(data interface{}) { b := data.([]byte) ret <- int(uint(b[0])<<24 | uint(b[1])<<16 | uint(b[2])<<8 | uint(b[3])) }) select { case data := <-ret: return data, nil case <-time.After(10 * time.Millisecond): } return -1, nil }
// DigitalRead retrieves digital value from specified pin. // Returns -1 if the response from the board has timed out func (f *FirmataAdaptor) DigitalRead(pin string) (val int, err error) { ret := make(chan int) p, err := strconv.Atoi(pin) if err != nil { return } if err = f.board.setPinMode(byte(p), input); err != nil { return } if err = f.board.togglePinReporting(byte(p), high, reportDigital); err != nil { return } if err = f.board.readAndProcess(); err != nil { return } gobot.Once(f.board.events[fmt.Sprintf("digital_read_%v", pin)], func(data interface{}) { ret <- int(data.([]byte)[0]) }) select { case data := <-ret: return data, nil case <-time.After(10 * time.Millisecond): } return -1, nil }
func ExampleOnce() { e := gobot.NewEvent() gobot.Once(e, func(s interface{}) { fmt.Println(s) fmt.Println("I will no longer respond to events") }) gobot.Publish(e, 100) gobot.Publish(e, 200) }
// I2cRead returns size bytes from the i2c device // Returns an empty array if the response from the board has timed out func (f *FirmataAdaptor) I2cRead(address int, size int) (data []byte, err error) { ret := make(chan []byte) if err = f.board.I2cRead(address, size); err != nil { return } gobot.Once(f.board.Event("I2cReply"), func(data interface{}) { ret <- data.(client.I2cReply).Data }) data = <-ret return }
func main() { gbot := gobot.NewGobot() adaptor := mavlink.NewMavlinkAdaptor("iris", "/dev/ttyACM0") iris := mavlink.NewMavlinkDriver(adaptor, "iris") work := func() { gobot.Once(iris.Event("packet"), func(data interface{}) { packet := data.(*common.MAVLinkPacket) dataStream := common.NewRequestDataStream(100, packet.SystemID, packet.ComponentID, 4, 1, ) iris.SendPacket(common.CraftMAVLinkPacket(packet.SystemID, packet.ComponentID, dataStream, )) }) gobot.On(iris.Event("message"), func(data interface{}) { if data.(common.MAVLinkMessage).Id() == 30 { message := data.(*common.Attitude) fmt.Println("Attitude") fmt.Println("TIME_BOOT_MS", message.TIME_BOOT_MS) fmt.Println("ROLL", message.ROLL) fmt.Println("PITCH", message.PITCH) fmt.Println("YAW", message.YAW) fmt.Println("ROLLSPEED", message.ROLLSPEED) fmt.Println("PITCHSPEED", message.PITCHSPEED) fmt.Println("YAWSPEED", message.YAWSPEED) fmt.Println("") } }) } robot := gobot.NewRobot("mavBot", []gobot.Connection{adaptor}, []gobot.Device{iris}, work, ) gbot.AddRobot(robot) gbot.Start() }
// I2cRead returns size bytes from the i2c device // Returns an empty array if the response from the board has timed out func (f *FirmataAdaptor) I2cRead(size uint) (data []byte, err error) { ret := make(chan []byte) if err = f.board.i2cReadRequest(f.i2cAddress, size); err != nil { return } if err = f.board.readAndProcess(); err != nil { return } gobot.Once(f.board.events["i2c_reply"], func(data interface{}) { ret <- data.(map[string][]byte)["data"] }) select { case data := <-ret: return data, nil case <-time.After(10 * time.Millisecond): } return []byte{}, nil }
func TestNeuroskyDriverStart(t *testing.T) { sem := make(chan bool, 0) d := initTestNeuroskyDriver() gobot.Once(d.Event("error"), func(data interface{}) { gobottest.Assert(t, data.(error), errors.New("read error")) sem <- true }) gobottest.Assert(t, len(d.Start()), 0) <-time.After(50 * time.Millisecond) readError = errors.New("read error") select { case <-sem: case <-time.After(100 * time.Millisecond): { t.Errorf("error was not emitted") } } }
func TestButtonDriverStart(t *testing.T) { sem := make(chan bool, 0) d := initTestButtonDriver() gobot.Assert(t, len(d.Start()), 0) testAdaptorDigitalRead = func() (val int, err error) { val = 1 return } gobot.Once(d.Event(Push), func(data interface{}) { gobot.Assert(t, d.Active, true) sem <- true }) select { case <-sem: case <-time.After(15 * time.Millisecond): t.Errorf("Button Event \"Push\" was not published") } testAdaptorDigitalRead = func() (val int, err error) { val = 0 return } gobot.Once(d.Event(Release), func(data interface{}) { gobot.Assert(t, d.Active, false) sem <- true }) select { case <-sem: case <-time.After(15 * time.Millisecond): t.Errorf("Button Event \"Release\" was not published") } testAdaptorDigitalRead = func() (val int, err error) { err = errors.New("digital read error") return } gobot.Once(d.Event(Error), func(data interface{}) { sem <- true }) select { case <-sem: case <-time.After(15 * time.Millisecond): t.Errorf("Button Event \"Error\" was not published") } testAdaptorDigitalRead = func() (val int, err error) { val = 1 return } gobot.Once(d.Event(Push), func(data interface{}) { sem <- true }) d.halt <- true select { case <-sem: t.Errorf("Button Event \"Press\" should not published") case <-time.After(15 * time.Millisecond): } }
func TestProcess(t *testing.T) { sem := make(chan bool) b := initTestFirmata() tests := []struct { event string data []byte expected interface{} init func() }{ { event: "ProtocolVersion", data: []byte{249, 2, 3}, expected: "2.3", init: func() {}, }, { event: "AnalogRead0", data: []byte{0xE0, 0x23, 0x05}, expected: 675, init: func() {}, }, { event: "AnalogRead1", data: []byte{0xE1, 0x23, 0x06}, expected: 803, init: func() {}, }, { event: "DigitalRead2", data: []byte{0x90, 0x04, 0x00}, expected: 1, init: func() { b.pins[2].Mode = Input }, }, { event: "DigitalRead4", data: []byte{0x90, 0x16, 0x00}, expected: 1, init: func() { b.pins[4].Mode = Input }, }, { event: "PinState13", data: []byte{240, 110, 13, 1, 1, 247}, expected: Pin{[]int{0, 1, 4}, 1, 0, 1, 127}, init: func() {}, }, { event: "I2cReply", data: []byte{240, 119, 9, 0, 0, 0, 24, 1, 1, 0, 26, 1, 247}, expected: I2cReply{ Address: 9, Register: 0, Data: []byte{152, 1, 154}, }, init: func() {}, }, { event: "FirmwareQuery", data: []byte{240, 121, 2, 3, 83, 0, 116, 0, 97, 0, 110, 0, 100, 0, 97, 0, 114, 0, 100, 0, 70, 0, 105, 0, 114, 0, 109, 0, 97, 0, 116, 0, 97, 0, 46, 0, 105, 0, 110, 0, 111, 0, 247}, expected: "StandardFirmata.ino", init: func() {}, }, { event: "StringData", data: append([]byte{240, 0x71}, append([]byte("Hello Firmata!"), 247)...), expected: "Hello Firmata!", init: func() {}, }, } for _, test := range tests { test.init() gobot.Once(b.Event(test.event), func(data interface{}) { gobot.Assert(t, data, test.expected) sem <- true }) testReadData = test.data go b.process() select { case <-sem: case <-time.After(10 * time.Millisecond): t.Errorf("%v was not published", test.event) } } }
func main() { if gobot.Version() != "0.7.dev" { panic("this requires the dev branch!") } summary := &telemetry{Status: "STANDBY"} gbot := gobot.NewGobot() a := api.NewAPI(gbot) a.Get("/mavlink/:a", func(res http.ResponseWriter, req *http.Request) { path := req.URL.Path t := strings.Split(path, "/") buf, err := Asset("assets/" + t[2]) if err != nil { http.Error(res, err.Error(), http.StatusNotFound) 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) }) adaptor := mavlink.NewMavlinkAdaptor("iris", "/dev/ttyACM0") iris := mavlink.NewMavlinkDriver(adaptor, "iris") work := func() { iris.AddEvent("telemetry") gobot.Once(iris.Event("packet"), func(data interface{}) { fmt.Println(data) packet := data.(*common.MAVLinkPacket) dataStream := common.NewRequestDataStream(10, packet.SystemID, packet.ComponentID, 0, 1, ) iris.SendPacket(common.CraftMAVLinkPacket(packet.SystemID, packet.ComponentID, dataStream, )) }) gobot.On(iris.Event("message"), func(data interface{}) { fmt.Println("message: ", data.(common.MAVLinkMessage).Id()) if data.(common.MAVLinkMessage).Id() == 0 { statusCodes := map[uint8]string{ 1: "BOOT", 2: "CALIBRATING", 3: "STANDBY", 4: "ACTIVE", 5: "CRITICAL", 6: "EMERGENCY", 7: "POWEROFF", 8: "ENUM_END", } summary.Status = statusCodes[data.(*common.Heartbeat).SYSTEM_STATUS] if summary.Status != "" { gobot.Publish(iris.Event("telemetry"), summary) } } if data.(common.MAVLinkMessage).Id() == 30 { roll := data.(*common.Attitude).ROLL pitch := data.(*common.Attitude).PITCH yaw := data.(*common.Attitude).YAW if roll < 4 || roll > -4 { summary.Roll = (roll * 180 / 3.14) } if yaw < 4 || roll > -4 { summary.Yaw = (yaw * 180 / 3.14) } if pitch < 4 || roll > -4 { summary.Pitch = (pitch * 180 / 3.14) } gobot.Publish(iris.Event("telemetry"), summary) } if data.(common.MAVLinkMessage).Id() == 33 { summary.Latitude = float32(data.(*common.GlobalPositionInt).LAT) / 10000000.0 summary.Longitude = float32(data.(*common.GlobalPositionInt).LON) / 10000000.0 summary.Altitude = data.(*common.GlobalPositionInt).ALT summary.Heading = float32(data.(*common.GlobalPositionInt).HDG) / 100 gobot.Publish(iris.Event("telemetry"), summary) } }) } gbot.AddRobot(gobot.NewRobot("irisBot", []gobot.Connection{adaptor}, []gobot.Device{iris}, work, )) a.Start() gbot.Start() }