From f0873adea6ba910896f282c5d91729a931107d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Agsj=C3=B6?= Date: Mon, 27 Feb 2017 20:53:01 +0100 Subject: [PATCH 1/2] Removed smbus block operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Agsjö --- drivers/i2c/i2c.go | 8 ------ drivers/i2c/i2c_test.go | 10 ++------ sysfs/i2c_device.go | 55 ++++++++++++++++------------------------- 3 files changed, 23 insertions(+), 50 deletions(-) diff --git a/drivers/i2c/i2c.go b/drivers/i2c/i2c.go index 75cf92110..7a1521c15 100644 --- a/drivers/i2c/i2c.go +++ b/drivers/i2c/i2c.go @@ -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 { diff --git a/drivers/i2c/i2c_test.go b/drivers/i2c/i2c_test.go index b80673733..7a54da2e8 100644 --- a/drivers/i2c/i2c_test.go +++ b/drivers/i2c/i2c_test.go @@ -53,12 +53,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) @@ -77,8 +71,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) } diff --git a/sysfs/i2c_device.go b/sysfs/i2c_device.go index a133d9f74..bcf3ed840 100644 --- a/sysfs/i2c_device.go +++ b/sysfs/i2c_device.go @@ -20,17 +20,14 @@ const ( 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 { @@ -45,7 +42,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) @@ -129,19 +125,6 @@ func (d *i2cDevice) ReadWordData(reg uint8) (val uint16, err error) { 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") - } - - 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 @@ -160,21 +143,25 @@ func (d *i2cDevice) WriteWordData(reg uint8, val uint16) (err error) { } 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. From ea93b203bdca1edf14fc462e90a34f9335243b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Agsj=C3=B6?= Date: Mon, 27 Feb 2017 23:40:14 +0100 Subject: [PATCH 2/2] Added more capabilities checks for I2C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Agsjö --- drivers/i2c/i2c_test.go | 18 +++++++++++++++++- sysfs/i2c_device.go | 33 +++++++++++++++++++++++++++++++++ sysfs/syscall.go | 10 ++++++++-- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c_test.go b/drivers/i2c/i2c_test.go index 7a54da2e8..a6bb2243e 100644 --- a/drivers/i2c/i2c_test.go +++ b/drivers/i2c/i2c_test.go @@ -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 } diff --git a/sysfs/i2c_device.go b/sysfs/i2c_device.go index bcf3ed840..9f08b53d1 100644 --- a/sysfs/i2c_device.go +++ b/sysfs/i2c_device.go @@ -9,6 +9,7 @@ import ( ) const ( + // From /usr/include/linux/i2c-dev.h: // ioctl signals I2C_SLAVE = 0x0703 I2C_FUNCS = 0x0705 @@ -16,7 +17,15 @@ const ( // 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 @@ -108,35 +117,59 @@ 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) WriteByte(val uint8) (err error) { + if d.funcs&I2C_FUNC_SMBUS_WRITE_BYTE == 0 { + return fmt.Errorf("SMBus write byte not supported") + } + 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 diff --git a/sysfs/syscall.go b/sysfs/syscall.go index 073004955..cf599779f 100644 --- a/sysfs/syscall.go +++ b/sysfs/syscall.go @@ -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{} @@ -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 + } }