gobot.io/x/gobot@v1.16.0/sysfs/i2c_device.go (about) 1 package sysfs 2 3 import ( 4 "fmt" 5 "os" 6 "syscall" 7 "unsafe" 8 ) 9 10 const ( 11 // From /usr/include/linux/i2c-dev.h: 12 // ioctl signals 13 I2C_SLAVE = 0x0703 14 I2C_FUNCS = 0x0705 15 I2C_SMBUS = 0x0720 16 // Read/write markers 17 I2C_SMBUS_READ = 1 18 I2C_SMBUS_WRITE = 0 19 20 // From /usr/include/linux/i2c.h: 21 // Adapter functionality 22 I2C_FUNC_SMBUS_READ_BYTE = 0x00020000 23 I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000 24 I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000 25 I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000 26 I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000 27 I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000 28 I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000 29 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000 30 // Transaction types 31 I2C_SMBUS_BYTE = 1 32 I2C_SMBUS_BYTE_DATA = 2 33 I2C_SMBUS_WORD_DATA = 3 34 I2C_SMBUS_PROC_CALL = 4 35 I2C_SMBUS_BLOCK_DATA = 5 36 I2C_SMBUS_I2C_BLOCK_BROKEN = 6 37 I2C_SMBUS_BLOCK_PROC_CALL = 7 /* SMBus 2.0 */ 38 I2C_SMBUS_I2C_BLOCK_DATA = 8 /* SMBus 2.0 */ 39 ) 40 41 type i2cSmbusIoctlData struct { 42 readWrite byte 43 command byte 44 size uint32 45 data uintptr 46 } 47 48 type i2cDevice struct { 49 file File 50 funcs uint64 // adapter functionality mask 51 } 52 53 // NewI2cDevice returns an io.ReadWriteCloser with the proper ioctrl given 54 // an i2c bus location. 55 func NewI2cDevice(location string) (d *i2cDevice, err error) { 56 d = &i2cDevice{} 57 58 if d.file, err = OpenFile(location, os.O_RDWR, os.ModeExclusive); err != nil { 59 return 60 } 61 if err = d.queryFunctionality(); err != nil { 62 return 63 } 64 65 return 66 } 67 68 func (d *i2cDevice) queryFunctionality() (err error) { 69 _, _, errno := Syscall( 70 syscall.SYS_IOCTL, 71 d.file.Fd(), 72 I2C_FUNCS, 73 uintptr(unsafe.Pointer(&d.funcs)), 74 ) 75 76 if errno != 0 { 77 err = fmt.Errorf("Querying functionality failed with syscall.Errno %v", errno) 78 } 79 return 80 } 81 82 func (d *i2cDevice) SetAddress(address int) (err error) { 83 _, _, errno := Syscall( 84 syscall.SYS_IOCTL, 85 d.file.Fd(), 86 I2C_SLAVE, 87 uintptr(byte(address)), 88 ) 89 90 if errno != 0 { 91 err = fmt.Errorf("Setting address failed with syscall.Errno %v", errno) 92 } 93 94 return 95 } 96 97 func (d *i2cDevice) Close() (err error) { 98 return d.file.Close() 99 } 100 101 func (d *i2cDevice) ReadByte() (val byte, err error) { 102 if d.funcs&I2C_FUNC_SMBUS_READ_BYTE == 0 { 103 return 0, fmt.Errorf("SMBus read byte not supported") 104 } 105 106 var data uint8 107 err = d.smbusAccess(I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, uintptr(unsafe.Pointer(&data))) 108 return data, err 109 } 110 111 func (d *i2cDevice) ReadByteData(reg uint8) (val uint8, err error) { 112 if d.funcs&I2C_FUNC_SMBUS_READ_BYTE_DATA == 0 { 113 return 0, fmt.Errorf("SMBus read byte data not supported") 114 } 115 116 var data uint8 117 err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, uintptr(unsafe.Pointer(&data))) 118 return data, err 119 } 120 121 func (d *i2cDevice) ReadWordData(reg uint8) (val uint16, err error) { 122 if d.funcs&I2C_FUNC_SMBUS_READ_WORD_DATA == 0 { 123 return 0, fmt.Errorf("SMBus read word data not supported") 124 } 125 126 var data uint16 127 err = d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, uintptr(unsafe.Pointer(&data))) 128 return data, err 129 } 130 131 func (d *i2cDevice) WriteByte(val byte) (err error) { 132 if d.funcs&I2C_FUNC_SMBUS_WRITE_BYTE == 0 { 133 return fmt.Errorf("SMBus write byte not supported") 134 } 135 136 err = d.smbusAccess(I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, uintptr(0)) 137 return err 138 } 139 140 func (d *i2cDevice) WriteByteData(reg uint8, val uint8) (err error) { 141 if d.funcs&I2C_FUNC_SMBUS_WRITE_BYTE_DATA == 0 { 142 return fmt.Errorf("SMBus write byte data not supported") 143 } 144 145 var data = val 146 err = d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, uintptr(unsafe.Pointer(&data))) 147 return err 148 } 149 150 func (d *i2cDevice) WriteWordData(reg uint8, val uint16) (err error) { 151 if d.funcs&I2C_FUNC_SMBUS_WRITE_WORD_DATA == 0 { 152 return fmt.Errorf("SMBus write word data not supported") 153 } 154 155 var data = val 156 err = d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, uintptr(unsafe.Pointer(&data))) 157 return err 158 } 159 160 func (d *i2cDevice) WriteBlockData(reg uint8, data []byte) (err error) { 161 if len(data) > 32 { 162 return fmt.Errorf("Writing blocks larger than 32 bytes (%v) not supported", len(data)) 163 } 164 165 buf := make([]byte, len(data)+1) 166 copy(buf[1:], data) 167 buf[0] = reg 168 169 n, err := d.file.Write(buf) 170 171 if err != nil { 172 return err 173 } 174 175 if n != len(buf) { 176 return fmt.Errorf("Write to device truncated, %v of %v written", n, len(buf)) 177 } 178 179 return nil 180 } 181 182 // Read implements the io.ReadWriteCloser method by direct I2C read operations. 183 func (d *i2cDevice) Read(b []byte) (n int, err error) { 184 return d.file.Read(b) 185 } 186 187 // Write implements the io.ReadWriteCloser method by direct I2C write operations. 188 func (d *i2cDevice) Write(b []byte) (n int, err error) { 189 return d.file.Write(b) 190 } 191 192 func (d *i2cDevice) smbusAccess(readWrite byte, command byte, size uint32, data uintptr) error { 193 smbus := &i2cSmbusIoctlData{ 194 readWrite: readWrite, 195 command: command, 196 size: size, 197 data: data, 198 } 199 200 _, _, errno := Syscall( 201 syscall.SYS_IOCTL, 202 d.file.Fd(), 203 I2C_SMBUS, 204 uintptr(unsafe.Pointer(smbus)), 205 ) 206 207 if errno != 0 { 208 return fmt.Errorf("Failed with syscall.Errno %v", errno) 209 } 210 211 return nil 212 }