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  }