Share
Embed
Transcript
136 slides
-
CodeDaze Episode II It is a dark time for the
galaxy. The new GO ORDER has seized power over the systems, imposing it’s diabolical rules on the population. Space battles are being fought across the galaxy and the TAB fighters are winning. The ORDER has been busy converting historic libraries, compiling their scripts into new libraries that will bend to the will of GO. With the support of a large group of fanatic and loyal followers it seems all other languages will be lost to the might of the ORDER. But a small RUBY ALLIANCE has plans to hijack the ORDER’s Goroutines and in doing so, embed itself into their droid network. A difficult task lies ahead... A surprisingly short time ago, when this conference was not too far away... -
These are the droids you're looking for... August 2017 Sphero
Announces R2-D2 -
• Sphero support* • *Only Bluetooth Classic • No support
for BLE! • No BB8! GitHub issue #165 Artoo -
BB8 Hello World func main() { bleAdaptor := ble.NewClientAdaptor(os.Args[1]) bb8
:= bb8.NewDriver(bleAdaptor) work := func() { gobot.Every(1*time.Second, func() { r := uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) bb8.SetRGB(r, g, b) }) } robot := gobot.NewRobot("bb", []gobot.Connection{bleAdaptor}, []gobot.Device{bb8}, work, ) robot.Start() } -
gobot.NewRobot() work := func() { gobot.Every(1*time.Second, func() { r :=
uint8(gobot.Rand(255)) g := uint8(gobot.Rand(255)) b := uint8(gobot.Rand(255)) bb8.SetRGB(r, g, b) }) } robot := gobot.NewRobot("bb", []gobot.Connection{bleAdaptor}, []gobot.Device{bb8}, work, ) robot.Start() -
Terminology • BLE - Bluetooth Low Energy ◦ Modern Bluetooth
4.* spec • GATT - Generic Attribute ◦ Like a BLE plugin system -
Services • Encapsulate the behavior of part of a device
• Collection of data and associated behaviors -
Characteristics • The API of a service • The “endpoints”
to control a device -
gatttool $ sudo hcitool lescan LE Scan ... DF:59:60:07:1F:3B D2-1F3B
$ gatttool -b DF:59:60:07:1F:3B -I [DF:59:60:07:1F:3B][LE]> connect Attempting to connect to DF:59:60:07:1F:3B Connection successful -
gatttool $ sudo hcitool lescan LE Scan ... DF:59:60:07:1F:3B D2-1F3B
$ gatttool -b DF:59:60:07:1F:3B -I [DF:59:60:07:1F:3B][LE]> connect Attempting to connect to DF:59:60:07:1F:3B Connection successful [DF:59:60:07:1F:3B][LE]> (gatttool:11398): GLib-WARNING **: Invalid file descriptor. -
BLE Packet Sniffing (Android 8+) FS > data > misc
> bluetooth > logs -
• Reset logfiles • Send a command from the app
• Dump logfiles • Load and find command • Record value • Repeat • Repeat again • ...and again Extracting Commands -
Look for patterns Tripod - 8d:0a:17:0d:01:01:cf:d8 Bipod - 8d:0a:17:0d:02:02:cd:d8 Tripod
- 8d:0a:17:0d:03:01:cd:d8 Bipod - 8d:0a:17:0d:04:02:cb:d8 Tripod - 8d:0a:17:0d:05:01:cb:d8 -
Look for patterns Tripod - 8d:0a:17:0d:01:01:cf:d8 Bipod - 8d:0a:17:0d:02:02:cd:d8 Tripod
- 8d:0a:17:0d:03:01:cd:d8 Bipod - 8d:0a:17:0d:04:02:cb:d8 Tripod - 8d:0a:17:0d:05:01:cb:d8 Same for all -
Look for patterns Tripod - 8d:0a:17:0d:01:01:cf:d8 Bipod - 8d:0a:17:0d:02:02:cd:d8 Tripod
- 8d:0a:17:0d:03:01:cd:d8 Bipod - 8d:0a:17:0d:04:02:cb:d8 Tripod - 8d:0a:17:0d:05:01:cb:d8 Changing -
Look for patterns Tripod - 8d:0a:17:0d:01:01:cf:d8 Bipod - 8d:0a:17:0d:02:02:cd:d8 Tripod
- 8d:0a:17:0d:03:01:cd:d8 Bipod - 8d:0a:17:0d:04:02:cb:d8 Tripod - 8d:0a:17:0d:05:01:cb:d8 Sequence -
Look for patterns Tripod - 8d:0a:17:0d:01:01:cf:d8 Bipod - 8d:0a:17:0d:02:02:cd:d8 Tripod
- 8d:0a:17:0d:03:01:cd:d8 Bipod - 8d:0a:17:0d:04:02:cb:d8 Tripod - 8d:0a:17:0d:05:01:cb:d8 Command Value -
Look for patterns Tripod - 8d:0a:17:0d:01:01:cf:d8 Bipod - 8d:0a:17:0d:02:02:cd:d8 Tripod
- 8d:0a:17:0d:03:01:cd:d8 Bipod - 8d:0a:17:0d:04:02:cb:d8 Tripod - 8d:0a:17:0d:05:01:cb:d8 Checksum ~((0x0a + 0x17 + 0x0d + 0x05 + 0x01) % 0xFF) = 0xcb -
R2D2 Driver package r2d2 type Driver struct { name string
connection gobot.Connection seq uint8 mtx sync.Mutex collisionResponse []uint8 packetChannel chan *packet gobot.Eventer } func (b *Driver) Tripod() { log.Print("Tripod") b.packetChannel <- b.craftPacket(0x17, 0x0d, []uint8{0x01}) } -
func (b *Driver) Tripod() { log.Print("Tripod") b.packetChannel <- b.craftPacket(0x17, 0x0d,
[]uint8{0x01}) } func (b *Driver) craftPacket(did byte, cid byte, body []uint8) *packet { b.mtx.Lock() defer b.mtx.Unlock() packet := new(packet) packet.header = []uint8{0x8d, 0x0a, did, cid, b.seq} packet.body = body packet.checksum = b.calculateChecksum(packet) packet.footer = []uint8{0xd8} return packet } craftPacket 8d:0a:17:0d:01:01:cf:d8 -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
go-mruby Hello World func main() { mrb := mruby.NewMrb() defer
mrb.Close() addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) { args := m.GetArgs() return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil } class := mrb.DefineClass("Example", nil) class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2)) result, err := mrb.LoadString(`Example.add(12, 30)`) if err != nil { panic(err.Error()) } fmt.Printf("Result: %s\n", result.String()) } -
1. go-mruby: Builds libmruby.a - MRUBY_CONFIG allows us to specify
our own build_config.rb Build Process MRuby::Build.new do |conf| toolchain :gcc conf.gem :git => 'https://github.com/matsumoto-r/mruby-sleep.git' conf.gem :core => 'mruby-random' conf.gembox 'default' end -
1. go-mruby: Builds libmruby.a - MRUBY_CONFIG allows us to specify
our own build_config.rb - vendor mruby: clones mruby from github - build mruby - copy libmruby.a out Build Process -
1. go-mruby: Builds libmruby.a - MRUBY_CONFIG allows us to specify
our own build_config.rb - vendor mruby: clones mruby from github - build mruby - copy libmruby.a out 2. `go build` links against libmruby.a using Cgo Build Process // #cgo CFLAGS: -Ivendor/mruby/include // #cgo LDFLAGS: ${SRCDIR}/libmruby.a -lm import "C" -
Vision • Only need to write Ruby • Extensible (leverage
existing work) • Coordinate multiple async tasks • Utilize Actor model ◦ Droids as actors ◦ Droid components as actors • Actors pass messages to communicate intents -
r2d2_dome.mrb droid = R2D2.new("D2-1F3B") heading = 0; direction = -1
while true do droid.dome(heading) direction = -1 if heading >= 180 direction = 1 if heading <= -160 heading = heading + direction Sleep::usleep(100) end -
r2d2_dome.mrb droid = R2D2.new("D2-1F3B") heading = 0; direction = -1
while true do droid.dome(heading) direction = -1 if heading >= 180 direction = 1 if heading <= -160 heading = heading + direction Sleep::usleep(100) end -
r2d2_dome.mrb droid = R2D2.new("D2-1F3B") heading = 0; direction = -1
while true do droid.dome(heading) direction = -1 if heading >= 180 direction = 1 if heading <= -160 heading = heading + direction Sleep::usleep(100) end -
startWorker() func main() { var wg sync.WaitGroup table := NewDroidTable()
argsWithoutProg := os.Args[1:] for _, mrbFile := range argsWithoutProg { startWorker(mrbFile, table, &wg) } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c for _ = range argsWithoutProg { wg.Done() } }() wg.Wait() } -
startWorker() func main() { var wg sync.WaitGroup table := NewDroidTable()
argsWithoutProg := os.Args[1:] for _, mrbFile := range argsWithoutProg { startWorker(mrbFile, table, &wg) } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c for _ = range argsWithoutProg { wg.Done() } }() wg.Wait() } -
startWorker() func main() { var wg sync.WaitGroup table := NewDroidTable()
argsWithoutProg := os.Args[1:] for _, mrbFile := range argsWithoutProg { startWorker(mrbFile, table, &wg) } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c for _ = range argsWithoutProg { wg.Done() } }() wg.Wait() } -
startWorker() func startWorker(file string, table droidTable, wg *sync.WaitGroup) { wg.Add(1)
go func() { mrb := mruby.NewMrb() defer mrb.Close() droids.NewR2D2(table.r2d2, mrb) droids.NewBB8(table.bb8, mrb) dat, err := ioutil.ReadFile(file) content := string(dat) result, err := mrb.LoadString(content) fmt.Printf("Done: %s\n", result) }() } -
startWorker() func startWorker(file string, table droidTable, wg *sync.WaitGroup) { wg.Add(1)
go func() { mrb := mruby.NewMrb() defer mrb.Close() droids.NewR2D2(table.r2d2, mrb) droids.NewBB8(table.bb8, mrb) dat, err := ioutil.ReadFile(file) content := string(dat) result, err := mrb.LoadString(content) fmt.Printf("Done: %s\n", result) }() } -
startWorker() func startWorker(file string, table droidTable, wg *sync.WaitGroup) { wg.Add(1)
go func() { mrb := mruby.NewMrb() defer mrb.Close() droids.NewR2D2(table.r2d2, mrb) droids.NewBB8(table.bb8, mrb) dat, err := ioutil.ReadFile(file) content := string(dat) result, err := mrb.LoadString(content) fmt.Printf("Done: %s\n", result) }() } -
startWorker() func startWorker(file string, table droidTable, wg *sync.WaitGroup) { wg.Add(1)
go func() { mrb := mruby.NewMrb() defer mrb.Close() droids.NewR2D2(table.r2d2, mrb) droids.NewBB8(table.bb8, mrb) dat, err := ioutil.ReadFile(file) content := string(dat) result, err := mrb.LoadString(content) fmt.Printf("Done: %s\n", result) }() } -
Define mruby Classes func startWorker(file string, table droidTable, wg *sync.WaitGroup)
{ wg.Add(1) go func() { mrb := mruby.NewMrb() defer mrb.Close() droids.NewR2D2(table.r2d2, mrb) droids.NewBB8(table.bb8, mrb) dat, err := ioutil.ReadFile(file) content := string(dat) result, err := mrb.LoadString(content) fmt.Printf("Done: %s\n", result) }() } -
Define mruby Classes func NewR2D2(table map[string]*gobotR2D2.Driver, mrb *mruby.Mrb) *r2d2 {
droids := r2d2{ table: table, } class := mrb.DefineClass("R2D2", nil) _, err := mrb.LoadString(` class R2D2 attr_accessor :name end `) class.DefineMethod("initialize", droids.Initialize, mruby.ArgsReq(1)) class.DefineMethod("dome", droids.Dome, mruby.ArgsReq(1)) class.DefineMethod("tripod", droids.Tripod, mruby.ArgsReq(0)) class.DefineMethod("bipod", droids.Bipod, mruby.ArgsReq(0)) class.DefineMethod("macro", droids.Macro, mruby.ArgsReq(1)) class.DefineMethod("move", droids.Move, mruby.ArgsReq(2)) return &droids } -
Define mruby Classes func NewR2D2(table map[string]*gobotR2D2.Driver, mrb *mruby.Mrb) *r2d2 {
droids := r2d2{ table: table, } class := mrb.DefineClass("R2D2", nil) _, err := mrb.LoadString(` class R2D2 attr_accessor :name end `) class.DefineMethod("initialize", droids.Initialize, mruby.ArgsReq(1)) class.DefineMethod("dome", droids.Dome, mruby.ArgsReq(1)) class.DefineMethod("tripod", droids.Tripod, mruby.ArgsReq(0)) class.DefineMethod("bipod", droids.Bipod, mruby.ArgsReq(0)) class.DefineMethod("macro", droids.Macro, mruby.ArgsReq(1)) class.DefineMethod("move", droids.Move, mruby.ArgsReq(2)) return &droids } -
startWorker func startWorker(file string, table droidTable, wg *sync.WaitGroup) { wg.Add(1)
go func() { mrb := mruby.NewMrb() defer mrb.Close() droids.NewR2D2(table.r2d2, mrb) droids.NewBB8(table.bb8, mrb) dat, err := ioutil.ReadFile(file) content := string(dat) result, err := mrb.LoadString(content) fmt.Printf("Done: %s\n", result) }() } -
R2D2.new droid = R2D2.new("D2-1F3B") heading = 0 direction = -1
while true do droid.dome(heading) direction = -1 if heading >= 180 direction = 1 if heading <= -160 heading = heading + direction Sleep::usleep(100) end -
R2D2.new func NewR2D2(table map[string]*gobotR2D2.Driver, mrb *mruby.Mrb) *r2d2 { droids :=
r2d2{ table: table, } class := mrb.DefineClass("R2D2", nil) _, err := mrb.LoadString(` class R2D2 attr_accessor :name end `) class.DefineMethod("initialize", droids.Initialize, mruby.ArgsReq(1)) class.DefineMethod("dome", droids.Dome, mruby.ArgsReq(1)) class.DefineMethod("tripod", droids.Tripod, mruby.ArgsReq(0)) class.DefineMethod("bipod", droids.Bipod, mruby.ArgsReq(0)) class.DefineMethod("macro", droids.Macro, mruby.ArgsReq(1)) class.DefineMethod("move", droids.Move, mruby.ArgsReq(2)) return &droids } -
R2D2.new func (droids *r2d2) Initialize(mrb *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value)
{ args := mrb.GetArgs() name := string(args[0].String()) bleAdaptor := ble.NewClientAdaptor(name) droidDriver := gobotR2D2.NewDriver(bleAdaptor) droids.table[name] = droidDriver self.Call("name=", args[0]) var wg sync.WaitGroup wg.Add(1) work := func() { wg.Done() } robot := gobot.NewRobot("R2D2", []gobot.Connection{bleAdaptor}, []gobot.Device{droidDriver}, work) go robot.Start() wg.Wait() return self, nil } -
R2D2.new func (droids *r2d2) Initialize(mrb *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value)
{ args := mrb.GetArgs() name := string(args[0].String()) bleAdaptor := ble.NewClientAdaptor(name) droidDriver := gobotR2D2.NewDriver(bleAdaptor) droids.table[name] = droidDriver self.Call("name=", args[0]) var wg sync.WaitGroup wg.Add(1) work := func() { wg.Done() } robot := gobot.NewRobot("R2D2", []gobot.Connection{bleAdaptor}, []gobot.Device{droidDriver}, work) go robot.Start() wg.Wait() return self, nil } -
R2D2.new func (droids *r2d2) Initialize(mrb *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value)
{ args := mrb.GetArgs() name := string(args[0].String()) bleAdaptor := ble.NewClientAdaptor(name) droidDriver := gobotR2D2.NewDriver(bleAdaptor) droids.table[name] = droidDriver self.Call("name=", args[0]) var wg sync.WaitGroup wg.Add(1) work := func() { wg.Done() } robot := gobot.NewRobot("R2D2", []gobot.Connection{bleAdaptor}, []gobot.Device{droidDriver}, work) go robot.Start() wg.Wait() return self, nil } -
dome() in mruby droid = R2D2.new("D2-1F3B") heading = 0; direction
= -1 while true do droid.dome(heading) direction = -1 if heading >= 180 direction = 1 if heading <= -160 heading = heading + direction Sleep::usleep(100) end -
dome() in mruby func NewR2D2(table map[string]*gobotR2D2.Driver, mrb *mruby.Mrb) *r2d2 {
droids := r2d2{ table: table, } class := mrb.DefineClass("R2D2", nil) _, err := mrb.LoadString(` class R2D2 attr_accessor :name end `) class.DefineMethod("initialize", droids.Initialize, mruby.ArgsReq(1)) class.DefineMethod("dome", droids.Dome, mruby.ArgsReq(1)) class.DefineMethod("tripod", droids.Tripod, mruby.ArgsReq(0)) class.DefineMethod("bipod", droids.Bipod, mruby.ArgsReq(0)) class.DefineMethod("macro", droids.Macro, mruby.ArgsReq(1)) class.DefineMethod("move", droids.Move, mruby.ArgsReq(2)) return &droids } -
Dome() in DeeToo func (droids *r2d2) Dome(mrb *mruby.Mrb, self *mruby.MrbValue)
(mruby.Value, mruby.Value) { args := mrb.GetArgs() heading := int16(args[0].Fixnum()) droids.driver(self).Dome(heading) return nil, nil } -
Dome() in DeeToo func (droids *r2d2) Dome(mrb *mruby.Mrb, self *mruby.MrbValue)
(mruby.Value, mruby.Value) { args := mrb.GetArgs() heading := int16(args[0].Fixnum()) droids.driver(self).Dome(heading) return nil, nil } -
Dome() in gobot R2D2 Driver func (b *Driver) Dome(heading int16)
{ log.Printf("Dome - heading: %v", heading) encoded,_ := EncodeSixShifted(heading) b.packetChannel <- b.craftPacket(0x17, 0x0f, append(encoded, 0x00, 0x00)) } -
Droid Table func main() { var wg sync.WaitGroup table :=
NewDroidTable() argsWithoutProg := os.Args[1:] for _, mrbFile := range argsWithoutProg { startWorker(mrbFile, table, &wg) } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c for _ = range argsWithoutProg { wg.Done() } }() wg.Wait() } -
Droid Table func main() { var wg sync.WaitGroup table :=
NewDroidTable() argsWithoutProg := os.Args[1:] for _, mrbFile := range argsWithoutProg { startWorker(mrbFile, table, &wg) } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c for _ = range argsWithoutProg { wg.Done() } }() wg.Wait() } -
Droid Table type droidTable struct { bb8 map[string]*bb8.BB8Driver r2d2 map[string]*r2d2.Driver
} func NewDroidTable() droidTable { table := droidTable{ bb8: make(map[string]*bb8.BB8Driver), r2d2: make(map[string]*r2d2.Driver), } return table } -
Droid Table func main() { var wg sync.WaitGroup table :=
NewDroidTable() argsWithoutProg := os.Args[1:] for _, mrbFile := range argsWithoutProg { startWorker(mrbFile, table, &wg) } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c for _ = range argsWithoutProg { wg.Done() } }() wg.Wait() } -
Droid Table func startWorker(file string, table droidTable, wg *sync.WaitGroup) {
wg.Add(1) go func() { mrb := mruby.NewMrb() defer mrb.Close() droids.NewR2D2(table.r2d2, mrb) droids.NewBB8(table.bb8, mrb) dat, err := ioutil.ReadFile(file) content := string(dat) result, err := mrb.LoadString(content) fmt.Printf("Done: %s\n", result) }() } -
Droid Table func (droids *r2d2) Initialize(mrb *mruby.Mrb, self *mruby.MrbValue) (mruby.Value,
mruby.Value) { args := mrb.GetArgs() name := string(args[0].String()) bleAdaptor := ble.NewClientAdaptor(name) droidDriver := gobotR2D2.NewDriver(bleAdaptor) droids.table[name] = droidDriver self.Call("name=", args[0]) var wg sync.WaitGroup wg.Add(1) work := func() { wg.Done() } robot := gobot.NewRobot("R2D2", []gobot.Connection{bleAdaptor}, []gobot.Device{droidDriver}, work) go robot.Start() wg.Wait() return self, nil } -
Droid Table func NewR2D2(table map[string]*gobotR2D2.Driver, mrb *mruby.Mrb) *r2d2 { droids
:= r2d2{ table: table, } class := mrb.DefineClass("R2D2", nil) _, err := mrb.LoadString(` class R2D2 attr_accessor :name end `) class.DefineMethod("initialize", droids.Initialize, mruby.ArgsReq(1)) class.DefineMethod("dome", droids.Dome, mruby.ArgsReq(1)) class.DefineMethod("tripod", droids.Tripod, mruby.ArgsReq(0)) class.DefineMethod("bipod", droids.Bipod, mruby.ArgsReq(0)) class.DefineMethod("macro", droids.Macro, mruby.ArgsReq(1)) class.DefineMethod("move", droids.Move, mruby.ArgsReq(2)) return &droids } -
Droid Table func (droids *r2d2) driver(mrbInstance *mruby.MrbValue) *gobotR2D2.Driver { value,
err := mrbInstance.Call("name") var driver *gobotR2D2.Driver if err != nil { panic(err.Error()) } else { ident := string(value.String()) driver = droids.table[ident] } return driver } -
Droid Table func (droids *r2d2) driver(mrbInstance *mruby.MrbValue) *gobotR2D2.Driver { value,
err := mrbInstance.Call("name") var driver *gobotR2D2.Driver if err != nil { panic(err.Error()) } else { ident := string(value.String()) driver = droids.table[ident] } return driver } -
Future/Roadmap • Single binary by compiling the mruby byte code
into libmruby.a • Cross compiling the deetoo tool • Message passing between mrb files