Skip to content

Commit

Permalink
NEW: i2c.ReadBlockData(), BUGFIX: Read*Data() in digispark and some s…
Browse files Browse the repository at this point in the history
…mall other fixes
  • Loading branch information
gen2thomas committed Oct 1, 2022
1 parent 4a3bfe5 commit fc4894b
Show file tree
Hide file tree
Showing 8 changed files with 815 additions and 363 deletions.
98 changes: 58 additions & 40 deletions drivers/i2c/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,41 +68,33 @@ func (t *i2cTestAdaptor) ReadByte() (val byte, err error) {
t.mtx.Lock()
defer t.mtx.Unlock()
bytes := []byte{0}
bytesRead, err := t.i2cReadImpl(bytes)
if err != nil {
return 0, err
}
if bytesRead != 1 {
return 0, fmt.Errorf("Buffer underrun")
if err = t.readBytes(bytes); err != nil {
return
}
val = bytes[0]
return
}

func (t *i2cTestAdaptor) ReadByteData(reg uint8) (val uint8, err error) {
if err = t.WriteByte(reg); err != nil {
return
}
t.mtx.Lock()
defer t.mtx.Unlock()
bytes := []byte{0}
bytesRead, err := t.i2cReadImpl(bytes)
if err != nil {
return 0, err
if err = t.writeBytes([]byte{reg}); err != nil {
return
}
if bytesRead != 1 {
return 0, fmt.Errorf("Buffer underrun")
bytes := []byte{0}
if err = t.readBytes(bytes); err != nil {
return
}
val = bytes[0]
return
}

func (t *i2cTestAdaptor) ReadWordData(reg uint8) (val uint16, err error) {
if err = t.WriteByte(reg); err != nil {
return
}
t.mtx.Lock()
defer t.mtx.Unlock()
if err = t.writeBytes([]byte{reg}); err != nil {
return
}
bytes := []byte{0, 0}
bytesRead, err := t.i2cReadImpl(bytes)
if err != nil {
Expand All @@ -115,45 +107,50 @@ func (t *i2cTestAdaptor) ReadWordData(reg uint8) (val uint16, err error) {
return (uint16(high) << 8) | uint16(low), err
}

func (t *i2cTestAdaptor) WriteByte(val byte) (err error) {
func (t *i2cTestAdaptor) ReadBlockData(reg uint8, b []byte) (err error) {
t.mtx.Lock()
defer t.mtx.Unlock()
t.written = append(t.written, val)
bytes := []byte{val}
_, err = t.i2cWriteImpl(bytes)
return
if err = t.writeBytes([]byte{reg}); err != nil {
return
}
return t.readBytes(b)
}

func (t *i2cTestAdaptor) WriteByte(val byte) error {
t.mtx.Lock()
defer t.mtx.Unlock()
return t.writeBytes([]byte{val})
}

func (t *i2cTestAdaptor) WriteByteData(reg uint8, val uint8) (err error) {
t.mtx.Lock()
defer t.mtx.Unlock()
t.written = append(t.written, reg)
t.written = append(t.written, val)
bytes := []byte{val}
_, err = t.i2cWriteImpl(bytes)
return
bytes := []byte{reg, val}

return t.writeBytes(bytes)
}

func (t *i2cTestAdaptor) WriteWordData(reg uint8, val uint16) (err error) {
func (t *i2cTestAdaptor) WriteWordData(reg uint8, val uint16) error {
t.mtx.Lock()
defer t.mtx.Unlock()
t.written = append(t.written, reg)
low := uint8(val & 0xff)
high := uint8((val >> 8) & 0xff)
t.written = append(t.written, low)
t.written = append(t.written, high)
bytes := []byte{low, high}
_, err = t.i2cWriteImpl(bytes)
return
bytes := []byte{reg, low, high}

return t.writeBytes(bytes)
}

func (t *i2cTestAdaptor) WriteBlockData(reg uint8, b []byte) (err error) {
func (t *i2cTestAdaptor) WriteBlockData(reg uint8, b []byte) error {
t.mtx.Lock()
defer t.mtx.Unlock()
t.written = append(t.written, reg)
t.written = append(t.written, b...)
_, err = t.i2cWriteImpl(b)
return
if len(b) > 32 {
b = b[:32]
}
buf := make([]byte, len(b)+1)
copy(buf[1:], b)
buf[0] = reg

return t.writeBytes(buf)
}

func (t *i2cTestAdaptor) GetConnection( /* address */ int /* bus */, int) (connection Connection, err error) {
Expand Down Expand Up @@ -183,3 +180,24 @@ func newI2cTestAdaptor() *i2cTestAdaptor {
},
}
}

func (t *i2cTestAdaptor) readBytes(b []byte) error {
n, err := t.i2cReadImpl(b)
if err != nil {
return err
}
if n != len(b) {
return fmt.Errorf("Read %v bytes from device by i2c helpers, expected %v", n, len(b))
}
return nil
}

func (t *i2cTestAdaptor) writeBytes(b []byte) error {
t.written = append(t.written, b...)
// evaluation of count can be done in test
_, err := t.i2cWriteImpl(b)
if err != nil {
return err
}
return nil
}
53 changes: 53 additions & 0 deletions drivers/i2c/i2c.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,56 @@ const (
set = 0x01
)

// 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.
//
type I2cOperations interface {
io.ReadWriteCloser

// ReadByte must be implemented as the sequence:
// "S Addr Rd [A] [Data] NA P"
ReadByte() (val byte, err error)

// ReadByteData must be implemented as the sequence:
// "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [Data] NA P"
ReadByteData(reg uint8) (val uint8, err error)

// ReadWordData must be implemented as the sequence:
// "S Addr Wr [A] Comm [A] Sr Addr Rd [A] [DataLow] A [DataHigh] NA P"
ReadWordData(reg uint8) (val uint16, err error)

// 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"
WriteByte(val byte) (err error)

// WriteByteData must be implemented as the sequence:
// "S Addr Wr [A] Comm [A] Data [A] P"
WriteByteData(reg uint8, val uint8) (err error)

// WriteWordData must be implemented as the sequence:
// "S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P"
WriteWordData(reg uint8, val uint16) (err error)

// WriteBlockData must be implemented as the sequence:
// "S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P"
WriteBlockData(reg uint8, b []byte) (err error)
}

Expand Down Expand Up @@ -146,6 +188,17 @@ func (c *i2cConnection) ReadWordData(reg uint8) (val uint16, err error) {
return c.bus.ReadWordData(reg)
}

// 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)
}

// WriteByte writes a single byte to the i2c device.
func (c *i2cConnection) WriteByte(val byte) (err error) {
c.mutex.Lock()
Expand Down
Loading

0 comments on commit fc4894b

Please sign in to comment.