Skip to content

Commit

Permalink
Get I2C functionality before doing SMBus block I/O
Browse files Browse the repository at this point in the history
In the sysfs i2cDevice implementation, use an ioctl to get the adapter
functionality mask. Prefer SMBus block I/O but if it's not available,
perform read/write calls directly on the file descriptor.

Improve Wiichuck error handling. Add a 1 ms delay between I/O operations
to the Wiichuck; this dramatically improves reliability.

Signed-off-by: Hrishikesh Tapaswi <[email protected]>
  • Loading branch information
hrishikesh195 authored and deadprogram committed Feb 17, 2016
1 parent 11371f5 commit 42475e4
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 9 deletions.
3 changes: 3 additions & 0 deletions examples/chip_wiichuck.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ func main() {
gobot.On(wiichuck.Event("z"), func(data interface{}) {
fmt.Println("z")
})
gobot.On(wiichuck.Event("error"), func(data interface{}) {
fmt.Println("Wiichuck error:", data)
})
}

robot := gobot.NewRobot("chuck",
Expand Down
3 changes: 3 additions & 0 deletions examples/firmata_wiichuck.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ func main() {
gobot.On(wiichuck.Event("z"), func(data interface{}) {
fmt.Println("z")
})
gobot.On(wiichuck.Event("error"), func(data interface{}) {
fmt.Println("Wiichuck error:", data)
})
}

robot := gobot.NewRobot("chuck",
Expand Down
12 changes: 9 additions & 3 deletions platforms/i2c/wiichuck_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type WiichuckDriver struct {
name string
connection I2c
interval time.Duration
pauseTime time.Duration
gobot.Eventer
joystick map[string]float64
data map[string]float64
Expand All @@ -22,14 +23,16 @@ type WiichuckDriver struct {
// NewWiichuckDriver creates a WiichuckDriver with specified i2c interface and name.
//
// It adds the following events:
// "z"- Get's triggered every interval amount of time if the z button is pressed
// "c" - Get's triggered every interval amount of time if the c button is pressed
// "joystick" - Get's triggered every "interval" amount of time if a joystick event occured, you can access values x, y
// "z"- Gets triggered every interval amount of time if the z button is pressed
// "c" - Gets triggered every interval amount of time if the c button is pressed
// "joystick" - Gets triggered every "interval" amount of time if a joystick event occured, you can access values x, y
// "error" - Gets triggered whenever the WiichuckDriver encounters an error
func NewWiichuckDriver(a I2c, name string, v ...time.Duration) *WiichuckDriver {
w := &WiichuckDriver{
name: name,
connection: a,
interval: 10 * time.Millisecond,
pauseTime: 1 * time.Millisecond,
Eventer: gobot.NewEventer(),
joystick: map[string]float64{
"sy_origin": -1,
Expand All @@ -50,6 +53,7 @@ func NewWiichuckDriver(a I2c, name string, v ...time.Duration) *WiichuckDriver {
w.AddEvent(Z)
w.AddEvent(C)
w.AddEvent(Joystick)
w.AddEvent(Error)
return w
}
func (w *WiichuckDriver) Name() string { return w.name }
Expand All @@ -68,10 +72,12 @@ func (w *WiichuckDriver) Start() (errs []error) {
gobot.Publish(w.Event(Error), err)
continue
}
<-time.After(w.pauseTime)
if err := w.connection.I2cWrite(wiichuckAddress, []byte{0x00}); err != nil {
gobot.Publish(w.Event(Error), err)
continue
}
<-time.After(w.pauseTime)
newValue, err := w.connection.I2cRead(wiichuckAddress, 6)
if err != nil {
gobot.Publish(w.Event(Error), err)
Expand Down
40 changes: 35 additions & 5 deletions sysfs/i2c_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const (
I2C_SMBUS_WRITE = 0
I2C_SMBUS_READ = 1
I2C_SMBUS_I2C_BLOCK_DATA = 8

// Adapter functionality
I2C_FUNCS = 0x0705
I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000
)

type i2cSmbusIoctlData struct {
Expand All @@ -29,7 +34,8 @@ type I2cDevice interface {
}

type i2cDevice struct {
file File
file File
funcs uint64 // adapter functionality mask
}

// NewI2cDevice returns an io.ReadWriteCloser with the proper ioctrl given
Expand All @@ -40,12 +46,30 @@ func NewI2cDevice(location string, address int) (d *i2cDevice, err error) {
if d.file, err = OpenFile(location, os.O_RDWR, os.ModeExclusive); err != nil {
return
}
if err = d.queryFunctionality(); err != nil {
return
}

err = d.SetAddress(address)

return
}

func (d *i2cDevice) queryFunctionality() (err error) {
_, _, errno := Syscall(
syscall.SYS_IOCTL,
d.file.Fd(),
I2C_FUNCS,
uintptr(unsafe.Pointer(&d.funcs)),
)

if errno != 0 {
err = fmt.Errorf("Querying functionality failed with syscall.Errno %v", errno)
}
fmt.Printf("Functionality: 0x%x\n", d.funcs)
return
}

func (d *i2cDevice) SetAddress(address int) (err error) {
_, _, errno := Syscall(
syscall.SYS_IOCTL,
Expand All @@ -55,7 +79,7 @@ func (d *i2cDevice) SetAddress(address int) (err error) {
)

if errno != 0 {
err = fmt.Errorf("Failed with syscall.Errno %v", errno)
err = fmt.Errorf("Setting address failed with syscall.Errno %v", errno)
}

return
Expand All @@ -66,6 +90,11 @@ func (d *i2cDevice) Close() (err error) {
}

func (d *i2cDevice) Read(b []byte) (n int, err error) {
if d.funcs&I2C_FUNC_SMBUS_READ_BLOCK_DATA == 0 {
// Adapter doesn't support SMBus block read
return d.file.Read(b)
}

data := make([]byte, len(b)+1)
data[0] = byte(len(b))

Expand All @@ -83,7 +112,7 @@ func (d *i2cDevice) Read(b []byte) (n int, err error) {
)

if errno != 0 {
return n, fmt.Errorf("Failed with syscall.Errno %v", errno)
return n, fmt.Errorf("Read failed with syscall.Errno %v", errno)
}

copy(b, data[1:])
Expand All @@ -92,7 +121,8 @@ func (d *i2cDevice) Read(b []byte) (n int, err error) {
}

func (d *i2cDevice) Write(b []byte) (n int, err error) {
if len(b) <= 2 {
if d.funcs&I2C_FUNC_SMBUS_WRITE_BLOCK_DATA == 0 {
// Adapter doesn't support SMBus block write
return d.file.Write(b)
}

Expand All @@ -119,7 +149,7 @@ func (d *i2cDevice) Write(b []byte) (n int, err error) {
)

if errno != 0 {
err = fmt.Errorf("Failed with syscall.Errno %v", errno)
err = fmt.Errorf("Write failed with syscall.Errno %v", errno)
}

return len(b), err
Expand Down
2 changes: 1 addition & 1 deletion sysfs/i2c_device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestNewI2cDevice(t *testing.T) {

n, err = i.Read(buf)

gobot.Assert(t, n, 4)
gobot.Assert(t, n, 3)
gobot.Assert(t, err, nil)

}

0 comments on commit 42475e4

Please sign in to comment.