2014-04-27 18:54:41 -07:00
|
|
|
package i2c
|
2014-04-26 03:11:51 -07:00
|
|
|
|
2014-11-29 12:10:23 -08:00
|
|
|
import (
|
|
|
|
"errors"
|
2017-07-12 09:00:35 -06:00
|
|
|
"io"
|
2017-05-07 22:28:07 +02:00
|
|
|
"sync"
|
2014-11-29 12:10:23 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2017-02-10 11:54:45 +01:00
|
|
|
// Error event
|
2017-02-09 16:47:11 +01:00
|
|
|
Error = "error"
|
2014-11-29 12:10:23 -08:00
|
|
|
)
|
|
|
|
|
2017-02-09 09:41:12 +01:00
|
|
|
const (
|
2017-02-10 11:54:45 +01:00
|
|
|
// BusNotInitialized is the initial value for a bus
|
|
|
|
BusNotInitialized = -1
|
|
|
|
|
|
|
|
// AddressNotInitialized is the initial value for an address
|
2017-02-09 14:35:48 +01:00
|
|
|
AddressNotInitialized = -1
|
2017-02-09 09:41:12 +01:00
|
|
|
)
|
|
|
|
|
2017-02-10 11:54:45 +01:00
|
|
|
var (
|
|
|
|
ErrEncryptedBytes = errors.New("Encrypted bytes")
|
|
|
|
ErrNotEnoughBytes = errors.New("Not enough bytes read")
|
|
|
|
ErrNotReady = errors.New("Device is not ready")
|
|
|
|
ErrInvalidPosition = errors.New("Invalid position value")
|
|
|
|
)
|
|
|
|
|
2022-03-19 21:16:31 +01:00
|
|
|
type bitState uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
clear bitState = 0x00
|
|
|
|
set = 0x01
|
|
|
|
)
|
|
|
|
|
2022-09-06 19:55:05 +02:00
|
|
|
// I2cOperations represents the i2c methods according to I2C/SMBus specification.
|
|
|
|
// Some functions are not in the interface yet:
|
|
|
|
// * Process Call (WriteWordDataReadWordData)
|
|
|
|
// * Block Write - Block Read (WriteBlockDataReadBlockData)
|
|
|
|
// * Host Notify - WriteWordData() can be used instead
|
|
|
|
//
|
|
|
|
// see: https://docs.kernel.org/i2c/smbus-protocol.html#key-to-symbols
|
|
|
|
//
|
|
|
|
// S: Start condition; Sr: Repeated start condition, used to switch from write to read mode.
|
|
|
|
// P: Stop condition; Rd/Wr (1 bit): Read/Write bit. Rd equals 1, Wr equals 0.
|
|
|
|
// A, NA (1 bit): Acknowledge (ACK) and Not Acknowledge (NACK) bit
|
|
|
|
// Addr (7 bits): I2C 7 bit address. (10 bit I2C address not yet supported by gobot).
|
|
|
|
// Comm (8 bits): Command byte, a data byte which often selects a register on the device.
|
|
|
|
// Data (8 bits): A plain data byte. DataLow and DataHigh represent the low and high byte of a 16 bit word.
|
|
|
|
// Count (8 bits): A data byte containing the length of a block operation.
|
|
|
|
// [..]: Data sent by I2C device, as opposed to data sent by the host adapter.
|
|
|
|
//
|
2017-07-12 09:00:35 -06:00
|
|
|
type I2cOperations interface {
|
|
|
|
io.ReadWriteCloser
|
2022-09-06 19:55:05 +02:00
|
|
|
|
|
|
|
// ReadByte must be implemented as the sequence:
|
|
|
|
// "S Addr Rd [A] [Data] NA P"
|
2017-07-12 09:00:35 -06:00
|
|
|
ReadByte() (val byte, err error)
|
2022-09-06 19:55:05 +02:00
|
|
|
|
|
|
|
// ReadByteData must be implemented as the sequence:
|
|
|
|
// "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [Data] NA P"
|
2017-07-12 09:00:35 -06:00
|
|
|
ReadByteData(reg uint8) (val uint8, err error)
|
2022-09-06 19:55:05 +02:00
|
|
|
|
|
|
|
// ReadWordData must be implemented as the sequence:
|
|
|
|
// "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [DataLow] A [DataHigh] NA P"
|
2017-07-12 09:00:35 -06:00
|
|
|
ReadWordData(reg uint8) (val uint16, err error)
|
2022-09-06 19:55:05 +02:00
|
|
|
|
|
|
|
// ReadBlockData must be implemented as the sequence:
|
|
|
|
// "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P"
|
|
|
|
ReadBlockData(reg uint8, b []byte) (err error)
|
|
|
|
|
|
|
|
// WriteByte must be implemented as the sequence:
|
|
|
|
// "S Addr Wr [A] Data [A] P"
|
2017-07-12 09:00:35 -06:00
|
|
|
WriteByte(val byte) (err error)
|
2022-09-06 19:55:05 +02:00
|
|
|
|
|
|
|
// WriteByteData must be implemented as the sequence:
|
|
|
|
// "S Addr Wr [A] Comm [A] Data [A] P"
|
2017-07-12 09:00:35 -06:00
|
|
|
WriteByteData(reg uint8, val uint8) (err error)
|
2022-09-06 19:55:05 +02:00
|
|
|
|
|
|
|
// WriteWordData must be implemented as the sequence:
|
|
|
|
// "S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P"
|
2017-07-12 09:00:35 -06:00
|
|
|
WriteWordData(reg uint8, val uint16) (err error)
|
2022-09-06 19:55:05 +02:00
|
|
|
|
|
|
|
// WriteBlockData must be implemented as the sequence:
|
|
|
|
// "S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P"
|
2017-07-12 09:00:35 -06:00
|
|
|
WriteBlockData(reg uint8, b []byte) (err error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// I2cDevice is the interface to a specific i2c bus
|
|
|
|
type I2cDevice interface {
|
|
|
|
I2cOperations
|
|
|
|
SetAddress(int) error
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// Connection is a connection to an I2C device with a specified address
|
|
|
|
// on a specific bus. Used as an alternative to the I2c interface.
|
2017-07-12 09:47:44 -06:00
|
|
|
// Implements I2cOperations to talk to the device, wrapping the
|
2017-02-13 08:31:49 +01:00
|
|
|
// calls in SetAddress to always target the specified device.
|
|
|
|
// Provided by an Adaptor by implementing the I2cConnector interface.
|
2017-07-12 09:00:35 -06:00
|
|
|
type Connection I2cOperations
|
2017-02-10 11:54:45 +01:00
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
type i2cConnection struct {
|
2017-07-12 09:00:35 -06:00
|
|
|
bus I2cDevice
|
2017-02-13 08:31:49 +01:00
|
|
|
address int
|
2017-05-07 22:28:07 +02:00
|
|
|
mutex *sync.Mutex
|
2017-02-10 11:54:45 +01:00
|
|
|
}
|
|
|
|
|
2017-02-10 11:08:32 +01:00
|
|
|
// NewConnection creates and returns a new connection to a specific
|
2017-02-10 11:54:45 +01:00
|
|
|
// i2c device on a bus and address.
|
2017-07-12 09:00:35 -06:00
|
|
|
func NewConnection(bus I2cDevice, address int) (connection *i2cConnection) {
|
2017-05-07 22:28:07 +02:00
|
|
|
return &i2cConnection{bus: bus, address: address, mutex: &sync.Mutex{}}
|
2017-01-20 00:17:41 +01:00
|
|
|
}
|
|
|
|
|
2017-02-10 11:54:45 +01:00
|
|
|
// Read data from an i2c device.
|
2017-02-06 00:19:42 +01:00
|
|
|
func (c *i2cConnection) Read(data []byte) (read int, err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-03-20 18:21:12 +01:00
|
|
|
if err = c.bus.SetAddress(c.address); err != nil {
|
2017-02-06 00:19:42 +01:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
read, err = c.bus.Read(data)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// Write data to an i2c device.
|
2017-02-06 00:19:42 +01:00
|
|
|
func (c *i2cConnection) Write(data []byte) (written int, err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-03-20 18:21:12 +01:00
|
|
|
if err = c.bus.SetAddress(c.address); err != nil {
|
2017-02-06 00:19:42 +01:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
written, err = c.bus.Write(data)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// Close connection to i2c device.
|
2017-02-06 00:19:42 +01:00
|
|
|
func (c *i2cConnection) Close() error {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-02-06 00:19:42 +01:00
|
|
|
return c.bus.Close()
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// ReadByte reads a single byte from the i2c device.
|
2017-02-09 09:44:32 +01:00
|
|
|
func (c *i2cConnection) ReadByte() (val byte, err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-01-20 00:17:41 +01:00
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return c.bus.ReadByte()
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// ReadByteData reads a byte value for a register on the i2c device.
|
2017-01-20 00:17:41 +01:00
|
|
|
func (c *i2cConnection) ReadByteData(reg uint8) (val uint8, err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-01-20 00:17:41 +01:00
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return c.bus.ReadByteData(reg)
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// ReadWordData reads a word value for a register on the i2c device.
|
2017-01-20 00:17:41 +01:00
|
|
|
func (c *i2cConnection) ReadWordData(reg uint8) (val uint16, err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-01-20 00:17:41 +01:00
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return c.bus.ReadWordData(reg)
|
|
|
|
}
|
|
|
|
|
2022-09-06 19:55:05 +02:00
|
|
|
// ReadBlockData reads a block of bytes from a register on the i2c device.
|
|
|
|
func (c *i2cConnection) ReadBlockData(reg uint8, b []byte) (err error) {
|
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return c.bus.ReadBlockData(reg, b)
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// WriteByte writes a single byte to the i2c device.
|
2017-02-09 09:44:32 +01:00
|
|
|
func (c *i2cConnection) WriteByte(val byte) (err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-01-20 00:17:41 +01:00
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return c.bus.WriteByte(val)
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// WriteByteData writes a byte value to a register on the i2c device.
|
2017-01-20 00:17:41 +01:00
|
|
|
func (c *i2cConnection) WriteByteData(reg uint8, val uint8) (err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-01-20 00:17:41 +01:00
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return c.bus.WriteByteData(reg, val)
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// WriteWordData writes a word value to a register on the i2c device.
|
2017-02-06 00:19:42 +01:00
|
|
|
func (c *i2cConnection) WriteWordData(reg uint8, val uint16) (err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-02-06 00:19:42 +01:00
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return c.bus.WriteWordData(reg, val)
|
|
|
|
}
|
|
|
|
|
2017-02-13 08:31:49 +01:00
|
|
|
// WriteBlockData writes a block of bytes to a register on the i2c device.
|
2017-02-06 00:19:42 +01:00
|
|
|
func (c *i2cConnection) WriteBlockData(reg uint8, b []byte) (err error) {
|
2017-05-07 22:28:07 +02:00
|
|
|
c.mutex.Lock()
|
|
|
|
defer c.mutex.Unlock()
|
|
|
|
|
2017-01-20 00:17:41 +01:00
|
|
|
if err := c.bus.SetAddress(c.address); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-02-06 00:19:42 +01:00
|
|
|
return c.bus.WriteBlockData(reg, b)
|
2017-01-20 00:17:41 +01:00
|
|
|
}
|
2022-03-19 21:16:31 +01:00
|
|
|
|
|
|
|
// setBit is used to set a bit at a given position to 1.
|
|
|
|
func setBit(n uint8, pos uint8) uint8 {
|
|
|
|
n |= (1 << pos)
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
// clearBit is used to set a bit at a given position to 0.
|
|
|
|
func clearBit(n uint8, pos uint8) uint8 {
|
|
|
|
mask := ^uint8(1 << pos)
|
|
|
|
n &= mask
|
|
|
|
return n
|
|
|
|
}
|
2022-08-31 19:40:31 +02:00
|
|
|
|
|
|
|
func twosComplement16Bit(uValue uint16) int16 {
|
|
|
|
result := int32(uValue)
|
|
|
|
if result&0x8000 != 0 {
|
|
|
|
result -= 1 << 16
|
|
|
|
}
|
|
|
|
return int16(result)
|
|
|
|
}
|
2022-08-27 19:45:01 +02:00
|
|
|
|
|
|
|
func swapBytes(value uint16) uint16 {
|
|
|
|
return (value << 8) | (value >> 8)
|
|
|
|
}
|