piframe-go/vendor/github.com/d2r2/go-i2c/i2c.go
2020-09-04 14:56:41 -04:00

242 lines
6.4 KiB
Go

// Package i2c provides low level control over the Linux i2c bus.
//
// Before usage you should load the i2c-dev kernel module
//
// sudo modprobe i2c-dev
//
// Each i2c bus can address 127 independent i2c devices, and most
// Linux systems contain several buses.
package i2c
import (
"encoding/hex"
"fmt"
"os"
"syscall"
)
// I2C represents a connection to I2C-device.
type I2C struct {
addr uint8
bus int
rc *os.File
}
// NewI2C opens a connection for I2C-device.
// SMBus (System Management Bus) protocol over I2C
// supported as well: you should preliminary specify
// register address to read from, either write register
// together with the data in case of write operations.
func NewI2C(addr uint8, bus int) (*I2C, error) {
f, err := os.OpenFile(fmt.Sprintf("/dev/i2c-%d", bus), os.O_RDWR, 0600)
if err != nil {
return nil, err
}
if err := ioctl(f.Fd(), I2C_SLAVE, uintptr(addr)); err != nil {
return nil, err
}
v := &I2C{rc: f, bus: bus, addr: addr}
return v, nil
}
// GetBus return bus line, where I2C-device is allocated.
func (v *I2C) GetBus() int {
return v.bus
}
// GetAddr return device occupied address in the bus.
func (v *I2C) GetAddr() uint8 {
return v.addr
}
func (v *I2C) write(buf []byte) (int, error) {
return v.rc.Write(buf)
}
// WriteBytes send bytes to the remote I2C-device. The interpretation of
// the message is implementation-dependent.
func (v *I2C) WriteBytes(buf []byte) (int, error) {
lg.Debugf("Write %d hex bytes: [%+v]", len(buf), hex.EncodeToString(buf))
return v.write(buf)
}
func (v *I2C) read(buf []byte) (int, error) {
return v.rc.Read(buf)
}
// ReadBytes read bytes from I2C-device.
// Number of bytes read correspond to buf parameter length.
func (v *I2C) ReadBytes(buf []byte) (int, error) {
n, err := v.read(buf)
if err != nil {
return n, err
}
lg.Debugf("Read %d hex bytes: [%+v]", len(buf), hex.EncodeToString(buf))
return n, nil
}
// Close I2C-connection.
func (v *I2C) Close() error {
return v.rc.Close()
}
// ReadRegBytes read count of n byte's sequence from I2C-device
// starting from reg address.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) ReadRegBytes(reg byte, n int) ([]byte, int, error) {
lg.Debugf("Read %d bytes starting from reg 0x%0X...", n, reg)
_, err := v.WriteBytes([]byte{reg})
if err != nil {
return nil, 0, err
}
buf := make([]byte, n)
c, err := v.ReadBytes(buf)
if err != nil {
return nil, 0, err
}
return buf, c, nil
}
// ReadRegU8 reads byte from I2C-device register specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) ReadRegU8(reg byte) (byte, error) {
_, err := v.WriteBytes([]byte{reg})
if err != nil {
return 0, err
}
buf := make([]byte, 1)
_, err = v.ReadBytes(buf)
if err != nil {
return 0, err
}
lg.Debugf("Read U8 %d from reg 0x%0X", buf[0], reg)
return buf[0], nil
}
// WriteRegU8 writes byte to I2C-device register specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) WriteRegU8(reg byte, value byte) error {
buf := []byte{reg, value}
_, err := v.WriteBytes(buf)
if err != nil {
return err
}
lg.Debugf("Write U8 %d to reg 0x%0X", value, reg)
return nil
}
// ReadRegU16BE reads unsigned big endian word (16 bits)
// from I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) ReadRegU16BE(reg byte) (uint16, error) {
_, err := v.WriteBytes([]byte{reg})
if err != nil {
return 0, err
}
buf := make([]byte, 2)
_, err = v.ReadBytes(buf)
if err != nil {
return 0, err
}
w := uint16(buf[0])<<8 + uint16(buf[1])
lg.Debugf("Read U16 %d from reg 0x%0X", w, reg)
return w, nil
}
// ReadRegU16LE reads unsigned little endian word (16 bits)
// from I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) ReadRegU16LE(reg byte) (uint16, error) {
w, err := v.ReadRegU16BE(reg)
if err != nil {
return 0, err
}
// exchange bytes
w = (w&0xFF)<<8 + w>>8
return w, nil
}
// ReadRegS16BE reads signed big endian word (16 bits)
// from I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) ReadRegS16BE(reg byte) (int16, error) {
_, err := v.WriteBytes([]byte{reg})
if err != nil {
return 0, err
}
buf := make([]byte, 2)
_, err = v.ReadBytes(buf)
if err != nil {
return 0, err
}
w := int16(buf[0])<<8 + int16(buf[1])
lg.Debugf("Read S16 %d from reg 0x%0X", w, reg)
return w, nil
}
// ReadRegS16LE reads signed little endian word (16 bits)
// from I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) ReadRegS16LE(reg byte) (int16, error) {
w, err := v.ReadRegS16BE(reg)
if err != nil {
return 0, err
}
// exchange bytes
w = (w&0xFF)<<8 + w>>8
return w, nil
}
// WriteRegU16BE writes unsigned big endian word (16 bits)
// value to I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) WriteRegU16BE(reg byte, value uint16) error {
buf := []byte{reg, byte((value & 0xFF00) >> 8), byte(value & 0xFF)}
_, err := v.WriteBytes(buf)
if err != nil {
return err
}
lg.Debugf("Write U16 %d to reg 0x%0X", value, reg)
return nil
}
// WriteRegU16LE writes unsigned little endian word (16 bits)
// value to I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) WriteRegU16LE(reg byte, value uint16) error {
w := (value*0xFF00)>>8 + value<<8
return v.WriteRegU16BE(reg, w)
}
// WriteRegS16BE writes signed big endian word (16 bits)
// value to I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) WriteRegS16BE(reg byte, value int16) error {
buf := []byte{reg, byte((uint16(value) & 0xFF00) >> 8), byte(value & 0xFF)}
_, err := v.WriteBytes(buf)
if err != nil {
return err
}
lg.Debugf("Write S16 %d to reg 0x%0X", value, reg)
return nil
}
// WriteRegS16LE writes signed little endian word (16 bits)
// value to I2C-device starting from address specified in reg.
// SMBus (System Management Bus) protocol over I2C.
func (v *I2C) WriteRegS16LE(reg byte, value int16) error {
w := int16((uint16(value)*0xFF00)>>8) + value<<8
return v.WriteRegS16BE(reg, w)
}
func ioctl(fd, cmd, arg uintptr) error {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, cmd, arg, 0, 0, 0)
if err != 0 {
return err
}
return nil
}