Skip to content

Commit

Permalink
Merge pull request hybridgroup#381 from erkkah/i2c-remove-smbusblock
Browse files Browse the repository at this point in the history
Removing SMBus block operations from I2C layer
  • Loading branch information
deadprogram authored Mar 10, 2017
2 parents fc23d52 + ea93b20 commit b7791a9
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 52 deletions.
8 changes: 0 additions & 8 deletions drivers/i2c/i2c.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,6 @@ func (c *i2cConnection) ReadWordData(reg uint8) (val uint16, err error) {
return c.bus.ReadWordData(reg)
}

// ReadBlockData reads a block of bytes for a register on the i2c device.
func (c *i2cConnection) ReadBlockData(reg uint8, b []byte) (n int, err error) {
if err := c.bus.SetAddress(c.address); err != nil {
return 0, err
}
return c.bus.ReadBlockData(reg, b)
}

// WriteByte writes a single byte to the i2c device.
func (c *i2cConnection) WriteByte(val byte) (err error) {
if err := c.bus.SetAddress(c.address); err != nil {
Expand Down
28 changes: 19 additions & 9 deletions drivers/i2c/i2c_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,31 @@ import (

"gobot.io/x/gobot/gobottest"
"gobot.io/x/gobot/sysfs"
"syscall"
"unsafe"
)

func syscallImpl(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
if (trap == syscall.SYS_IOCTL) && (a2 == sysfs.I2C_FUNCS) {
var funcPtr *uint64 = (*uint64)(unsafe.Pointer(a3))
*funcPtr = sysfs.I2C_FUNC_SMBUS_READ_BYTE | sysfs.I2C_FUNC_SMBUS_READ_BYTE_DATA |
sysfs.I2C_FUNC_SMBUS_READ_WORD_DATA |
sysfs.I2C_FUNC_SMBUS_WRITE_BYTE | sysfs.I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
sysfs.I2C_FUNC_SMBUS_WRITE_WORD_DATA
}
// Let all operations succeed
return 0, 0, 0
}

func initI2CDevice() sysfs.I2cDevice {
fs := sysfs.NewMockFilesystem([]string{
"/dev/i2c-1",
})
sysfs.SetFilesystem(fs)

sysfs.SetSyscall(&sysfs.MockSyscall{})
sysfs.SetSyscall(&sysfs.MockSyscall{
Impl: syscallImpl,
})
i, _ := sysfs.NewI2cDevice("/dev/i2c-1")
return i
}
Expand Down Expand Up @@ -53,12 +69,6 @@ func TestI2CReadWordData(t *testing.T) {
gobottest.Assert(t, v, uint16(0))
}

func TestI2CReadBlockData(t *testing.T) {
c := NewConnection(initI2CDevice(), 0x06)
i, _ := c.ReadBlockData(0x01, []byte{})
gobottest.Assert(t, i, 0)
}

func TestI2CWriteByte(t *testing.T) {
c := NewConnection(initI2CDevice(), 0x06)
err := c.WriteByte(0x01)
Expand All @@ -77,8 +87,8 @@ func TestI2CWriteWordData(t *testing.T) {
gobottest.Assert(t, err, nil)
}

func TestI2CWriteBlockDataErrNotSupported(t *testing.T) {
func TestI2CWriteBlockData(t *testing.T) {
c := NewConnection(initI2CDevice(), 0x06)
err := c.WriteBlockData(0x01, []byte{0x01, 0x02})
gobottest.Refute(t, err, nil)
gobottest.Assert(t, err, nil)
}
86 changes: 53 additions & 33 deletions sysfs/i2c_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,34 @@ import (
)

const (
// From /usr/include/linux/i2c-dev.h:
// ioctl signals
I2C_SLAVE = 0x0703
I2C_FUNCS = 0x0705
I2C_SMBUS = 0x0720
// Read/write markers
I2C_SMBUS_READ = 1
I2C_SMBUS_WRITE = 0

// From /usr/include/linux/i2c.h:
// Adapter functionality
I2C_FUNC_SMBUS_READ_BYTE = 0x00020000
I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000
I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000
I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000
I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000
I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000
I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000
// Transaction types
I2C_SMBUS_BYTE = 1
I2C_SMBUS_BYTE_DATA = 2
I2C_SMBUS_WORD_DATA = 3
I2C_SMBUS_PROC_CALL = 4
I2C_SMBUS_BLOCK_DATA = 5
I2C_SMBUS_I2C_BLOCK_DATA = 6
I2C_SMBUS_BLOCK_PROC_CALL = 7 /* SMBus 2.0 */
I2C_SMBUS_BLOCK_DATA_PEC = 8 /* SMBus 2.0 */
I2C_SMBUS_PROC_CALL_PEC = 9 /* SMBus 2.0 */
I2C_SMBUS_BLOCK_PROC_CALL_PEC = 10 /* SMBus 2.0 */
I2C_SMBUS_WORD_DATA_PEC = 11 /* SMBus 2.0 */
I2C_SMBUS_BYTE = 1
I2C_SMBUS_BYTE_DATA = 2
I2C_SMBUS_WORD_DATA = 3
I2C_SMBUS_PROC_CALL = 4
I2C_SMBUS_BLOCK_DATA = 5
I2C_SMBUS_I2C_BLOCK_BROKEN = 6
I2C_SMBUS_BLOCK_PROC_CALL = 7 /* SMBus 2.0 */
I2C_SMBUS_I2C_BLOCK_DATA = 8 /* SMBus 2.0 */
)

type i2cSmbusIoctlData struct {
Expand All @@ -45,7 +51,6 @@ type I2cOperations interface {
ReadByte() (val uint8, err error)
ReadByteData(reg uint8) (val uint8, err error)
ReadWordData(reg uint8) (val uint16, err error)
ReadBlockData(reg uint8, b []byte) (n int, err error)
WriteByte(val uint8) (err error)
WriteByteData(reg uint8, val uint8) (err error)
WriteWordData(reg uint8, val uint16) (err error)
Expand Down Expand Up @@ -112,69 +117,84 @@ func (d *i2cDevice) Close() (err error) {
}

func (d *i2cDevice) ReadByte() (val uint8, err error) {
if d.funcs&I2C_FUNC_SMBUS_READ_BYTE == 0 {
return 0, fmt.Errorf("SMBus read byte not supported")
}

var data uint8
err = d.smbusAccess(I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, uintptr(unsafe.Pointer(&data)))
return data, err
}

func (d *i2cDevice) ReadByteData(reg uint8) (val uint8, err error) {
if d.funcs&I2C_FUNC_SMBUS_READ_BYTE_DATA == 0 {
return 0, fmt.Errorf("SMBus read byte data not supported")
}

var data uint8
err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, uintptr(unsafe.Pointer(&data)))
return data, err
}

func (d *i2cDevice) ReadWordData(reg uint8) (val uint16, err error) {
if d.funcs&I2C_FUNC_SMBUS_READ_WORD_DATA == 0 {
return 0, fmt.Errorf("SMBus read word data not supported")
}

var data uint16
err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, uintptr(unsafe.Pointer(&data)))
return data, err
}

func (d *i2cDevice) ReadBlockData(reg uint8, buf []byte) (n int, err error) {
if d.funcs&I2C_FUNC_SMBUS_READ_BLOCK_DATA == 0 {
return 0, fmt.Errorf("SMBus block data reading not supported")
func (d *i2cDevice) WriteByte(val uint8) (err error) {
if d.funcs&I2C_FUNC_SMBUS_WRITE_BYTE == 0 {
return fmt.Errorf("SMBus write byte not supported")
}

data := make([]byte, 32+1) // Max message + size as defined by SMBus standard

err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_I2C_BLOCK_DATA, uintptr(unsafe.Pointer(&data[0])))

copy(buf, data[1:])
return int(data[0]), err
}

func (d *i2cDevice) WriteByte(val uint8) (err error) {
err = d.smbusAccess(I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, uintptr(0))
return err
}

func (d *i2cDevice) WriteByteData(reg uint8, val uint8) (err error) {
if d.funcs&I2C_FUNC_SMBUS_WRITE_BYTE_DATA == 0 {
return fmt.Errorf("SMBus write byte data not supported")
}

var data = val
err = d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, uintptr(unsafe.Pointer(&data)))
return err
}

func (d *i2cDevice) WriteWordData(reg uint8, val uint16) (err error) {
if d.funcs&I2C_FUNC_SMBUS_WRITE_WORD_DATA == 0 {
return fmt.Errorf("SMBus write word data not supported")
}

var data = val
err = d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, uintptr(unsafe.Pointer(&data)))
return err
}

func (d *i2cDevice) WriteBlockData(reg uint8, data []byte) (err error) {
if d.funcs&I2C_FUNC_SMBUS_WRITE_BLOCK_DATA == 0 {
return fmt.Errorf("SMBus block data writing not supported")
}

if len(data) > 32 {
data = data[:32]
return fmt.Errorf("Writing blocks larger than 32 bytes (%v) not supported", len(data))
}

buf := make([]byte, len(data)+1)
copy(buf[:1], data)
buf[0] = uint8(len(data))
copy(buf[1:], data)
buf[0] = reg

err = d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_I2C_BLOCK_DATA, uintptr(unsafe.Pointer(&buf[0])))
n, err := d.file.Write(buf)

return err
if err != nil {
return err
}

if n != len(buf) {
return fmt.Errorf("Write to device truncated, %v of %v written", n, len(buf))
}

return nil
}

// Read implements the io.ReadWriteCloser method by direct I2C read operations.
Expand Down
10 changes: 8 additions & 2 deletions sysfs/syscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ type SystemCaller interface {
type NativeSyscall struct{}

// MockSyscall represents the mock Syscall
type MockSyscall struct{}
type MockSyscall struct {
Impl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
}

var sys SystemCaller = &NativeSyscall{}

Expand All @@ -34,5 +36,9 @@ func (sys *NativeSyscall) Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err

// Syscall implements the SystemCaller interface
func (sys *MockSyscall) Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
return 0, 0, 0
if sys.Impl != nil {
return sys.Impl(trap, a1, a2, a3)
} else {
return 0, 0, 0
}
}

0 comments on commit b7791a9

Please sign in to comment.