gobot.io/x/gobot/v2@v2.1.0/platforms/digispark/digispark_i2c.go (about)

     1  package digispark
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sync"
     7  )
     8  
     9  // digisparkI2cConnection implements the interface gobot.I2cOperations
    10  type digisparkI2cConnection struct {
    11  	address uint8
    12  	adaptor *Adaptor
    13  	mtx     sync.Mutex
    14  }
    15  
    16  // NewDigisparkI2cConnection creates an i2c connection to an i2c device at
    17  // the specified address
    18  func NewDigisparkI2cConnection(adaptor *Adaptor, address uint8) (connection *digisparkI2cConnection) {
    19  	return &digisparkI2cConnection{adaptor: adaptor, address: address}
    20  }
    21  
    22  // Init makes sure that the i2c device is already initialized
    23  func (c *digisparkI2cConnection) Init() (err error) {
    24  	if !c.adaptor.i2c {
    25  		if err = c.adaptor.littleWire.i2cInit(); err != nil {
    26  			return
    27  		}
    28  		c.adaptor.i2c = true
    29  	}
    30  	return
    31  }
    32  
    33  // Test tests i2c connection with the given address
    34  func (c *digisparkI2cConnection) Test(address uint8) error {
    35  	if !c.adaptor.i2c {
    36  		return errors.New("Digispark i2c not initialized")
    37  	}
    38  	return c.adaptor.littleWire.i2cStart(address, 0)
    39  }
    40  
    41  // UpdateDelay updates i2c signal delay amount; tune if neccessary to fit your requirements
    42  func (c *digisparkI2cConnection) UpdateDelay(duration uint) error {
    43  	if !c.adaptor.i2c {
    44  		return errors.New("Digispark i2c not initialized")
    45  	}
    46  	return c.adaptor.littleWire.i2cUpdateDelay(duration)
    47  }
    48  
    49  // Read tries to read a full buffer from the i2c device.
    50  // Returns an empty array if the response from the board has timed out.
    51  func (c *digisparkI2cConnection) Read(b []byte) (countRead int, err error) {
    52  	c.mtx.Lock()
    53  	defer c.mtx.Unlock()
    54  
    55  	return c.readInternal(b)
    56  }
    57  
    58  // Write writes the buffer content in data to the i2c device.
    59  func (c *digisparkI2cConnection) Write(data []byte) (countWritten int, err error) {
    60  	c.mtx.Lock()
    61  	defer c.mtx.Unlock()
    62  
    63  	return c.writeInternal(data, true)
    64  }
    65  
    66  // Close do nothing than return nil.
    67  func (c *digisparkI2cConnection) Close() error {
    68  	return nil
    69  }
    70  
    71  // ReadByte reads one byte from the i2c device.
    72  func (c *digisparkI2cConnection) ReadByte() (val byte, err error) {
    73  	c.mtx.Lock()
    74  	defer c.mtx.Unlock()
    75  
    76  	buf := []byte{0}
    77  	if err = c.readAndCheckCount(buf); err != nil {
    78  		return
    79  	}
    80  	val = buf[0]
    81  	return
    82  }
    83  
    84  // ReadByteData reads one byte of the given register address from the i2c device.
    85  func (c *digisparkI2cConnection) ReadByteData(reg uint8) (val uint8, err error) {
    86  	c.mtx.Lock()
    87  	defer c.mtx.Unlock()
    88  
    89  	if err = c.writeAndCheckCount([]byte{reg}, false); err != nil {
    90  		return
    91  	}
    92  
    93  	buf := []byte{0}
    94  	if err = c.readAndCheckCount(buf); err != nil {
    95  		return
    96  	}
    97  	val = buf[0]
    98  	return
    99  }
   100  
   101  // ReadWordData reads two bytes of the given register address from the i2c device.
   102  func (c *digisparkI2cConnection) ReadWordData(reg uint8) (val uint16, err error) {
   103  	c.mtx.Lock()
   104  	defer c.mtx.Unlock()
   105  
   106  	if err = c.writeAndCheckCount([]byte{reg}, false); err != nil {
   107  		return
   108  	}
   109  
   110  	buf := []byte{0, 0}
   111  	if err = c.readAndCheckCount(buf); err != nil {
   112  		return
   113  	}
   114  	low, high := buf[0], buf[1]
   115  
   116  	val = (uint16(high) << 8) | uint16(low)
   117  	return
   118  }
   119  
   120  // ReadBlockData reads a block of maximum 32 bytes from the given register address of the i2c device.
   121  func (c *digisparkI2cConnection) ReadBlockData(reg uint8, data []byte) (err error) {
   122  	c.mtx.Lock()
   123  	defer c.mtx.Unlock()
   124  
   125  	if err = c.writeAndCheckCount([]byte{reg}, false); err != nil {
   126  		return
   127  	}
   128  
   129  	if len(data) > 32 {
   130  		data = data[:32]
   131  	}
   132  	return c.readAndCheckCount(data)
   133  }
   134  
   135  // WriteByte writes one byte to the i2c device.
   136  func (c *digisparkI2cConnection) WriteByte(val byte) error {
   137  	c.mtx.Lock()
   138  	defer c.mtx.Unlock()
   139  
   140  	buf := []byte{val}
   141  	return c.writeAndCheckCount(buf, true)
   142  }
   143  
   144  // WriteByteData writes one byte to the given register address of the i2c device.
   145  func (c *digisparkI2cConnection) WriteByteData(reg uint8, val byte) error {
   146  	c.mtx.Lock()
   147  	defer c.mtx.Unlock()
   148  
   149  	buf := []byte{reg, val}
   150  	return c.writeAndCheckCount(buf, true)
   151  }
   152  
   153  // WriteWordData writes two bytes to the given register address of the i2c device.
   154  func (c *digisparkI2cConnection) WriteWordData(reg uint8, val uint16) error {
   155  	c.mtx.Lock()
   156  	defer c.mtx.Unlock()
   157  
   158  	low := uint8(val & 0xff)
   159  	high := uint8((val >> 8) & 0xff)
   160  	buf := []byte{reg, low, high}
   161  	return c.writeAndCheckCount(buf, true)
   162  }
   163  
   164  // WriteBlockData writes a block of maximum 32 bytes to the given register address of the i2c device.
   165  func (c *digisparkI2cConnection) WriteBlockData(reg uint8, data []byte) error {
   166  	c.mtx.Lock()
   167  	defer c.mtx.Unlock()
   168  
   169  	if len(data) > 32 {
   170  		data = data[:32]
   171  	}
   172  
   173  	buf := make([]byte, len(data)+1)
   174  	copy(buf[1:], data)
   175  	buf[0] = reg
   176  	return c.writeAndCheckCount(buf, true)
   177  }
   178  
   179  // WriteBytes writes a block of maximum 32 bytes to the current register address of the i2c device.
   180  func (c *digisparkI2cConnection) WriteBytes(buf []byte) error {
   181  	c.mtx.Lock()
   182  	defer c.mtx.Unlock()
   183  
   184  	if len(buf) > 32 {
   185  		buf = buf[:32]
   186  	}
   187  
   188  	return c.writeAndCheckCount(buf, true)
   189  }
   190  
   191  func (c *digisparkI2cConnection) readAndCheckCount(buf []byte) error {
   192  	countRead, err := c.readInternal(buf)
   193  	if err != nil {
   194  		return err
   195  	}
   196  	expectedCount := len(buf)
   197  	if countRead != expectedCount {
   198  		return fmt.Errorf("Digispark i2c read %d bytes, expected %d bytes", countRead, expectedCount)
   199  	}
   200  	return nil
   201  }
   202  
   203  func (c *digisparkI2cConnection) writeAndCheckCount(buf []byte, finalStop bool) error {
   204  	countWritten, err := c.writeInternal(buf, finalStop)
   205  	if err != nil {
   206  		return err
   207  	}
   208  	expectedCount := len(buf)
   209  	if countWritten != expectedCount {
   210  		return fmt.Errorf("Digispark i2c write %d bytes, expected %d bytes", countWritten, expectedCount)
   211  	}
   212  	return nil
   213  }
   214  
   215  func (c *digisparkI2cConnection) readInternal(b []byte) (countRead int, err error) {
   216  	if !c.adaptor.i2c {
   217  		err = errors.New("Digispark i2c not initialized")
   218  		return
   219  	}
   220  	if err = c.adaptor.littleWire.i2cStart(c.address, 1); err != nil {
   221  		return
   222  	}
   223  	l := 8
   224  	stop := uint8(0)
   225  
   226  	for stop == 0 {
   227  		if countRead+l >= len(b) {
   228  			l = len(b) - countRead
   229  			stop = 1
   230  		}
   231  		if err = c.adaptor.littleWire.i2cRead(b[countRead:countRead+l], l, stop); err != nil {
   232  			return
   233  		}
   234  		countRead += l
   235  	}
   236  	return
   237  }
   238  
   239  func (c *digisparkI2cConnection) writeInternal(data []byte, finalStop bool) (countWritten int, err error) {
   240  	if !c.adaptor.i2c {
   241  		err = errors.New("Digispark i2c not initialized")
   242  		return
   243  	}
   244  	if err = c.adaptor.littleWire.i2cStart(c.address, 0); err != nil {
   245  		return
   246  	}
   247  	l := 4
   248  	lastQuadruplet := false
   249  	stop := uint8(0)
   250  
   251  	for !lastQuadruplet {
   252  		if countWritten+l >= len(data) {
   253  			lastQuadruplet = true
   254  			l = len(data) - countWritten
   255  			if finalStop {
   256  				stop = 1
   257  			}
   258  		}
   259  		if err = c.adaptor.littleWire.i2cWrite(data[countWritten:countWritten+l], l, stop); err != nil {
   260  			return
   261  		}
   262  		countWritten += l
   263  	}
   264  	return
   265  }