diff --git a/drivers/i2c/i2c_test.go b/drivers/i2c/i2c_test.go index 7a54da2e..a6bb2243 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 bcf3ed84..9f08b53d 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 07300495..cf599779 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 + } }