From 8f79c322e0bf81dd9d4daf3731b29b568f58ac7b Mon Sep 17 00:00:00 2001 From: Hrishikesh Tapaswi Date: Sat, 30 Jan 2016 02:00:27 -0800 Subject: [PATCH] Add support for the CHIP platform This includes support for GPIO and I2C interfaces. Signed-off-by: Hrishikesh Tapaswi --- examples/chip_blink.go | 32 ++++++ examples/chip_button.go | 34 +++++++ examples/chip_wiichuck.go | 40 ++++++++ platforms/chip/README.md | 72 ++++++++++++++ platforms/chip/chip_adaptor.go | 148 ++++++++++++++++++++++++++++ platforms/chip/chip_adaptor_test.go | 81 +++++++++++++++ platforms/chip/doc.go | 7 ++ 7 files changed, 414 insertions(+) create mode 100644 examples/chip_blink.go create mode 100644 examples/chip_button.go create mode 100644 examples/chip_wiichuck.go create mode 100644 platforms/chip/README.md create mode 100644 platforms/chip/chip_adaptor.go create mode 100644 platforms/chip/chip_adaptor_test.go create mode 100644 platforms/chip/doc.go diff --git a/examples/chip_blink.go b/examples/chip_blink.go new file mode 100644 index 00000000..26cc94d4 --- /dev/null +++ b/examples/chip_blink.go @@ -0,0 +1,32 @@ +package main + +import ( + "time" + + "github.com/hybridgroup/gobot" + "github.com/hybridgroup/gobot/platforms/chip" + "github.com/hybridgroup/gobot/platforms/gpio" +) + +func main() { + gbot := gobot.NewGobot() + + chipAdaptor := chip.NewChipAdaptor("chip") + led := gpio.NewLedDriver(chipAdaptor, "led", "U14_13") + + work := func() { + gobot.Every(1*time.Second, func() { + led.Toggle() + }) + } + + robot := gobot.NewRobot("blinkBot", + []gobot.Connection{chipAdaptor}, + []gobot.Device{led}, + work, + ) + + gbot.AddRobot(robot) + + gbot.Start() +} diff --git a/examples/chip_button.go b/examples/chip_button.go new file mode 100644 index 00000000..17f4e968 --- /dev/null +++ b/examples/chip_button.go @@ -0,0 +1,34 @@ +package main + +import ( + "fmt" + + "github.com/hybridgroup/gobot" + "github.com/hybridgroup/gobot/platforms/chip" + "github.com/hybridgroup/gobot/platforms/gpio" +) + +func main() { + gbot := gobot.NewGobot() + + chipAdaptor := chip.NewChipAdaptor("chip") + button := gpio.NewButtonDriver(chipAdaptor, "button", "U14_13") + + work := func() { + gobot.On(button.Event("push"), func(data interface{}) { + fmt.Println("button pressed") + }) + + gobot.On(button.Event("release"), func(data interface{}) { + fmt.Println("button released") + }) + } + + robot := gobot.NewRobot("buttonBot", + []gobot.Connection{chipAdaptor}, + []gobot.Device{button}, + work, + ) + gbot.AddRobot(robot) + gbot.Start() +} diff --git a/examples/chip_wiichuck.go b/examples/chip_wiichuck.go new file mode 100644 index 00000000..ac601c8a --- /dev/null +++ b/examples/chip_wiichuck.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + + "github.com/hybridgroup/gobot" + "github.com/hybridgroup/gobot/platforms/chip" + "github.com/hybridgroup/gobot/platforms/i2c" +) + +func main() { + gbot := gobot.NewGobot() + + chipAdaptor := chip.NewChipAdaptor("chip") + wiichuck := i2c.NewWiichuckDriver(chipAdaptor, "wiichuck") + + work := func() { + gobot.On(wiichuck.Event("joystick"), func(data interface{}) { + fmt.Println("joystick", data) + }) + + gobot.On(wiichuck.Event("c"), func(data interface{}) { + fmt.Println("c") + }) + + gobot.On(wiichuck.Event("z"), func(data interface{}) { + fmt.Println("z") + }) + } + + robot := gobot.NewRobot("chuck", + []gobot.Connection{chipAdaptor}, + []gobot.Device{wiichuck}, + work, + ) + + gbot.AddRobot(robot) + + gbot.Start() +} diff --git a/platforms/chip/README.md b/platforms/chip/README.md new file mode 100644 index 00000000..d154a1d5 --- /dev/null +++ b/platforms/chip/README.md @@ -0,0 +1,72 @@ +# CHIP + +The [CHIP](http://www.getchip.com/) is a small, inexpensive ARM based single board computer, with many different IO interfaces available on the [pin headers](http://docs.getchip.com/#pin-headers). + +For documentation about the CHIP platform click [here](http://docs.getchip.com/). + +## How to Install +``` +go get -d -u github.com/hybridgroup/gobot/... && go install github.com/hybridgroup/gobot/platforms/chip +``` + +## Cross compiling for the CHIP +If you're using Go version earlier than 1.5, you must first configure your Go environment for ARM linux cross compiling. + +```bash +$ cd $GOROOT/src +$ GOOS=linux GOARCH=arm ./make.bash --no-clean +``` + +The above step is not required for Go >= 1.5 + +Then compile your Gobot program with + +```bash +$ GOARM=7 GOARCH=arm GOOS=linux go build examples/chip_button.go +``` + +Then you can simply upload your program to the CHIP and execute it with + +```bash +$ scp chip_button root@192.168.1.xx: +$ ssh -t root@192.168.1.xx "./chip_button" +``` + +## How to Use + +```go +package main + +import ( + "fmt" + + "github.com/hybridgroup/gobot" + "github.com/hybridgroup/gobot/platforms/chip" + "github.com/hybridgroup/gobot/platforms/gpio" +) + +func main() { + gbot := gobot.NewGobot() + + chipAdaptor := chip.NewChipAdaptor("chip") + button := gpio.NewButtonDriver(chipAdaptor, "button", "U14_13") + + work := func() { + gobot.On(button.Event("push"), func(data interface{}) { + fmt.Println("button pressed") + }) + + gobot.On(button.Event("release"), func(data interface{}) { + fmt.Println("button released") + }) + } + + robot := gobot.NewRobot("buttonBot", + []gobot.Connection{chipAdaptor}, + []gobot.Device{button}, + work, + ) + gbot.AddRobot(robot) + gbot.Start() +} +``` diff --git a/platforms/chip/chip_adaptor.go b/platforms/chip/chip_adaptor.go new file mode 100644 index 00000000..e364967e --- /dev/null +++ b/platforms/chip/chip_adaptor.go @@ -0,0 +1,148 @@ +package chip + +import ( + "errors" + + "github.com/hybridgroup/gobot" + "github.com/hybridgroup/gobot/platforms/gpio" + "github.com/hybridgroup/gobot/platforms/i2c" + "github.com/hybridgroup/gobot/sysfs" +) + +var _ gobot.Adaptor = (*ChipAdaptor)(nil) + +var _ gpio.DigitalReader = (*ChipAdaptor)(nil) +var _ gpio.DigitalWriter = (*ChipAdaptor)(nil) + +var _ i2c.I2c = (*ChipAdaptor)(nil) + +type ChipAdaptor struct { + name string + digitalPins map[int]sysfs.DigitalPin + i2cDevice sysfs.I2cDevice +} + +var pins = map[string]int{ + "U14_13": 408, + "U14_14": 409, + "U14_15": 410, + "U14_16": 411, + "U14_17": 412, + "U14_18": 413, + "U14_19": 414, + "U14_20": 415, +} + +// NewChipAdaptor creates a ChipAdaptor with the specified name +func NewChipAdaptor(name string) *ChipAdaptor { + c := &ChipAdaptor{ + name: name, + digitalPins: make(map[int]sysfs.DigitalPin), + } + return c +} + +// Name returns the name of the ChipAdaptor +func (c *ChipAdaptor) Name() string { return c.name } + +// Connect initializes the board +func (c *ChipAdaptor) Connect() (errs []error) { + return +} + +// Finalize closes connection to board and pins +func (c *ChipAdaptor) Finalize() (errs []error) { + for _, pin := range c.digitalPins { + if pin != nil { + if err := pin.Unexport(); err != nil { + errs = append(errs, err) + } + } + } + if c.i2cDevice != nil { + if err := c.i2cDevice.Close(); err != nil { + errs = append(errs, err) + } + } + return errs +} + +func (c *ChipAdaptor) translatePin(pin string) (i int, err error) { + if val, ok := pins[pin]; ok { + i = val + } else { + err = errors.New("Not a valid pin") + } + return +} + +// digitalPin returns matched digitalPin for specified values +func (c *ChipAdaptor) digitalPin(pin string, dir string) (sysfsPin sysfs.DigitalPin, err error) { + i, err := c.translatePin(pin) + + if err != nil { + return + } + + if c.digitalPins[i] == nil { + c.digitalPins[i] = sysfs.NewDigitalPin(i) + if err = c.digitalPins[i].Export(); err != nil { + return + } + } + + if err = c.digitalPins[i].Direction(dir); err != nil { + return + } + + return c.digitalPins[i], nil +} + +// DigitalRead reads digital value from the specified pin. +// Valids pins are XIO-P0 through XIO-P1 (pins 13-20 on header 14). +func (c *ChipAdaptor) DigitalRead(pin string) (val int, err error) { + sysfsPin, err := c.digitalPin(pin, sysfs.IN) + if err != nil { + return + } + return sysfsPin.Read() +} + +// DigitalWrite writes digital value to the specified pin. +// Valids pins are XIO-P0 through XIO-P1 (pins 13-20 on header 14). +func (c *ChipAdaptor) DigitalWrite(pin string, val byte) (err error) { + sysfsPin, err := c.digitalPin(pin, sysfs.OUT) + if err != nil { + return err + } + return sysfsPin.Write(int(val)) +} + +// I2cStart starts an i2c device in specified address. +// This assumes that the bus used is /dev/i2c-1, which corresponds to +// pins labeled TWI1 (pins 9 and 11 on header 13). +func (c *ChipAdaptor) I2cStart(address int) (err error) { + if c.i2cDevice == nil { + c.i2cDevice, err = sysfs.NewI2cDevice("/dev/i2c-1", address) + } + return err +} + +// I2cWrite writes data to i2c device +func (c *ChipAdaptor) I2cWrite(address int, data []byte) (err error) { + if err = c.i2cDevice.SetAddress(address); err != nil { + return + } + _, err = c.i2cDevice.Write(data) + return +} + +// I2cRead returns value from i2c device using specified size +func (c *ChipAdaptor) I2cRead(address int, size int) (data []byte, err error) { + if err = c.i2cDevice.SetAddress(address); err != nil { + return + } + data = make([]byte, size) + _, err = c.i2cDevice.Read(data) + return +} diff --git a/platforms/chip/chip_adaptor_test.go b/platforms/chip/chip_adaptor_test.go new file mode 100644 index 00000000..d66484c5 --- /dev/null +++ b/platforms/chip/chip_adaptor_test.go @@ -0,0 +1,81 @@ +package chip + +import ( + "errors" + "testing" + + "github.com/hybridgroup/gobot" + "github.com/hybridgroup/gobot/sysfs" +) + +type NullReadWriteCloser struct { + contents []byte +} + +func (n *NullReadWriteCloser) SetAddress(int) error { + return nil +} + +func (n *NullReadWriteCloser) Write(b []byte) (int, error) { + n.contents = make([]byte, len(b)) + copy(n.contents[:], b[:]) + + return len(b), nil +} + +func (n *NullReadWriteCloser) Read(b []byte) (int, error) { + copy(b, n.contents) + return len(b), nil +} + +var closeErr error = nil + +func (n *NullReadWriteCloser) Close() error { + return closeErr +} + +func initTestChipAdaptor() *ChipAdaptor { + a := NewChipAdaptor("myAdaptor") + a.Connect() + return a +} + +func TestChipAdaptorDigitalIO(t *testing.T) { + a := initTestChipAdaptor() + fs := sysfs.NewMockFilesystem([]string{ + "/sys/class/gpio/export", + "/sys/class/gpio/unexport", + "/sys/class/gpio/gpio408/value", + "/sys/class/gpio/gpio408/direction", + "/sys/class/gpio/gpio415/value", + "/sys/class/gpio/gpio415/direction", + }) + + sysfs.SetFilesystem(fs) + + a.DigitalWrite("U14_13", 1) + gobot.Assert(t, fs.Files["/sys/class/gpio/gpio408/value"].Contents, "1") + + fs.Files["/sys/class/gpio/gpio415/value"].Contents = "1" + i, _ := a.DigitalRead("U14_20") + gobot.Assert(t, i, 1) + + gobot.Assert(t, a.DigitalWrite("U13_99", 1), errors.New("Not a valid pin")) +} + +func TestChipAdaptorI2c(t *testing.T) { + a := initTestChipAdaptor() + fs := sysfs.NewMockFilesystem([]string{ + "/dev/i2c-1", + }) + sysfs.SetFilesystem(fs) + sysfs.SetSyscall(&sysfs.MockSyscall{}) + a.I2cStart(0xff) + a.i2cDevice = &NullReadWriteCloser{} + + a.I2cWrite(0xff, []byte{0x00, 0x01}) + data, _ := a.I2cRead(0xff, 2) + gobot.Assert(t, data, []byte{0x00, 0x01}) + + gobot.Assert(t, len(a.Finalize()), 0) +} diff --git a/platforms/chip/doc.go b/platforms/chip/doc.go new file mode 100644 index 00000000..c501a5e0 --- /dev/null +++ b/platforms/chip/doc.go @@ -0,0 +1,7 @@ +/* +Package chip contains the Gobot adaptor for the CHIP + +For further information refer to the chip README: +https://github.com/hybridgroup/gobot/blob/master/platforms/chip/README.md +*/ +package chip