Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/vendelin8/gobot into vend…
Browse files Browse the repository at this point in the history
…elin8-master
  • Loading branch information
deadprogram committed Aug 24, 2018
2 parents a0b92d8 + 8f707f0 commit fc1e1ee
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 1 deletion.
42 changes: 42 additions & 0 deletions platforms/digispark/digispark_adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package digispark

import (
"errors"
"fmt"
"strconv"

"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/i2c"
)

// ErrConnection is the error resulting of a connection error with the digispark
Expand All @@ -16,6 +18,7 @@ type Adaptor struct {
littleWire lw
servo bool
pwm bool
i2c bool
connect func(*Adaptor) (err error)
}

Expand Down Expand Up @@ -89,3 +92,42 @@ func (d *Adaptor) ServoWrite(pin string, angle uint8) (err error) {
}
return d.littleWire.servoUpdateLocation(angle, angle)
}

// GetConnection returns an i2c connection to a device on a specified bus.
// Only supports bus number 0
func (d *Adaptor) GetConnection(address int, bus int) (connection i2c.Connection, err error) {
if bus != 0 {
return nil, fmt.Errorf("Invalid bus number %d, only 0 is supported", bus)
}
c := NewDigisparkI2cConnection(d, uint8(address))
if err := c.Init(); err != nil {
return nil, err
}
return i2c.Connection(c), nil
}

// GetDefaultBus returns the default i2c bus for this platform
func (d *Adaptor) GetDefaultBus() int {
return 0
}

// TestConnection returns found i2c connections to devices in a given range of addresses
func (d *Adaptor) TestConnection(start, end int, success func(int)) error {
conn, err := d.GetConnection(start, d.GetDefaultBus())
if err != nil {
return err
}
c := conn.(*digisparkI2cConnection)
if !d.i2c {
return errors.New("Digispark i2c not initialized")
}
if start > end {
start, end = end, start
}
for ; start <= end; start++ {
if err = c.Test(uint8(start)); err == nil {
success(start)
}
}
return nil
}
91 changes: 91 additions & 0 deletions platforms/digispark/digispark_adaptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package digispark

import (
"errors"
"fmt"
"strings"
"testing"

"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/gpio"
"gobot.io/x/gobot/drivers/i2c"
"gobot.io/x/gobot/gobottest"
)

Expand All @@ -15,6 +17,7 @@ var _ gobot.Adaptor = (*Adaptor)(nil)
var _ gpio.DigitalWriter = (*Adaptor)(nil)
var _ gpio.PwmWriter = (*Adaptor)(nil)
var _ gpio.ServoWriter = (*Adaptor)(nil)
var _ i2c.Connector = (*Adaptor)(nil)

type mock struct {
locationA uint8
Expand All @@ -25,6 +28,9 @@ type mock struct {
pin uint8
mode uint8
state uint8
address int
duration uint
direction uint8
}

func (l *mock) digitalWrite(pin uint8, state uint8) error {
Expand Down Expand Up @@ -58,6 +64,49 @@ func (l *mock) servoUpdateLocation(locationA uint8, locationB uint8) error {
return l.error()
}

const availableI2cAddress = 0x40
const maxUint8 = ^uint8(0)

var i2cData = []byte{5, 4, 3, 2, 1, 0}

func (l *mock) i2cInit() error {
l.direction = maxUint8
return l.error()
}

func (l *mock) i2cStart(address7bit uint8, direction uint8) error {
if address7bit != availableI2cAddress {
return fmt.Errorf("Invalid address, only %d is supported", availableI2cAddress)
}
if err := l.error(); err != nil {
return err
}
l.direction = direction
return nil
}

func (l *mock) i2cWrite(sendBuffer []byte, length int, endWithStop uint8) error {
l.direction = 0
return l.error()
}

func (l *mock) i2cRead(readBuffer []byte, length int, endWithStop uint8) error {
l.direction = 1
if len(readBuffer) < length {
length = len(readBuffer)
}
if len(i2cData) < length {
length = len(i2cData)
}
copy(readBuffer[:length], i2cData[:length])
return l.error()
}

func (l *mock) i2cUpdateDelay(duration uint) error {
l.duration = duration
return l.error()
}

var errorFunc = func() error { return nil }

func (l *mock) error() error { return errorFunc() }
Expand Down Expand Up @@ -136,3 +185,45 @@ func TestAdaptorPwmWrite(t *testing.T) {
err = a.PwmWrite("1", uint8(100))
gobottest.Assert(t, err, errors.New("pwm error"))
}

func TestAdaptorI2c(t *testing.T) {
var c i2c.Connection
var err error
data := []byte{0, 1, 2, 3, 4}
dataLen := len(data)
count := 0

a := initTestAdaptor()
c, err = a.GetConnection(0x40, 1)
gobottest.Assert(t, err, errors.New("Invalid bus number 1, only 0 is supported"))
gobottest.Assert(t, c, nil)
// init couldn't run, direction is still 0
gobottest.Assert(t, a.littleWire.(*mock).direction, uint8(0))

// connection inits, but start will fail
c, err = a.GetConnection(0x39, a.GetDefaultBus())
gobottest.Assert(t, err, nil)
gobottest.Refute(t, c, nil)
gobottest.Assert(t, a.littleWire.(*mock).direction, maxUint8)
err = c.(*digisparkI2cConnection).UpdateDelay(uint(100))
gobottest.Assert(t, err, nil)
gobottest.Assert(t, a.littleWire.(*mock).duration, uint(100))
count, err = c.Write(data)
gobottest.Assert(t, count, 0)
gobottest.Assert(t, err, fmt.Errorf("Invalid address, only %d is supported", availableI2cAddress))
gobottest.Assert(t, a.littleWire.(*mock).direction, maxUint8)

// connection inits, but start will succeed
c, err = a.GetConnection(availableI2cAddress, a.GetDefaultBus())
gobottest.Assert(t, err, nil)
gobottest.Refute(t, c, nil)
count, err = c.Write(data)
gobottest.Assert(t, count, dataLen)
gobottest.Assert(t, err, nil)
gobottest.Assert(t, a.littleWire.(*mock).direction, uint8(0))
count, err = c.Read(data)
gobottest.Assert(t, count, dataLen)
gobottest.Assert(t, err, nil)
gobottest.Assert(t, a.littleWire.(*mock).direction, uint8(1))
gobottest.Assert(t, data, i2cData[:dataLen])
}
160 changes: 160 additions & 0 deletions platforms/digispark/digispark_i2c.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package digispark

import (
"errors"
)

type digisparkI2cConnection struct {
address uint8
adaptor *Adaptor
}

// NewDigisparkI2cConnection creates an i2c connection to an i2c device at
// the specified address
func NewDigisparkI2cConnection(adaptor *Adaptor, address uint8) (connection *digisparkI2cConnection) {
return &digisparkI2cConnection{adaptor: adaptor, address: address}
}

// Init makes sure that the i2c device is already initialized
func (c *digisparkI2cConnection) Init() (err error) {
if !c.adaptor.i2c {
if err = c.adaptor.littleWire.i2cInit(); err != nil {
return
}
c.adaptor.i2c = true
}
return
}

// Test tests i2c connection with the given address
func (c *digisparkI2cConnection) Test(address uint8) error {
if !c.adaptor.i2c {
return errors.New("Digispark i2c not initialized")
}
return c.adaptor.littleWire.i2cStart(address, 0)
}

// UpdateDelay updates i2c signal delay amount; tune if neccessary to fit your requirements
func (c *digisparkI2cConnection) UpdateDelay(duration uint) error {
if !c.adaptor.i2c {
return errors.New("Digispark i2c not initialized")
}
return c.adaptor.littleWire.i2cUpdateDelay(duration)
}

// Read tries to read a full buffer from the i2c device.
// Returns an empty array if the response from the board has timed out.
func (c *digisparkI2cConnection) Read(b []byte) (read int, err error) {
if !c.adaptor.i2c {
err = errors.New("Digispark i2c not initialized")
return
}
if err = c.adaptor.littleWire.i2cStart(c.address, 1); err != nil {
return
}
l := 8
stop := uint8(0)

for stop == 0 {
if read+l >= len(b) {
l = len(b) - read
stop = 1
}
if err = c.adaptor.littleWire.i2cRead(b[read:read+l], l, stop); err != nil {
return
}
read += l
}
return
}

func (c *digisparkI2cConnection) Write(data []byte) (written int, err error) {
if !c.adaptor.i2c {
err = errors.New("Digispark i2c not initialized")
return
}
if err = c.adaptor.littleWire.i2cStart(c.address, 0); err != nil {
return
}
l := 4
stop := uint8(0)

for stop == 0 {
if written+l >= len(data) {
l = len(data) - written
stop = 1
}
if err = c.adaptor.littleWire.i2cWrite(data[written:written+l], l, stop); err != nil {
return
}
written += l
}
return
}

func (c *digisparkI2cConnection) Close() error {
return nil
}

func (c *digisparkI2cConnection) ReadByte() (val byte, err error) {
b := make([]byte, 1)
if err = c.adaptor.littleWire.i2cRead(b, 1, 1); err != nil {
return
}
val = b[0]
return
}

func (c *digisparkI2cConnection) ReadByteData(reg uint8) (val uint8, err error) {
if err = c.WriteByte(reg); err != nil {
return
}
return c.ReadByte()
}

func (c *digisparkI2cConnection) ReadWordData(reg uint8) (val uint16, err error) {
if err = c.WriteByte(reg); err != nil {
return
}

buf := []byte{0, 0}
if _, err = c.Read(buf); err != nil {
return
}
low, high := buf[0], buf[1]

val = (uint16(high) << 8) | uint16(low)
return
}

func (c *digisparkI2cConnection) WriteByte(val byte) (err error) {
b := []byte{val}
err = c.adaptor.littleWire.i2cWrite(b, 1, 1)
return
}

func (c *digisparkI2cConnection) WriteByteData(reg uint8, val byte) (err error) {
buf := []byte{reg, val}
_, err = c.Write(buf)
return
}

func (c *digisparkI2cConnection) WriteWordData(reg uint8, val uint16) (err error) {
low := uint8(val & 0xff)
high := uint8((val >> 8) & 0xff)
buf := []byte{reg, low, high}
_, err = c.Write(buf)
return
}

func (c *digisparkI2cConnection) WriteBlockData(reg uint8, data []byte) (err error) {
if len(data) > 32 {
data = data[:32]
}

buf := make([]byte, len(data)+1)
copy(buf[:1], data)
buf[0] = reg
_, err = c.Write(buf)
return
}
Loading

0 comments on commit fc1e1ee

Please sign in to comment.